Native Subagent Delegation¶
Bernstein keeps the coordination plan in its deterministic scheduler and delegates the mechanical execution of each leaf task to a native subagent primitive - Claude Code's --agents flag, Codex, or another adapter's own sub-agent mechanism. core/agents/subagent_delegation.py is the boundary that lets that composition stay replayable: the plan side is a pure, hashable data structure, and only the boundary crossing (validating and anchoring the native result) is a side effect.
The plan is data, not a live call¶
An OuterPlan is an ordered tuple of DispatchNode leaves. Each node names a native target (claude, codex, ...) and the per-agent knobs the native primitive consumes - model, effort, prompt, tools, background, batch - plus a result_schema the native structured output must satisfy:
from bernstein.core.agents.subagent_delegation import DispatchNode, OuterPlan, delegate_plan
node = DispatchNode(
name="backend-leaf",
target="claude",
model="sonnet",
effort="medium",
prompt="Implement the endpoint per the spec.",
result_schema={"type": "object", "properties": {"files_changed": {"type": "array"}}, "required": ["files_changed"]},
tools=("edit", "bash"),
batch=False,
)
plan = OuterPlan(nodes=(node,))
DispatchNode.node_hash() and OuterPlan.plan_hash() are pure functions of these plan fields alone - never of what the native subagent returns - so two byte-identical plans produce identical hashes across replays even though the inner execution is stochastic. OuterPlan rejects duplicate node names at construction.
Crossing the boundary¶
The module does not invoke the native subagent itself - the caller runs the native primitive (via the adapter surface) and passes the parsed structured result into dispatch_node() or delegate_plan():
result = dispatch_node(
node,
native_result={"files_changed": ["app.py"]},
journal=run_journal, # optional
chain=audit_chain_store, # optional
ledger=spend_ledger, # optional
undiscounted_cost_usd=0.02,
input_tokens=1200,
output_tokens=340,
)
dispatch_node() performs three steps in order:
- Schema validation at the worker boundary. The native result is checked against the node's
result_schema, sealed against additional properties. Hallucinated keys or missing required fields raiseNativeResultRejected(aSchemaViolationsubclass) before anything is anchored, so a bad payload never reaches the journal. - Journal anchoring. When a journal is supplied, the crossing is recorded as a
subagent.delegationevent carrying the node's replay-invariantnode_hashand the (stochastic)result_content_hash(SHA-256 of the canonical validated payload). The outer DAG - the ordered sequence ofnode_hashvalues - therefore replays byte-identically even when the anchored result content differs run to run.delegate_plan()dispatches every node of a plan in strict plan order for exactly this reason. - Cost attribution. When a spend ledger is supplied, a
batch=Truenode's cost is discounted byBATCH_TIER_DISCOUNT(0.5, i.e. the standard non-interactive batch rate) and taggedtier=batchin the ledger;cache_read_tokens/cache_write_tokensare recorded sobernstein costcan attribute prompt-cache savings.
When an AuditChainStore is also supplied, the same boundary is mirrored into the HMAC-chained audit log via record_subagent_delegation (event type EVENT_SUBAGENT_DELEGATION = "subagent.delegation"), cross-referencing the run id, node hash, result content hash, and journal position.
Guarantees¶
- No live LLM in the coordination loop. The outer plan's identity (
node_hash/plan_hash) never depends on the native subagent's output, so the coordination graph is deterministic even though each leaf's execution is not. - Rejection before anchoring. A native result that fails schema validation raises before any journal or audit write happens - a hallucinated or malformed payload cannot enter the replay record.
- Deterministic ordering.
delegate_plan()always dispatches nodes inOuterPlan.nodesorder, so the sequence of anchored events is a pure function of the plan.
Limitations¶
- There is no dedicated CLI command for this boundary. It is an internal API called by the scheduler's dispatch path, not an operator-facing subcommand.
bernstein delegation verify <run>verifies a different surface - the per-hop HMAC authorization receipt chain incore/identity/delegation.py(the ACT log: which principal authorized which sub-agent action). It does not reconstruct or verifysubagent.delegationjournal events. Verifying a run's delegation boundaries means replaying its journal (see Deterministic replay) and, when an audit chain was wired in, checkingbernstein audit verifyfor the mirroredsubagent.delegationaudit events.delegate_plan()requires every plan node to have a matching entry in the caller-suppliednative_resultsmapping; a missing entry raisesKeyErrorrather than skipping the node.
Source¶
src/bernstein/core/agents/subagent_delegation.py