Skip to main content
When you run a workflow in MirrorNeuron, two distinct runtime layers work together. BEAM handles everything that needs to be fast, stateful, and highly concurrent — routing, supervision, retries, persistence, and coordination. OpenShell handles everything that needs isolation — running scripts, staging files, and capturing output. Understanding where that boundary sits and why it exists will help you design workflows that scale without overwhelming your infrastructure.

The two-layer model

MirrorNeuron enforces a hard split between its control plane and its execution plane.
The control plane lives entirely in BEAM. It manages:
  • Job orchestration and lifecycle
  • Message routing between agents
  • Supervision and fault recovery
  • Redis-backed persistence for job state, snapshots, and event history
  • Retry and backoff logic
  • Aggregation and event history
  • Cluster coordination via libcluster and Horde
These are cheap, concurrent, stateful tasks. BEAM excels at them. A single node can hold thousands of logical workers without meaningful overhead.

Logical workers vs execution leases

The most important distinction in the MirrorNeuron runtime is between a logical worker and an execution lease.

Logical workers

A logical worker is a BEAM process that represents one node in your workflow graph. It:
  • receives messages from the router
  • holds workflow state in memory
  • can wait for work cheaply without consuming OS resources
  • emits events to the runtime event bus
  • may request external execution when it is an executor node
You can have thousands of logical workers active at once. BEAM processes are lightweight — holding a large graph of waiting workers does not burden the system.

Execution leases

An execution lease is permission to consume sandbox capacity. When an executor node handles a message, it does not immediately start a sandbox. Instead, it first requests a lease from MirrorNeuron.Execution.LeaseManager:
1

Request a lease

The executor emits an executor_lease_requested event and requests a slot from its assigned pool and slot count.
2

Wait if capacity is exhausted

If the pool has no free slots, the lease request queues until a slot is released. The logical worker waits without blocking any other BEAM process.
3

Run the sandbox

Once the lease is granted, the executor emits executor_lease_acquired and runs the OpenShell command.
4

Release the lease

When execution finishes — whether successfully or with an error — the executor releases the lease, freeing the slot for the next queued request.
This separation is the core reason MirrorNeuron can hold large logical graphs without overloading an OpenShell gateway. The runtime can keep thousands of logical workers active while limiting the actual number of running sandboxes to whatever your infrastructure can handle.

Executor pools and slot accounting

MirrorNeuron assigns executor capacity through named pools. Each pool has a configurable slot count. Every executor node request consumes one or more slots from its assigned pool. Configure the default pool capacity using the environment variable:
export MIRROR_NEURON_EXECUTOR_MAX_CONCURRENCY=4
To configure multiple named pools with independent capacities:
export MIRROR_NEURON_EXECUTOR_POOL_CAPACITIES="default=4,gpu=1,io=8"
On your executor nodes, declare which pool to use and how many slots to request:
{
  "agent_type": "executor",
  "config": {
    "pool": "default",
    "pool_slots": 1
  }
}
If you omit pool, the executor uses "default". If you omit pool_slots, it requests 1 slot.
Pools are currently enforced per runtime node. When you need more execution capacity, you scale out by adding nodes — each node brings its own bounded pool. A four-node cluster with eight slots per node supports up to 32 concurrent sandboxes, regardless of how many logical workers are waiting.

Scaling example

Logical workersNodesSlots per nodeMax concurrent sandboxes
100144
10004832
500010880
The logical worker count does not constrain how many sandboxes run at once. Only the pool configuration does.

Message model

Every message that flows between agents in MirrorNeuron follows a fixed four-section structure. This keeps the runtime generic: BEAM only needs to read the envelope to route and observe messages. It never needs to parse your application payload to work correctly.
{
  "envelope": {
    "spec_version": "mn-msg/1",
    "message_id": "abc123",
    "job_id": "research_flow_v1",
    "from": "ingress",
    "to": "retriever",
    "type": "research_request",
    "class": "event",
    "timestamp": 1713000000000,
    "correlation_id": "xyz789",
    "causation_id": "prev_msg_id",
    "attempt": 1,
    "priority": 100,
    "content_type": "application/json",
    "content_encoding": "identity"
  },
  "headers": {
    "schema_ref": "com.example.research.request",
    "schema_version": "1.0.0"
  },
  "body": {
    "topic": "electric vehicle charging adoption in New England",
    "text": "Collect a short research summary."
  },
  "artifacts": []
}

envelope

The envelope is runtime-owned. It carries all routing and trace metadata: the source and destination node IDs, the message type and class, a correlation chain for tracing, delivery attempt count, priority, and content negotiation fields. The runtime reads the envelope to route messages and record event history.

headers

The headers object is extensible routing and schema metadata. Use it for schema references, content negotiation hints, or any metadata that a downstream agent or router needs to inspect without parsing the full body.

body

The body is your application-owned payload. The runtime treats it as opaque. Workers running in OpenShell sandboxes read and write the body through the payload contract — BEAM only forwards it.

artifacts

The artifacts array carries references to large externalized data objects. Pass IDs or storage references here instead of embedding large blobs directly in the body. Keeping messages small is important in a clustered runtime: small control messages route and persist much more efficiently than inline payloads.

stream

The optional stream field carries framing metadata for streaming or chunked message flows. It is null on non-streaming messages.

Why this scales better

The alternative — launching one sandbox for every logical worker immediately — breaks down under fan-out:
  • Gateway connections spike and reset under launch pressure
  • OS subprocess count climbs without bound
  • Duplicate cleanup races emerge when sandboxes fail mid-flight
  • No backpressure exists to slow down the producer side
The MirrorNeuron model addresses all of these by making execution capacity explicit and accounting for it at the lease level. BEAM workers queue cheaply. Sandboxes start only when a slot is available. The system stays stable regardless of graph size.
If you are running large fan-out workflows and seeing lease queue depth climb, increase MIRROR_NEURON_EXECUTOR_MAX_CONCURRENCY or add more runtime nodes — each addition contributes its own independent pool of slots.