A rule naming a tool that assembly registers only under some configuration or
in a sub-registry (system_one, advise, best_of_n, apply_isolated,
discard_isolated, submit_plan, conclude_no_changes, review_report,
complete_subtask) was refused on save and reported dormant at load, because the
tool is absent from the registry at that moment. Each owner now declares its
conditional tool with tool.RegisterConditional and the controller's vocabulary
reads the declarations; a boot test reconciles every tool the assembly can
register against the built-ins plus the declarations. The dormant-rule item
shape is also held by wire-parity.
The task tool, read-only tasks, fleets, parallel tasks, the sub-agent
store and records, profiles and the child's capability grant move from
internal/runtime/agent to internal/runtime/delegation. They are clients
of the agent: they build child agents and run them. The executor loop
now names none of them.
What the loop itself does for a child stays in agent. child_run.go holds
running an agent as a child and composing its answer and host receipts.
child_registry.go holds shaping the child's tool surface. Delegation uses
a small exported surface for these: AppendHostReceipts, AttachReviewReport,
CompleteSubtaskContract, ExpandToolPatterns, MaxToolOutputBytes,
NormalizeToolSchemas, SubagentImageNote, VisionRefFor, WithCallContext
and the host-receipt labels.
Tests followed the code. The ones that check the agent's own judgements
against the real delegation tools (batch skipping, the plan-mode barrier,
contract hints, delegation profiles across the proxy) run as agent_test
in the agent directory through export_test.go. The user-turn retention
test is split so each package pins its half. Test helpers used on both
sides are copied, since neither test binary may import the other. One
test more than before, from that split; none dropped.
Baseline: the moved files carry their debt unchanged under the new path,
and task.go gains the one import line the move costs (-allow-widen).
Three moves close the edges from the contract layer into runtime/evidence:
- The audit records the host emits beside a run (ReadinessAudit,
OutcomeSample, DelegationAudit) move to contract/hostaudit, so event and
trajectory carry them without the ledger that computes them.
ClassifyEvidenceOrigin, which reads delegation text, stays in evidence as
a function over the record.
- taskcontract and plancontract move from contract to runtime: only the
agent and completion consume them, and both are built from evidence
receipts rather than declaring data anything lower reads.
- evidence moves from runtime to safety. It imports nothing above the
subsystem layer, and builtin tools and the trajectory recorder, both
subsystems, depend on it.
layer-order drops from 18 to 5.
internal/ was 141 packages side by side, so nothing but a reader's memory
said which were foundations and which assembled the rest. Each now sits in a
layer directory, and the directory is the declaration:
base L0 foundation with no domain in it
contract L1 types and interfaces the layers above agree on
model, tools, safety, ext, state, platform
L2 subsystems, peers of one another
runtime L3 the turn engine
session L4 the controller
assembly L5 the composition root
frontend L6 cli, serve, acp and the host adapters
Only paths change: package names, code and behaviour do not. Imports,
repolint and coverage baselines, sensitive paths, CI package lists and docs
follow the new paths; release notes keep the paths they were written with,
and sample paths inside tests and fixtures keep theirs.
repolint gains layer-order: a package may import its own layer and those
below it, read from where it lives. The 47 imports that point upward today
are recorded as that rule's opening debt (-allow-widen, a new rule's first
baseline) and can only go down. Most of it is config, which still reaches
into eight subsystems and is the next thing to take apart; the rest is
event, history and a few tools reaching into runtime for types that belong
in contract.