Meta Harness
Meta Harness decides how the coding actor is assembled. The actor reads the session's fact log and produces a view plus the next transition. Meta Harness lets a host choose the ordered list of components in that actor. It does not add a second loop, a second event stream, or a way around permissions and the completion gate.
If you do not set harness, the session uses the default coding_actor tree:
the stock parts in their default order. Nothing changes for existing embedders.
Invariants
Stock parts
With no components and no parts, the order is system, tools, budget,
compact, infer. Part names are case-insensitive. Any other stock name fails
with unknown harness part '<name>'; expected system|tools|budget|compact|infer.
parts is the older stock-only list. When components is non-empty it wins.
A stock-only list keeps the spec-based graph, so cause keys stay stable. Any
host: entry switches to the ordered component tree.
Host components
A host component is one Moore component: initial state, a fold over facts, and
an output that adds to the view. The host registers it under an id and
references it as host:<id>. Ids must be non-empty ASCII letters, digits, _,
or -. They are lowercased.
BuiltinHostHarnessRegistry ships one component, intent_stamp. It adds the
system line INTENT_STAMP_MARKER (a3s.meta_harness.intent_stamp.v1). Tests
use it to prove that a host mount reached the view. Unknown ids fail with
unknown builtin host harness component '<id>'; known: intent_stamp.
Rust embedders that need a whole custom graph can install a
HostHarnessAssembler. It returns a HarnessGraph and takes precedence over
with_harness. admit_component_tree(name, components) builds a graph from an
explicit component list under the same kernel policy.
Compose a session
The examples below build the same tree: stock system and tools, the
built-in intent_stamp host component, then budget and infer.
Recipe fields:
What SDKs can and cannot do
Node.js, Python, and Go pass the declarative recipe to Core. When harness is
set, each SDK installs BuiltinHostHarnessRegistry, so host:intent_stamp is
the only host id they can resolve.
Custom host components require a Rust embedder that calls
with_host_harness_registry or with_host_harness_assembler.
Failure modes
Recipe errors surface immediately: HarnessComposeOptions::compose returns an
error, Node.js Harness.compose throws, Python Harness.compose raises
ValueError, and the Go bridge rejects the session request with
INVALID_REQUEST and a harness: message. The registry resolves ids when a run
opens its fact run, so an unknown host id fails the first send or stream,
not session creation.
Relation to the completion gate
The completion gate is part of the kernel, not a stock part. No recipe removes it. A run that mutated the workspace still needs a Passed verification report bound to the effect digest, or a host waiver for that digest, before it counts as complete. See Verification.
A Rust host can supply that evidence with
SessionOptions::with_completion_attestor. The attestor runs after the
mutations exist and before the gate decides. It receives the effect digest and
the mutated paths, and may return a report. It is not a tool, the model cannot
grant it, and the gate still checks the report status and digest.