Development record
In-Session Subagent Dispatch — the Default Host-Delegated Oracle
Superseded by itd-2609201916056194 on 2026-09-20, on the product thinker's ruling: host-delegated dispatch became the default by the boundary rule in AGENTS.md rather than by the
autoandin-sessionconfig values this record names, which were never built; the one repo-wide oracle backend it keys on is read by nothing and is re-decided per agent by itd-2609170822093401; the CLI adapter draft is what finally gives that backend a second value. The multi-iteration audit-fix loop is itd-50's and reaching another harness is itd-22's.
Press Release
abcd's default oracle backend needs zero external setup: it delegates to the host's in-session subagent. Every oracle call — audits, plan-reviews, impl-reviews — routes to an in-session Claude subagent via the host's Task tool. No subscriptions to configure, no MCP servers to install, no CLIs to find. The persona gets Carmack-style reviews from the same
oraclealready running their session, out of the box. Opt-in oracle adapters (RepoPrompt and others) route reviews to a different vendor when a persona configures one — but nothing needs configuring for the default to work."I was on a borrowed laptop with no external oracle configured," said Henry, junior developer. "abcd just used the in-session
oracle. The review wasn't as cross-vendor as an external adapter would give, but it was instant and free — and it worked without me setting anything up."
Why This Matters
Every external oracle adapter needs external setup — a desktop app, a CLI, a subscription. Requiring any of them before abcd can review anything is friction. So the default oracle path uses the abcd-running Claude session itself: host-delegated, always available, zero setup. External adapters are opt-in, layered above this default for personas who want cross-vendor review.
The challenge: abcd's core process cannot directly call the host's Task tool — that's a model-side capability, only Claude (running in the harness loop) can invoke it. Crossing that boundary requires a wire protocol.
What's In Scope
- Sentinel-output protocol: when
AgentDispatch.dispatch_agent(agent_name="in_session", ...)is invoked, the harness emits a structured payload (JSON) that the orchestrating Claude session reads as a tool result and translates into aTasktool invocation. The slash-command markdown (commands/intent.md,disembark.md, etc.) embeds instructions telling the host: "if the script returned atask_dispatchpayload, invoke Task with these args." - Subagent context isolation: each in-session dispatch spawns a fresh subagent context (no continuity by design — the no-state-between-calls property is documented as an in-session-specific limitation, distinct from an external adapter's chat-based continuity).
- Result return path: the Task subagent's output flows back via the host session into a file or stdout that abcd's loop reads on next iteration.
- No-continuity caveat: the same-chat re-review semantics an external oracle adapter may offer do NOT apply to in-session — each iteration is a fresh Task call. The audit-fix loop must re-prime context every iteration. This is acceptable: host-delegated in-session dispatch is the default oracle path, and per-iteration re-priming is its documented tradeoff.
- Verdict parser interop: in-session subagent outputs use the same
<verdict>...</verdict>tag protocol as every oracle adapter.
What's Out of Scope
- Autonomously orchestrating multiple in-session subagents (e.g. for parallel review of different facets) — single subagent per call; multi-agent orchestration is a future intent or part of a broader brief revision.
- Routing to specific Anthropic models (Opus vs Sonnet vs Haiku) — uses whatever model the user's Claude Code session is running. abcd doesn't pick.
- Cost optimisation (in-session calls bill against the user's Claude subscription; abcd doesn't budget) — covered by itd-17 model effectiveness tracking if relevant.
- Capability-aware backend selection. Choosing among the host default and any configured oracle adapters by
(task_class, agent, model_id)capability is itd-17's concern (capability-aware dispatch), layered ABOVE this intent's default host-delegation. This intent ships only the default path; it never selects backends.
Scope Conditions
None stated.
Acceptance Criteria
BDD format, per
itd-1-acceptance-gates. These gates are checked byintent-fidelity-reviewerwhen this intent moves toshipped/.
- Given a fresh laptop with no oracle adapter configured and
oracle.backend = "auto"in.abcd/config.json, when any abcd command invokes the oracle (e.g./abcd:disembark's lifeboat-oracle Phase C audit), then the audit completes successfully via in-session subagent dispatch and writes a finding JSON to.abcd/lifeboat/audit/oracle-<ts>.jsonwithout ever attempting an external network call or shell-out toclaude -p. - Given
oracle.backend = "in-session"is explicitly pinned, when abcd's host script returns its sentinel-output payload, then the orchestrating Claude session reads the payload, invokes the host'sTasktool with the agent name and prompt declared in the payload, and returns the subagent's output back to abcd via the documented result-return path (file or stdout) for the next iteration to consume. - Given an in-session-dispatched subagent emits a Carmack-style review, when abcd parses the result, then the verdict tag matches the same
<verdict>SHIP|NEEDS_WORK|MAJOR_RETHINK</verdict>protocol used by every oracle adapter — the parser is backend-agnostic. - Given an audit-fix loop runs over multiple iterations under
oracle.backend = "in-session", when the second and subsequent iterations dispatch, then each iteration is a freshTaskcall with no inheritedchat_idcontinuity AND abcd's loop re-primes the subagent context (artefact + prior verdict + applied fixes) every iteration — the no-state property is documented in04-surfaces/02-disembark.mdand surfaced in CLI help text. - Given
oracle.backend = "auto", when an oracle call runs and a persona has configured an opt-in oracle adapter, then that adapter handles the call; and given no adapter is configured, then the call routes to the in-session host-delegated default — host-delegation is the default, never an error for missing external setup. - Given a different host harness (per itd-22's transport-/host-agnostic reach), when an in-session dispatch is requested, then the dispatch routes through that host's subagent invocation primitive AND the same wire-protocol contract holds — the per-host branch is invisible to the calling agent.
Open Questions
- What's the canonical wire protocol shape? JSON-on-stdout with a
next_action: "task_dispatch"field, or some other sentinel? Slash-command markdown needs to know what to look for. - How does the orchestrating session know to read the wire-protocol payload? The slash-command markdown instructs Claude — but commands like
/abcd:disembarkinvokescripts/abcdwhich spawns a long-running process; how does the post-process payload get back to Claude's view? - Does this work across hosts (per itd-22)? Each host has its own subagent invocation primitive; the dispatch impl needs a per-host branch.
- What's the right way to test this without spinning up a real subagent? Mock the host's Task tool? Stub the wire-protocol consumer side?
- Does itd-2 need to ship before itd-22 (host-agnostic reach), or can both be designed in parallel since they share the dispatch Protocol surface?
Audit Notes
Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/.
Frontmatter
| id | itd-2 |
|---|---|
| type | intent |
| lifecycle | superseded |
| kind | standalone |
| severity | critical |
.abcd/development/intents/superseded/itd-2-in-session-subagent-dispatch.md
open on GitHub ↗ · commit history ↗
Referenced by4
- adr-35The lifeboat is a coverage experiment — read-only, out-of-tree, and proven before it is packed (supersedes adr-4)related
- adr-39Host-tier policy — MCP floor, reference host, open-source defaultrelated
- itd-2609201916056194A role runs through the command-line harness the operator chose, and every fall back to the host is recordedsuperseded by
- itd-2609201916151817One verb takes a READY intent to delivered, and refuses while a decision is openrelated
mentions18
- dcn-26071400000000012026-07-14 — The lifeboat is built as a COVERAGE EXPERIMENT, not a feature
- dcn-26071400000000052026-07-14 — adr-35's blast radius across the record was FAR wider than the plan
- iss-94The intent corpus still specifies the pre-adr-35 lifeboat model: itd-2, itd-8, itd-9, itd-10, itd-13, itd-15, itd-19, itd-22 and itd-24 variously use the retired 'disembark to home' signature, the in-tree .abcd/lifeboat/ home, or the in-tree .abcd/development/voyage/ path (itd-9's acceptance writes voyage provenance in-tree — the exact path that would fail abcd's own privacy-hygiene audit rule). The brief, glossary and roadmap were reconciled to adr-35; the intents were deliberately NOT rewritten, because an intent is a proposal with its own lifecycle and silently rewriting nine of them inside an unrelated change is worse than tracking the drift. Each reconciles when it is next planned.
- iss-299brief/README.md's 05-internals directory-tree comment enumerates ten chapters including a nonexistent 'in-session dispatch' (that is planned intent itd-2, not a chapter); the directory holds nine files and its own index has nine rows
- iss-392bughunt round-3 confirmed nitpick batch — zero-padded record-id filenames evade the id-uniqueness lint in all three families; the go-version lockstep test skips .yaml workflows; scripts/*.sh lack the eol=lf pin the repo's own policy states; agents/CHANGELOG announces lifeboat-reviewer 0.1.1 while the prompt carries 0.1.0; five live records still route to the pre-flattening commands/abcd/ and retired docs/reference pages
- iss-2608301803423101an unclosed comment or fence anywhere in an issue record blinds every grounds triage route permanently and promote orphans a draft per attempt
- iss-2609240227236354itd-6 passes its readiness gate (intent ready itd-6: READY, all seven checks ok) but cannot be built from today's tree: its spec spc-2609211950427074 stands on four things that do not exist. (1) The build loop's validator stage the adapter implements, itd-2609201916151817 (planned, spec spc-2609202134338445 open; there is no build verb). (2) The layered oracle.review resolver the model-tier and pacing intents share, itd-2609170822093401 and itd-2609201925079472 (both planned, specs spc-2609180535002478 and spc-2609202134341288 open). (3) The command-line runner the adapters chapter entry sits beside, itd-2609201916056194 (planned, spec spc-2609221533057881 open). (4) An MCP client, which the spec's Approach names as a new dependency subject to the new-dependency sign-off; go.mod has none. itd-6 declares builds_on [itd-2] only, so the gate has no edge to refuse on and READY reads as buildable to a run that picks it.
- iss-2609300903497125record-lint did not check dependency edges against supersession or cycles: an intent's builds_on or blocked_by naming a superseded intent passed (record_schema checks existence only), and so did two intents building on each other; the base tree carried eleven such stale edges and the runner and loop cycle with record-lint green
- itd-1Every Intent Has Acceptance Criteria; Every Audit Verifies Them
- itd-5Every Agent Prompt Carries Its Version, Earns Its Lock, And Survives Injection
- itd-6RepoPrompt over MCP is one opt-in reviewer route, beside the host's own agents
- itd-17Pick the Right Oracle for the Job, Automatically
- itd-22abcd Reaches Any Harness Through an Adaptor
- itd-33Multiple Agents Coordinate On Intent And Spec Work Without Duplicating Effort Or Producing Competing Artefacts
- itd-47Oracle-Backed Gates Pass Honestly Without A Human In The Loop
- itd-50The Audit Loop Drives An Intent To Acceptance — Or Calls For A Replan
- itd-179The reasoning behind what was pursued no longer evaporates at the gate — readiness and triage record grounds for the conjecture, not only the decision
- itd-2609170822093401abcd proposes the model each agent deserves, and facilitates it where it can