Job Bundle Format
In MirrorNeuron, a Job Bundle is the standard deployment package for a multi-agent workflow. It defines the structure of the agent graph, the initial state, and any necessary…
This is a reference for generated runtime bundles. To author a source package, use Author a blueprint: its manifest references separate role documents. The low-level graph fields below belong to the compiled artifact, not that source manifest.
Job Bundle Format
In MirrorNeuron, a Job Bundle is the standard deployment package for a multi-agent workflow. It defines the structure of the agent graph, the initial state, and any necessary executable payloads or static data required to run the job in an isolated execution sandbox.
Bundle Structure
A valid job bundle is a directory with the following structure:
my_job_bundle/
├── manifest.json
└── payloads/
├── worker_script.py
└── data.jsonmanifest.json: The declarative workflow definition. It maps out nodes (agents), edges (message routing), and execution policies.payloads/: A required directory containing all external static assets, shell scripts, Python code, and data files referenced by the executor nodes. The runtime resolves any relativesourcepaths in the manifest against this directory before uploading them to the OpenShell sandbox.
The manifest.json Schema
The manifest.json is a JSON document that defines the execution graph.
Top-level Fields
| Field | Type | Description |
|---|---|---|
manifest_version | String | Required. The version of the manifest format (e.g., "1.0"). |
graph_id | String | Required. A unique workflow id. |
job_name | String | Optional. A human-readable name for the job. Defaults to graph_id if missing. |
type | String | Optional. Set to "service" for workflows intended to run until manually stopped. Omit for default batch workflows. system and sysbatch are selected through scheduler policy. |
response_service | Object | Optional. Exactly {"enabled": true} enables one definition-scoped real-time Job responder. It is not a DAG node or Run service and accepts no command, handler, port, prompt, or endpoint fields. |
required_context_engine | Boolean | Optional. Set to true when the workflow requires the Context Engine. The runtime checks CONTEXT_ENGINE_ADDR or port 50052 and rejects the run before scheduling agents if the service is unavailable. Defaults to false. |
services | Array | Optional. Services registered by the job. See Services and Health Checks. |
required_services | Array | Optional. Services that must be healthy before job start. |
deployment | Object | Optional. Stable deployment key and metadata. See Deployments. |
schedule | Object | Optional. Periodic or delayed schedule declaration. See Schedules and Events. |
triggers | Array | Optional. Event-trigger schedule declarations. |
parameterized | Object | Optional. Dispatch payload and metadata declaration for scheduled or event-triggered runs. |
metadata | Object | Optional. Custom metadata tags for the job. |
entrypoints | Array | Required. A list of node_id strings where initial inputs will be injected to start the graph. |
initial_inputs | Object | Optional. A map where the keys are node_ids (from entrypoints) and values are arrays of message payloads to seed the job. |
nodes | Array | Required. The list of agent nodes that make up the workflow. |
edges | Array | Required. The list of message-routing edges between nodes. |
policies | Object | Optional. Job-level policies like recovery_mode. |
Nodes (Agents)
Each item in the nodes array defines an agent that will be supervised by the BEAM runtime.
| Field | Type | Description |
|---|---|---|
node_id | String | Required. Unique identifier for this node within the graph. |
agent_type | String | Required. The core runtime primitive. Typically "router", "executor", "aggregator", or "sensor". |
type | String | Optional. The behavioral template (e.g., "map", "reduce", "stream", "batch"). Defaults to "generic". |
role | String | Optional. A human-readable tag describing the agent's domain role (e.g., "researcher", "root_coordinator"). |
config | Object | Optional. Configuration specific to the agent_type and type (e.g., emit_type, pool, uploads). |
resources | Object | Optional. CPU, memory, disk, GPU, device, port, volume, and runtime-driver requirements. |
services | Array | Optional. Services registered by this specific agent. |
requires_services | Array | Optional. Node-scoped service requirements used during placement. |
policies | Object | Optional. Per-agent restart overrides and legacy policy fields. |
Job Types
MirrorNeuron supports four Nomad-inspired job types:
| Type | How to declare | Behavior |
|---|---|---|
service | top-level "type": "service" or scheduler policy | Long-running and restarted locally by policy until stopped. |
batch | default top-level type | Runs to completion and retries within policy limits. |
system | policies.scheduler.job_type: "system" | Runs owner-local long-running system work. It does not expand across federated peers. |
sysbatch | policies.scheduler.job_type: "sysbatch" | Runs owner-local one-off system work. It does not expand across federated peers. |
Example:
{
"policies": {
"scheduler": {
"job_type": "system",
"strategy": "spread"
}
}
}Restart Policies
Job-level restart policy lives under policies.restart; per-agent overrides
live under nodes[].policies.restart. Legacy reschedule fields remain
accepted for stored-manifest compatibility, but federation does not move a job
or agent to another Core.
{
"policies": {
"recovery_mode": "local_restart",
"restart": {
"attempts": 3,
"interval_ms": 600000,
"delay_ms": 1000,
"delay_function": "exponential",
"max_delay_ms": 30000,
"mode": "fail"
}
}
}See Reliability Guide.
Resource Requirements
{
"resources": {
"cpu_cores": 2,
"memory_mb": 8192,
"devices": [
{
"kind": "gpu",
"driver": "cuda",
"min_memory_mb": 16000,
"count": 1
}
],
"ports": [
{
"label": "api",
"port": 8088,
"protocol": "http"
}
],
"volumes": [
{
"name": "models",
"source": "/mnt/models",
"target": "/models",
"mode": "ro",
"type": "host"
}
],
"runtime_driver": "host_local"
}
}Service Requirements
{
"required_services": [
{
"name": "ollama",
"origin": "external",
"address": "${config.ollama.host}",
"port": "${config.ollama.port}",
"checks": [
{
"type": "http",
"url": "${config.ollama.api_base}/api/tags",
"expected_status": 200
}
]
}
]
}See Services and Health Checks.
Deployment Policy
{
"deployment": {
"key": "agent-api"
},
"policies": {
"update": {
"strategy": "canary",
"canary": 1,
"max_parallel": 1,
"auto_promote": false,
"auto_revert": true
}
}
}See Deployments.
Schedule And Triggers
{
"schedule": {
"kind": "periodic",
"crons": ["0 2 * * *"],
"timezone": "America/New_York",
"prohibit_overlap": true,
"missed_policy": "skip"
},
"triggers": [
{
"name": "dataset-uploaded",
"event_type": "file_uploaded",
"filters": {
"path": {
"prefix": "/datasets/"
}
}
}
]
}See Schedules and Events.
Edges (Routing)
Edges dictate how messages flow between agents after a step completes.
| Field | Type | Description |
|---|---|---|
from_node | String | Required. The node_id of the sending agent. |
to_node | String | Required. The node_id of the receiving agent. |
message_type | String | Required. The event or message type that triggers this edge (e.g., "research_request"). |
The payloads/ Directory
Because MirrorNeuron strictly separates the control plane (BEAM orchestration) from the execution plane (OpenShell sandboxes), any code executed by an "executor" agent must be supplied through the payloads/ directory.
When you configure an executor node to run a script, you declare it in the config.uploads map. The source paths are evaluated relative to the payloads/ directory:
{
"node_id": "python_worker",
"agent_type": "executor",
"config": {
"uploads": [
{
"source": "process_data.py",
"target": "/sandbox/process_data.py"
}
],
"command": ["/usr/bin/python3", "/sandbox/process_data.py"]
}
}In this example, the runtime will look for my_job_bundle/payloads/process_data.py and mount it into the OpenShell sandbox at /sandbox/process_data.py.
Blueprint-Scoped Python Dependencies
MirrorNeuron.Runner.HostLocal executor nodes can opt in to an isolated Python virtual environment with python_environment. Dependencies are cached by Python version, requirements contents, and inline package list, so repeated runs reuse the same environment while unrelated blueprints remain isolated.
{
"node_id": "video_worker",
"agent_type": "executor",
"config": {
"runner_module": "MirrorNeuron.Runner.HostLocal",
"upload_path": "person_detector",
"upload_as": "person_detector",
"workdir": "/sandbox/job/person_detector",
"command": ["python3.11", "scripts/analyze_door_camera_frame.py"],
"python_environment": {
"requirements": "person_detector/requirements.txt",
"packages": ["opencv-python-headless>=4.10,<5"]
}
}
}requirements must be a relative path inside payloads/. Inline packages are normal pip requirement strings. If both are provided, both are installed into the same cached environment. If neither is provided, no environment is created.
The default cache is node-local at
$MN_HOME/cache/blueprint-python-envs; source packages staged for installation
use the sibling blueprint-python-sources directory. Docker Core sees these
paths under /root/.mn/cache. MN_BLUEPRINT_PYTHON_ENVS_DIR can explicitly
select another cache, including the legacy shared location, but a synchronized
virtual-environment cache causes avoidable Syncthing indexing and is reported
as a warning by blueprint doctor.
The core Docker image only includes generic Python virtualenv support. Blueprint-specific packages such as OpenCV, optimization solvers, browser tooling, and model libraries should be declared by the blueprint, not installed into core. Root-level blueprint requirements.txt files are not automatically installed; put runtime dependency files under payloads/ and reference them explicitly from the executor node.
Blueprint-Owned Skills And Agents
A bundle may carry installable skill and agent packages alongside ordinary payload files:
payloads/
skills/<package>/pyproject.toml
agents/index.json
agents/<package>/pyproject.tomlEach package is either a source tree in the same layout as mn-skills or
mn-agents, or a Python wheel. Declare it at the manifest root:
{
"skill_dependencies": [
{
"type": "pip",
"source": "payload",
"name": "example-private-skill",
"version": "1.0.0",
"path": "skills/example_private_skill",
"format": "source"
}
],
"agent_dependencies": [
{
"type": "pip",
"source": "payload",
"name": "example-private-agent",
"version": "1.0.0",
"path": "agents/example_private_agent",
"format": "source"
}
]
}Paths are relative to payloads/ and cannot escape the bundle. Names and
versions must match the source pyproject.toml or wheel metadata. A payload
package overrides a GAR declaration with the same normalized distribution name
and exact version.
Blueprint-Owned Models
Large model files belong below payloads/models. They are streamed into the
content-addressed blob store instead of being read into memory:
{
"runtime": {
"models": {
"primary": {
"provider": "docker_model_runner",
"runtime_model": "example/private-model:latest",
"backend": "llama.cpp",
"context_size": 4096,
"required": true,
"source": {
"type": "payload",
"path": "models/private/model.gguf",
"format": "gguf",
"mmproj_path": "models/private/model.mmproj",
"license_path": "models/private/LICENSE"
}
}
}
}
}Supported formats are gguf, safetensors, and dduf. MirrorNeuron validates
safe paths, records SHA-256 digests, and packages the files into Docker Model
Runner before launch. Model licenses remain part of the bundle and backup.
Example Bundle
Here is a simple example of a complete manifest.json for a Map-Reduce style workflow.
{
"manifest_version": "1.0",
"graph_id": "document_summarizer",
"required_context_engine": false,
"entrypoints": ["dispatcher"],
"initial_inputs": {
"dispatcher": [
{"file": "doc1.txt"},
{"file": "doc2.txt"}
]
},
"nodes": [
{
"node_id": "dispatcher",
"agent_type": "router",
"type": "map",
"role": "root_coordinator",
"config": {
"emit_type": "summarize_request"
}
},
{
"node_id": "summarizer_worker",
"agent_type": "executor",
"type": "map",
"config": {
"pool": "default",
"uploads": [
{
"source": "summarize.py",
"target": "/app/summarize.py"
}
],
"command": ["/usr/bin/python3", "/app/summarize.py"]
}
},
{
"node_id": "result_collector",
"agent_type": "aggregator",
"type": "reduce",
"config": {
"complete_on_message": true,
"terminal_sink": true,
"complete_run": true
}
}
],
"edges": [
{
"from_node": "dispatcher",
"to_node": "summarizer_worker",
"message_type": "summarize_request"
},
{
"from_node": "summarizer_worker",
"to_node": "result_collector",
"message_type": "summarize_request"
}
],
"policies": {
"recovery_mode": "local_restart"
}
}Loading and Running
You can validate and run a job bundle using the MirrorNeuron CLI:
# Validate the bundle structure and manifest constraints
mn blueprint validate path/to/my_job_bundle
# Execute the bundle on its selected owner Core
mn blueprint run path/to/my_job_bundleExpected validation output:
Job bundle at 'path/to/my_job_bundle' is valid.Before running a third-party bundle, review manifest.json, payloads/, runner, command, pass_env, and any OpenShell policy file. See Security Model.
For HTTP clients, upload the ZIP as multipart data to POST /api/v1/bundles,
then pass the returned opaque bundle_id to POST /api/v1/jobs. The REST API
does not accept manifest, payload, or host filesystem paths directly.