feat(discovery)!: dispatch explore and research to purpose-built subagents - #1425
Conversation
Locks the task contract for moving /discovery:research and /discovery:explore off the orchestrator's context window, and records the harness constraints that decide the mechanism. Six decisions locked: dispatch-by-default with an inline escape hatch; custom plugin subagents over context: fork; nested fan-out as an optional detected capability; index-plus-sidecars from the start rather than past a size threshold; a mandatory coverage-ledger discipline; and a Phase 0 corpus enumeration ahead of any query. Constraints verified against official docs this session — the two subagent tool filters, Workflow and AskUserQuestion being unavailable in every subagent, the Task tools not surviving the background filter, and that a context: fork skill is a regular agent type on the narrow background set rather than a conversation fork. Six amendments pending confirmation come from a completed sweep of all 138 non-setup marketplace skills: prefer runtime Skill invocation over skills: preload (no shipped agent uses preload, and whether !-precompute fires under it is unverified); disable-model-invocation blocks both dispatch paths; a fourth mechanism exists for transcript-bound skills; optional nesting has a correctness edge, not only a speed one; index-plus-sidecars is not universal; and the interactive blocker is the absence of a user, mid-flow, rather than of a tool. The sweep's evidence is memory-tier under .work/ and is not committed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BiZPDNivFJorpvhbDJDwt2
…nt review Six agents reviewed the brief and the marketplace sweep independently: an empirical probe of preload semantics, a documentation research pass, two blind re-audits of 49 skills, an adversarial audit, and a re-test of 15 rows a coverage gap had left unchecked. Records a version floor of 2.1.219. Every Constraints claim is version-gated upstream and several are false on versions still in the field: background-as-default needs 2.1.198, without which the background-filter premise collapses; forked-skill background: false needs 2.1.218; and from 2.1.172 through 2.1.216 subagents nested by default with an unchangeable limit, making the spawn-depth setting inert there. Corrects four overstated claims. The tool filters do not apply to conversation forks, which receive the parent's exact pool - so every "in every subagent" quantifier is scoped to non-fork subagents, and the history-fork mechanism no longer contradicts the constraints block. The Task-tool blocker gains its agent-teams carve-out. Plugin agents lose permissionMode override under a default-mode parent, not only an inline MCP server. The CLAUDE_CODE_FORK_SUBAGENT rollout gate has not existed since 2.1.161. Settles three preload behaviors empirically. Shell precompute fires on the preload path, byte-identical to normal invocation, retiring the largest part of the risk. allowed-tools grants do not fire there, nor on the Skill tool path - only on slash invocation, so any skill relying on its own grant under model invocation is already degraded. user_config substitution remains inconclusive for want of a positive control. Replaces the preload-versus-runtime binary, which was false twice over: the documented supporting-files pattern is better than either, and the one agent held up as prior art uses neither path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BiZPDNivFJorpvhbDJDwt2
Measured against installed discovery v0.8.2 through plugin-agent frontmatter, not inferred. Preload injects the SKILL.md body only; supporting files under the skill directory stay on demand rather than being pulled into startup context. That is the property the recommended delivery shape depends on - the mandate arrives guaranteed while the heavy reference stays lazy, so preload and progressive disclosure are not in tension. CLAUDE_PLUGIN_ROOT expands on the preload path, so a preloaded skill's pointer to its sibling reference file arrives as a working absolute path at turn zero with no resolution step asked of the agent. Two behaviors remain untested: whether preload fires when Skill is absent from tools, and whether preloaded content survives auto-compaction. Neither is load-bearing for the chosen shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BiZPDNivFJorpvhbDJDwt2
… questions Each open question was assigned a dedicated subagent, blind to the orchestrator's own recommendations. All eight returned verdicts that overturned or improved on them; in five of eight the defect was the framing rather than the facts. Decisions 7-14 record the outcomes. Dispatch becomes the default posture and INLINE-ONLY the claim needing justification. That inversion re-derived 15 of the original 57 inline verdicts, and the dominant cause was one systematic defect: multi-action skills graded on their heaviest action, so a mutating action set the verdict while a read-only sibling in the same skill carried no blocker and held nearly all the context volume. The orchestration boundary is now stated at both ends. The parent owns the pre-dispatch envelope and also verification hand-off; a dispatched agent never verifies its own work. Three agents converged on that second half independently. It supersedes the nesting-degradation clause: independence is a property of context provenance, not spawn parentage, so a verifier reading the artifact off disk is fresh regardless of who spawned it, and the spawn-depth variable reverts to an optimization. Interactive gates get a three-cell test replacing the positional mid-flow wording that had caused batches to split on identical shapes. Dispatch granularity moves to phase-level with the skill verdict as a roll-up. Discipline reaches a dispatched agent by preloading the existing skill rather than authoring a new one, since the thin-mandate over heavy-reference split already exists in the file tree. The -deep retirement resolves as a split rather than the symmetric answer first proposed: research-deep is kept because its heaviest tier is not runtime-selectable from any dispatched context, and explore-deep retires only once its replacement agent reproduces the behavior it would delete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BiZPDNivFJorpvhbDJDwt2
Thirty-two inline verdicts had been upheld on inherited batch rationale rather than read against the skills' own text. All thirty-two are now opened in full: three changed, twenty-eight upheld with their blocker restated in the criteria's own terms, and one tested as a challenge and withdrawn. Every inline verdict in the ledger has now been read against primary text. The close-out also found a second bookkeeping gap in the coverage claim: the normalization buckets account for forty-seven of fifty-seven rows, and one batch of ten sits in none of them. Those ten read as though the amended criteria were applied - they cite the fourth mechanism by name and invoke its cost-inversion clause - and the ledger's own transcription note records that batch revising a row after the amendment. Worked post-amendment, never credited. Recorded rather than papered over. Final distribution after ratification and close-out: dispatch-default 22, dispatch-optional 44, inline-only 39, no-change 33. Inline-only fell from fifty-seven to thirty-nine under the inverted burden of proof. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BiZPDNivFJorpvhbDJDwt2
…n contracts The Plan section lands beneath the existing Brief: eight phases with mechanically-verifiable Sanity Checks, blast radius, test strategy, execution shape with scope fences and a sequential fallback, and the dispositions for all twenty-eight findings from the two review passes. The design contracts are tracked rather than left as worktree-local scratch. contract-spec.md carries three amendments forced by upstream facts verified against the official subagent docs: memory is dropped from both agent definitions because declaring it re-enables Edit regardless of the tools list, which falsified C1's tool-cage claim; C2 gains a preload_token sentinel and a status field because a preload miss is silent and would otherwise produce a confident undisciplined run; and C3's header gains per-claim sources with url, tier, and pool, without which the sibling verifier cannot grade the independence criterion from the persisted artifact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both gaps closed against a live rig rather than argued: a throwaway probe plugin, three agent files with identical bodies and no tools, sentinels absent from every dispatch prompt so nothing but preload could supply them. Both skills: reference forms resolve for an agent preloading a skill in its own plugin - the bare leaf name and the plugin-scoped string alike - so C1's frontmatter is valid as written. The scoped form ships, being the one with evidence on the same-plugin and cross-plugin paths both. $ARGUMENTS is substituted with the empty string on the preload path, not left literal. That is worse than the plan assumed: research/SKILL.md line 24 reaches a dispatched agent as an instruction with nothing after the colon, invisible rather than recognizably unfilled. The topic has to arrive in the dispatch prompt, and the agent body's refuse-to-guess rule is what turns a missing one into a stop instead of an invention. The negative control earned its place. An agent declaring a skill that does not exist started anyway and reported no skill content, with nothing surfaced to the dispatching parent. F2's silent-miss premise is now reproduced on demand, which moves C2's preload_token sentinel from a precaution against a documented behavior to the detector for an observed one. Phase 0 step 1 also changes from merge to wait: a standing babysit_loop worker lane is driving #1260 and pushed three commits during this session. Racing it would truncate its work. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s beyond explore Ten behaviors, read against the skill file rather than recalled, with the site for each. Pulled forward out of Phase 5 because Decision 14's retirement gate asks whether explorer.md reproduces them and explorer.md is authored in Phase 1. Finding the list only at Phase 5 would have meant either rewriting the agent or blocking retirement on work Phase 1 could have done in the first pass. Two of the ten are the gate proper: path-scoped rules loaded explicitly, since a subagent does not auto-load them, and the sidecar diversion when an unrelated EXPLORE.md already occupies the slot. Three do not transfer as written. The empty-scope orientation pass is a mode that only makes sense when scope arrives through $ARGUMENTS, which work item 0 showed is empty under preload; a dispatched agent without scope is a parent-envelope failure, so the refuse-to-guess rule replaces it. The precompute block stays behind under Amendment 9c. And the read-only note has to name two permitted write targets, not one - the artifact and the memory root's self-ignoring .gitignore guard. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ot touch The mechanical sweep replaces hand enumeration for every discovery skill outside research/. All four are absent from #1260's five files, so their line numbers survive the Phase 0 rebase and the sweep did not have to wait on the merge. explore carries thirteen hits: eleven edits, one correct under dispatch, and line 108 - a second $ARGUMENTS site that no hand pass had found, including this plan's own. That is the third time the method has caught what enumeration missed in this file. setup returns nothing on any of the six pattern classes, so its phase is purely additive. research-deep's every hit is the skill arguing its own inline requirement, which is what acceptance criterion 9 asks to survive rather than something to reconcile. blindspot's intake question is a genuine elicitation gate under the three-cell test, so its NO-CHANGE verdict now rests on a reading instead of on inheritance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…on evidence The Brief carried "downstream consumers tolerate an index-plus-sidecar shape without code changes" as explicitly unverified. Both pre-flights have now run. No parser of the outcome-gate table exists anywhere in scripts/ or the workflows, so Phase 2's new row and the ownership column break no gate. Across forty EXPLORE.md references and every cross-plugin RESEARCH.md reference, nothing reads either artifact's section structure - they are naming references, changelog history, sibling hand-off pointers, and two test fixtures using the filename as an arbitrary path token. The one coupling with teeth turned out already handled: the documented .worktreeinclude recipe globs EXPLORE-*.md and RESEARCH-*.md alongside the index, and *-checklist.md alongside those. Had it globbed the index alone, Decision 4 would have shipped a worktree copy of pointers to files that never came along - strictly worse than the self-contained artifact it replaces. One shape is recorded as unaffected but fragile: youtube-digest's check-research-complete.js asserts a minimum length on a RESEARCH.md in its own slice. Discovery does not write that slice, so nothing breaks here, but a min-length gate is precisely what an always-an-index artifact fails. It belongs to the sweep topic. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#1260 merged as 002bb38 and this branch is rebased onto it. Records the four post-rebase values the later phases derive from, all measured rather than projected: version 0.8.5 (not the 0.8.3 the plan expected — main shipped its own 0.8.4 while #1260 was open, so #1260's entries moved up), gate table 10 rows, artifact-protocol md5s collapsing to one, Tier-3 sentence at :150. Also records the second scope change (this session drove #1260 rather than polling for it), the seven Codex rounds it took to close and why each was fixed rather than waved through, the two re-verified premises (#1096 still unmerged, both preload targets still preloadable), and one stale Phase 2 sanity check corrected at source: --all exits 1 on unmodified main, and CI runs the base-ref form instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI lints **/*.md, so these would have failed the hygiene job the moment this branch opened a PR. All five predate this session's edits. Phase 2's work items numbered 1,2,3,4,3,4,5..12 — a duplicated pair that left every item after it labelled two lower than its position. Phase 3's started at 0 with 0b and 3b interleaved. Both are renumbered to run straight, and the four cross-references that named the old labels move with them rather than being left pointing at a different item. Also: a paragraph opening with "#1260" parsed as an ATX heading, a trailing blank line, and a stray space inside a code span in Phase 1's frontmatter assertion — rewritten to describe what the check actually asserts, since the inline snippet was never runnable as written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two workers /discovery:research and /discovery:explore dispatch to, so exploration and research execution leave the orchestrator's context window. Frontmatter is C1 as amended: the plugin-scoped skills: preload form settled empirically in Phase 1 work item 0, model: inherit stated rather than omitted, and no memory: — declaring it would auto-enable Edit regardless of tools and falsify each agent's own tool-honesty note. Both bodies carry the pre-dispatch envelope contract and refuse to guess an unresolved scope, the preload-liveness sentinel protocol, the C2 return payload with verification: pending non-negotiable, the truncation contract, open questions returned as text because AskUserQuestion is filtered out of every non-fork subagent, and the hoisting rule. explorer.md additionally reproduces the behaviors Decision 14 makes explore-deep's retirement conditional on. Tool honesty is stated at its true strength in both: Bash and Write are not read-only, and Edit's absence buys no in-place mutation of an existing repo file — not read-only status, and not enforcement of the memory-tier boundary, which holds by instruction. PLAN.md records why the end-to-end runtime probe moves to after Phase 3: it grades a sentinel the preloaded skills do not carry until Phases 2 and 3 author it, so running it here would fail against agents behaving exactly as specified. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two changes to /discovery:research that share one premise — the run should not be the sole judge of itself, and the orchestrator should not pay for its reading. Dispatch posture. From the main conversation the skill now dispatches discovery:researcher; the main conversation gains a file pointer and a summary rather than the research transcript. Three documented conditions send it inline instead — turn-by-turn steering, cost on a lookup too small to be worth an envelope, and an invoking context that is already a subagent (hoisting: the outer dispatch supplied the fresh context, so the inner hop only spends the inner window). Inline relaxes nothing. The three statements that preferred inline are overturned rather than softened, because dispatch-by-default contradicts them outright: the research-deep framing at :18, the direct-context-web preference at :65, and the main-context-vs-agent tradeoff at :126. Two of them were making a real point badly — the run that judges a claim should be the run that read the source, and summarization loss is bounded by what the artifact persists — so both are restated in terms that hold in either posture. Coverage. A new mandatory Phase 0 enumerates a bounded corpus into research-checklist.md before the first query, with a per-item depth criterion fixed at enumeration time, and gate criterion 11 cites the exit status of check-coverage-complete.sh rather than a reading of the table. This is distinct from the numbered gap list: gaps chase what searching surfaced, the ledger enforces what was knowable up front. The enumeration surface must be exhaustive by construction — a ledger built from search results certifies the blind spot it exists to close. The gate also grows an Owner column. Criteria 4 and 7 ask the run to judge the quality of its own choices, so they move to a sibling verifier that never saw the run; criterion 8 needs the consuming project's conventions and stays with the parent. Sidecar headers carry per-claim sources[] with url, tier, and pool, which is what makes criterion 4 gradeable from the artifact at all — independence is a property of publishing pools, and a bare tier list encodes neither. T8 is resolved with a scoped exception: the Tier-3 rule for subagent returns targets an ad-hoc summary with no captured primaries, and does not reach a run that executed this discipline and wrote every primary URL into the artifact. The tier attaches to the artifact and its captured sources, never to the transport. check-coverage-complete.sh is TDD'd against 19 cases and fails closed: exit 2 for a ledger it cannot parse — missing, empty, no table, no Done column, a row whose width does not match the header, or a Done cell that is neither marked nor unmarked. Two bugs the tests caught: awk's exit inside a rule still runs END, which was overwriting a fail-closed exit 2 with a pass, and a row with extra columns shifted the Done position undetected. Both pre-existing skill-quality warnings are cleared, and the reference material displaced to keep the body under the soft line target lands in four progressive-disclosure spokes rather than being deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… back Mirrors the research posture on /discovery:explore, against the 13-row mechanical sweep recorded in PLAN.md rather than a hand list — the sweep is what found the :108 site that three hand passes over this file had missed. The routing section inverts: discovery:explorer is the default from the main conversation, with the same three inline conditions, and the built-in Explore subagent and /explore-deep kept as named alternatives. The old text's claim that the main session synthesizes and persists the artifact was true only of built-in Explore agents, which cannot write one; discovery:explorer writes its own, so the sentence now says which is which instead of asserting the general case. Four sites instructed something a dispatched run cannot do, each reworded to keep the rule and change only the hand-off: - Open questions were "surfaced to the USER" in the output format and the outcome gate. AskUserQuestion is filtered out of every non-fork subagent, so they now return as open_questions for the parent to surface. The anti-pattern being guarded — silent downstream resolution — is unchanged. - Missing files required asking the user before git archaeology. A dispatched run cannot ask, so proceeding would silently violate the rule that protects a deliberate deletion; it records the question instead. - Plan mode is scoped to the inline path, since EnterPlanMode and ExitPlanMode are Filter-1 tools. - $ARGUMENTS at :40 and the exploration-modes table at :108 both assumed a value that is empty under preload; scope now arrives in the dispatch prompt, with no unscoped orientation mode — a general sweep would answer a question nobody asked. EXPLORE.md becomes an always-index with sidecars, pointing at the artifact-shape spoke rather than restating the schema, and keeps the sidecar-on-collision behavior explore-deep carried. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`check` gains a fifth row reporting what the session can support behind the new dispatch posture, as PASS/INFO only — absence degrades, never blocks, because inline is always available. Three signals: the harness version against the 2.1.219 floor, naming which recorded behaviors are false below it rather than just reporting a number; CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH, whose absence costs throughput and not coverage, since the one control needing a context that has not seen the work is the outcome-gate verifier and the parent dispatches that as a sibling; and fork availability stated as a control rather than a gate, because forks have defaulted on since 2.1.161. The sibling-skill audit recorded both other skills as NO-CHANGE on their merits, and that stands: research-deep still argues its own inline requirement (Workflow is unavailable in every non-fork subagent, and its multi-topic path needs Agent, which errors even in a fork), and blindspot's intake question is a genuine elicitation gate whose answer IS the deliverable. Their skill-quality warnings are cleared without touching those dispositions — research-deep gains a Gotchas surface and Use-when trigger phrasing, blindspot's triggers become single-quoted so the drop-regression check can track them, and setup gains a Gotchas surface. All five discovery skills now pass with zero warnings, from three carrying one or two. setup's five tracked trigger phrases and explore's one are preserved verbatim. blindspot/evals/evals.json is deliberately untouched: its explore-deep references belong to Phase 5's retirement gate, and deciding them here would pre-empt it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BREAKING CHANGE: /discovery:explore-deep is removed. Callers use /discovery:explore, which now dispatches discovery:explorer by default and provides the same isolation — project memory loaded, artifact persisted by the worker, only a bounded summary returning. Decision 14 made this conditional on explorer.md reproducing what explore-deep carried beyond /explore. Graded against the ten-behavior table: seven carry directly, and the three the table said to handle differently were handled rather than copied. The empty-scope orientation pass is deliberately dropped — a dispatched agent with no scope is a parent-envelope failure, not a mode, so it stops and says so instead of answering a question nobody asked. The ! precompute is deliberately not reproduced: it fires at every spawn before the agent knows it needs the data, and multiplies under fan-out. Both Decision-14 gate conditions are met explicitly — path-scoped rules Read at Step 0, and sidecar-on-collision with the chosen filename surfaced. The gate also rests on a live result rather than a reading alone. The end-to-end probe, run once Phases 2-3 had authored the preload sentinel, confirmed on a real dispatch that preload lands, Edit is genuinely absent from the agent's tool set, the payload returns verification: pending, and the artifact set is written to the slice the envelope named. That probe earned its keep twice over: it caught two contract defects static checks could not. The run wrote its coverage ledger with a Status column of prose rather than the Done column of checkboxes the gate parses, and improvised a sidecar header with one document-level confidence instead of per-claim claims[]. Both because the detail lived only in spokes it never opened. The gate correctly failed closed on the drifted ledger; SKILL.md now carries the exact ledger shape inline and makes the sidecar-schema read imperative before the first sidecar. Seven live references are re-pointed or removed. The eighth is deliberate: MIGRATION-PLAYBOOK.md still names explore-deep, in a sentence recording that it was retired and why. The naming doctrine needed the converse of its execution-tier rule stated — a tier the base skill can reach at runtime does not earn a sibling — and this is the precedent. PLUGIN-PHILOSOPHY.md's -deep example moves to research/research-deep, the pair that genuinely cannot collapse, since its heavy tier needs Workflow and its multi-topic path needs Agent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gate Minor, not patch: two new agent components, a new mandatory research phase, a changed default execution posture, and a removed user-invocable skill. The base is 0.8.5 rather than the 0.8.3 the plan projected — main shipped its own 0.8.4 while #1260 was open, so resolving that conflict moved #1260's entries up one. The manifest description drops the stale "inline or in an isolated forked subagent" framing, which named a mode that no longer exists and missed the one that now governs. The root README carries that string verbatim at catalog generation time, so it is regenerated rather than hand-edited — validate-plugins.sh runs generate-catalog.mjs --check and would have failed this phase's own gate otherwise. Serialized last on purpose, per issue #464: same-plugin version bumps plus top-inserted CHANGELOG entries serialize concurrent PRs by construction, and this branch already paid that cost once against #1260. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Warning Automated review did not complete — this is an infrastructure failure, not a review verdict. Treat any Claude comment on this PR (including a placeholder like "I'll analyze this and get back to you") as incomplete, not "no findings."
Re-running the job, or pushing a new commit, will retry the review. |
|
Warning Automated security review did not complete — this is an infrastructure failure, not a review verdict. Treat any Claude comment on this PR (including a placeholder like "I'll analyze this and get back to you") as incomplete, not "no findings."
Re-running the job, or pushing a new commit, will retry the review. |
…ry tier The 138-skill dispatch-posture audit was written into .work/discovery-subagent-dispatch/, whose .gitignore is `*`. Every file was worktree-local: it survived a session but not a worktree cleanup, and it was invisible to any other clone or session picking the sweep up. Filing a tracked issue that pointed there would have handed the next session a dangling reference to evidence it could not read. Promoted without re-derivation — the verdicts are unchanged from the run that produced them, because rewriting them here would create a second source of truth for work already done. Relative links are rewritten for the new depth, and the ledger takes the conventional LEDGER.md name. The README states what a consuming topic still owes rather than presenting the sweep as finished: the 32 INLINE-ONLY rows upheld without an independent read, the 10 rows in no normalization bucket, and the unresolved conflict with playbooks:fable-5, whose core doctrine encodes a stricter fan-out floor than the signals this sweep used. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
…ger header Three review findings; the first is a convention-level consequence of a change this branch made, not a discovery-local defect. topic-docs 2.3.0: the .worktreeinclude template matched one level (.work/*/RESEARCH.md) while the sub-slice mechanism introduced here writes .work/<slug>/<sub-slug>/. Globs do not descend, so a spawned worktree carried the top-level index and silently dropped every nested index, sidecar, and ledger — a partial set the receiving session cannot distinguish from a complete one, which is worse than carrying nothing. Additive: five nested patterns added, nothing existing changes meaning, and no visibility guarantee moves, since a sub-slice was always inside the slice and merely unreachable by the template. The coverage gate treated ANY table with a Done column as the ledger, so an unrelated status table satisfied criterion 11 without a single corpus item ever being enumerated. It now requires the full mandated header — Corpus item, Depth criterion, Done — and keeps scanning when a table does not match, so a real ledger later in the same document is still found. Three cases added, 25 total. The explore eval still expected the retired rename-on-collision behavior. The skill and the agent were fixed in the previous commit; this is the residue that would have asserted the old contract back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dce80e568d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ariant The post-dispatch contract told the parent to dispatch the verifier and apply project fit, but never to write either result back. Since the producer returns verification: pending by construction — it may not self-grade — an index left saying pending after the parent verified it permanently understates what is known, and a later reader cannot distinguish an unverified run from a verified one whose result was never recorded. That negates the artifact's central promise: resume from the artifact alone. The parent now updates the outcome-gate result once the verifier returns and project fit is applied, and a FAIL routes back to the phase the row names rather than shipping an artifact annotated with its own failure. Stated explicitly: the verifier writes nothing itself. It never saw the run, holds no envelope, and giving a second worker write access to the slice reintroduces the one-writer-per-slice problem the sub-slice rule exists to prevent. setup still described placement as governing explore, research, "and their -deep variants" — advertising a command retired in this same branch. Phase 5's live-reference sweep grepped the literal string explore-deep and could not see the paraphrase; both sites now name /discovery:research-deep, the only -deep variant that still exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 70bee93ad5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Four review findings. research-deep's multi-topic path spawned workers that run /research from inside a subagent, and the gate assigns its independent-corroboration and HIGH-confidence rows to a fresh verifier precisely because a producing context may not grade its own choices. Those workers generally cannot dispatch that verifier — Agent is filtered out of every non-fork subagent unless the nesting variable is set — and the parent path only synthesized. The root index could therefore present claims as gate-passed that nobody ever graded. This session now owns each topic's post-dispatch boundary: verifier, project fit, results written back, and only then synthesis. The envelope named the slice path but not the memory root. From a nested slice path an agent cannot tell which ancestor is the configured root, and the root is where the self-ignoring .gitignore guard belongs — so it would either leave the real root unguarded or write a `*` into the wrong directory, both silently. The root is now its own envelope field on both agents and in both routing summaries. The coverage gate's header check accepted Corpus item + Depth criterion + Done without the mandated `#` column, so a near-miss table still exited 0 as proof a ledger was completed. All four columns are now required, each exactly once — the exactly-once half also rejects a duplicated header, where the column a value lands in is ambiguous. The cell parser split on every pipe, so a backslash-escaped pipe inside a cell — a union type, an alternation — inflated the count and made the row ungradeable. A real ledger over a real corpus could never pass criterion 11 unless rewritten to say something less accurate. Escaped pipes are now content. 28 cases, shellcheck clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
💡 Codex Review
claude-code-plugins/plugins/discovery/skills/research-deep/SKILL.md
Lines 63 to 64 in 644866e
When a heavy single-topic request has no Workflow path, this prompt runs /research inside a general-purpose subagent, where the skill requires the independent-corroboration and HIGH-confidence rows to be graded by a fresh context; however, Agent is unavailable in this fork and the parent path only surfaces the returned summary and artifact path. Although the multi-topic branch now performs sibling verification and persists it, this Tier 2 branch can still present a RESEARCH.md whose load-bearing gate rows were never verified; perform that same parent-side verification and write-back before handoff.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
docs/topics/<slug>/ is the contract tier: committed on the task branch as contracts lock, pruned before merge, with the contract pasted into the PR body in its place. The contract-slice-prune-gate enforces exactly that, and it caught this branch carrying two slices that were never meant to merge. The second one was my own error, not just an omission. The sweep evidence was promoted into docs/topics/skill-dispatch-posture-sweep/ to stop issue #1426 pointing at a gitignored path — a real problem with the wrong fix, since that destination is branch-only, and the convention's redaction bar keeps raw captures in the memory tier regardless. The eleven batch artifacts, the decision rounds, and the verification passes are raw audit captures; they stay memory-tier and are not carried. Graduated instead, per the convention's own edges: - Ticket edge: the full 138-row ledger now lives in #1426's body, which is where actionable follow-ups belong and is self-sufficient — it states its own audit criteria, so a verdict can be re-derived rather than looked up. #1427 carries the fable-5 delegation conflict. - PR body: the Brief, Phase 0's measured facts, and the C1-C5 design contracts, in details blocks. PLAN.md is 113 KB against a ~64 KB cap, so this is the convention's "paste the contract, reference the rest" — the eight phase bodies and the two review passes stay in branch history. No ADR and no new docs/specs/ tree: the vault edge is for architectural decisions and specs, and an audit result feeding a tracked work item is neither. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The spell-check gate rejects "unparseable". Only a comment is affected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
The research path gained this in an earlier round and explore did not — a parallel omission, not a different judgement. The explorer always returns verification: pending because it may not grade its own work, so an EXPLORE.md left saying pending after the parent verified it cannot be told apart from one whose verifier never ran. That artifact is the whole handoff a fresh session resumes from, which is exactly where the ambiguity costs something. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8a19e84592
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ## Dispatch decision (multi-topic check, then three tiers) | ||
|
|
||
| **Multi-topic check — run FIRST, before any tier.** Count the independent sub-topics in the ask (numbered list, enumerated questions, separable subjects that share no claims). **N ≥ 2 separable topics → do NOT dispatch an engine on the combined blob.** An engine decomposes ONE question into generic research *angles*; fed a multi-topic blob, every broad agent researches all N topics shallowly — N× the wall-clock and tokens for worse depth. Instead: spawn **N parallel topic agents** (Agent tool, `general-purpose`, one per topic, each running the full `/research` discipline; instruct each to cite primary sources by URL — a subagent return without citations is ungrounded synthesis). Each agent writes its own artifact as a sibling `RESEARCH-<topic>.md`; the main session then synthesizes `RESEARCH.md` from the per-topic artifacts. An engine is for a SINGLE contested or deep question that needs falsification rounds and adversarial claim-checking. | ||
| **Multi-topic check — run FIRST, before any tier.** Count the independent sub-topics in the ask (numbered list, enumerated questions, separable subjects that share no claims). **N ≥ 2 separable topics → do NOT dispatch an engine on the combined blob.** An engine decomposes ONE question into generic research *angles*; fed a multi-topic blob, every broad agent researches all N topics shallowly — N× the wall-clock and tokens for worse depth. Instead: spawn **N parallel topic agents** (Agent tool, `general-purpose`, one per topic, each running the full `/research` discipline; instruct each to cite primary sources by URL — a subagent return without citations is ungrounded synthesis). **Give each agent its own sub-slice** — `<memory_dir>/<slug>/<topic-slug>/`, assigned by this session in the dispatch envelope, never chosen by the worker (two workers choosing independently can choose the same one). Each writes the normal `RESEARCH.md` index, its sidecars, and its own `research-checklist.md` inside that sub-slice; those filenames are fixed, so N agents pointed at one slice root would overwrite one another's index and ledger rather than producing separable artifacts. **This session owns each topic's post-dispatch boundary — synthesis is the last step, not the only one.** The `/research` gate assigns its independent-corroboration and HIGH-confidence rows to a fresh verifier precisely because a producing context may not grade its own choices, and a topic worker generally cannot dispatch that verifier: `Agent` is filtered out of every non-fork subagent unless `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` is set. So for **each** topic, this session dispatches the sibling verifier, applies project fit, and writes both results back into that topic's index — before synthesizing. Skipping it produces the worst available artifact: a root `RESEARCH.md` presenting claims as gate-passed when the rows that matter were never graded by anyone. Then synthesize the slice-root `RESEARCH.md` from the per-topic indexes. An engine is for a SINGLE contested or deep question that needs falsification rounds and adversarial claim-checking. |
There was a problem hiding this comment.
Verify single-topic Tier 2 artifacts before handoff
When no workflow is available for a heavy single topic, the Tier 2 path spawns a general-purpose worker that runs /research inside a subagent, but the new sibling-verifier, project-fit, and write-back obligations are applied only inside this N >= 2 branch. Fresh evidence after the multi-topic fix is that lines 48–68 still return the single worker's summary and artifact directly; without nested Agent, that producer cannot complete outcome-gate criteria 4, 7, or 8 itself, so the main session can present an unverified artifact. Apply the same parent-side verification and persistence boundary to the single-topic Tier 2 return.
Useful? React with 👍 / 👎.
…and #1425 (#1886) ## Summary Eight review threads were posted on #1322 and #1425 **after** those PRs merged, so the merge gate never saw them and they stranded unresolved. All eight were verified against `origin/main` and all eight were still real — none had been fixed by a later PR. Two of them, though, were not design gaps. They were the design doc (`docs/topics/context-engineering-claude-5/design/rerun-contract.md`) having gone **stale against a shipped contract that already solved them** — `plugins/claude-config/skills/audit-pass/reference/run-contract.md` already carries both `fix-comparable` and the widened `scan-baseline state digest`. Those two adopt the shipped vocabulary and semantics rather than minting a parallel set beside it. ## Findings and disposition | # | Finding | Verdict | Fix | |---|---|---|---| | 1 | P2 vacuous under the shared unchanged-tree precondition | Real; solved upstream | Adopt shipped `fix-comparable` (attribution-based) | | 2 | External instruction surfaces missing from the run basis | Real; solved upstream | Adopt shipped `scan-baseline state digest` | | 3 | Judging model config missing from the run basis | Real; uncovered in both | Precondition on P4/P4a only, not the shared list | | 4 | Sweep machinery version missing from the run basis | Real; uncovered in both | Added to comparability and the resume digest | | 5 | `PLAN.md` acceptance gate demands a strictly smaller derived set | Real | Disappearance in the tier that reported it | | 6 | `/research-deep` single-topic Tier 2 returns an ungraded artifact | Real | One boundary section every dispatching tier cites | | 7 | Root `.worktreeinclude` missing nested sub-slice patterns | Real | Materialized; verified empirically | | 8 | Multi-topic eval encodes the retired artifact layout | Real | All six evals realigned | ## Notable design decisions - **F3 is deliberately narrower than the finding asked.** The finding said "record the judging model configuration in comparability and lane digests". Putting it in the *shared* precondition would make P1/P3/P3a unfalsifiable across a model swap while asserting nothing extra, since `D` contains no model judgement — P1 is assertable precisely *because* nothing in the derived tier passes through a model. It conditions P4's tolerance and P4a only, plus the resume digest for judged lanes. - **F1's fix carries two bounds the finding did not name**, both surfaced by review: an identity-machinery change is never attributable (it recomputes every `finding_id`, so the pair is not fix-comparable at all), and attribution requires a recorded applied-set the design doc does not yet name. Phase 6 owes that capture; until it exists P2 abstains on operator-applied routed findings rather than claiming them. ## Verification - Two independent fresh-context audit rounds with rationale withheld. Round 1 found the shipped contract I had missed and the parallel-vocabulary problem; round 2 found nine defects in the revision, of which the ones this diff caused are fixed here (lane-digest scope falsifying Assertion 5.2, the judging-configuration clause sitting in P4's consequent, the sweep-version attribution hole, the orphaned containment half, an over-reaching user-scope claim, and PLAN.md collateral). - `.worktreeinclude` verified empirically, not by reading: `git ls-files -o -i --exclude-from` intersected with `git check-ignore` in a throwaway repo. Before: nested sub-slice files silently dropped. After: carried, with baselines and raw scratch still excluded. The tracked file now matches the documented block in `docs/conventions/topic-docs/README.md` byte for byte. - Gates: `check-changed-skills.sh origin/main` PASS (0 errors, 0 warnings — a pre-existing warning cleared as a side effect), `check-changelog-parity.sh` `--check` / `--check-order` / `--check-bump` all clean, markdownlint clean, `evals.json` valid. ## Known gaps, recorded not fixed - The design doc and the shipped contract now diverge in **both** directions: the design has `sweep version`, the shipped has `behavior-affecting arguments` and an `observable detection version` (a form it adopted after finding the design's triple unestablishable from outside a delegate plugin). Recorded in `PLAN.md` as Phase 8 reconciliation work, because changing either predicate changes what the shipped pass reports. - The design doc's new basis inputs land as prose without named assertions. So do the four incumbent inputs — this is a pre-existing structural gap, not one this diff introduces. - `PLAN.md` marks Phases 6, 8 and 9 TODO while `audit-pass` ships a more advanced run contract. Implementation ran ahead of the plan; flagged, not reconciled here. No linked issue ## Related - Refs #1322 — five stranded threads (findings 1-5) - Refs #1425 — three stranded threads (findings 6-8) - Adopts vocabulary from `plugins/claude-config/skills/audit-pass/reference/run-contract.md` --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Makes
/discovery:exploreand/discovery:researchdispatch a purpose-built plugin subagent bydefault, so exploration and research execution stop consuming the orchestrator's context window.
The main conversation gains a file pointer and a summary; the reading stays with the worker.
Four changes carry that:
discovery:exploreranddiscovery:researcher, the plugin's first. Eachpreloads its skill through
skills:, so the discipline arrives as content at turn zero ratherthan as a recollection the agent may or may not reach for. Neither declares
memory, and thatomission is load-bearing: declaring it auto-enables
Editregardless of thetoolslist, whichwould falsify each agent's own tool-honesty note.
skills:entry that fails to resolve is skipped silently —logged to the debug log and nowhere else — producing an undisciplined run that still writes an
artifact and still reports complete coverage. That failure is indistinguishable from success at
every other seam this design builds, so each skill carries a token the agent echoes back and the
parent discards any run whose token is missing or mismatched.
corpus into
research-checklist.mdbefore the first query, with a per-item depth criterionfixed at enumeration time. New outcome-gate criterion 11 cites the exit status of
check-coverage-complete.shrather than a reading of the table — the context most motivated tocall a checklist finished is the one reading it.
EXPLORE.md/RESEARCH.mdare always an index withcontent in sidecars carrying a machine-readable header. Sidecar headers carry per-claim
sources[]withurl,tier, andpool— that is what makes the independent-corroborationcriterion gradeable by a verifier that never saw the run.
Two structural consequences worth calling out for review:
Ownercolumn. Criteria where the run would judge the quality ofits own choices move to a sibling verifier the parent dispatches; project fit stays with the
parent, which alone holds the consuming project's conventions. A dispatched run returns
verification: pendingand renders no verdict on those rows./discovery:explore-deepis retired (BREAKING). Once/exploredispatches a named agent bydefault, the
-deepvariant is a second door onto an execution path the base skill already has.research-deepis deliberately kept — its heaviest tier needsWorkflowand its multi-topic pathneeds
Agent, neither reachable from a dispatched context, so that tier genuinely is a secondexecution path.
Three statements that preferred inline execution are overturned, not softened, because
dispatch-by-default contradicts them outright. Two were making a real point badly and are restated
in terms that hold in either posture: the run that judges a claim should be the run that read the
source, and summarization loss is bounded by what the artifact persists.
Both skills document an inline escape hatch and the three conditions under which it is correct —
tight turn-by-turn iteration, cost on a lookup too small to justify an envelope, and an invoking
context that is itself a subagent (hoisting). Running inline relaxes no discipline.
Plan and design contracts:
docs/topics/discovery-subagent-dispatch/.Test plan
Automated, all green locally:
bash scripts/run-plugin-tests.sh— full suite passes, including the newcheck-coverage-complete.test.sh(auto-discovered).bash plugins/discovery/scripts/check-coverage-complete.test.sh— 19 cases.shellcheck -x plugins/discovery/scripts/*.sh— clean.check-skill.shfor all five discovery skills — 0 errors, 0 warnings each, up from threeskills carrying one or two warnings before this branch.
explore's 1 andsetup's 5 trackedtrigger phrases are preserved verbatim.
claude plugin validate plugins/discovery,check-changelog-parity.sh --checkand--check-bump origin/main,validate-plugins.sh,check-skill-portability.sh origin/main,markdownlint over all changed paths — all exit 0.
Live runtime probe (the part no static check reaches). A real dispatch of
discovery:researcher, with the sentinel absent from the dispatch prompt so it could only havearrived via preload:
skills:preload landed — the agent quoted the token verbatim.Editis genuinely absent from the agent's tool set — the tool-honesty note is a fact about theharness, not a claim about it.
verification: pendingand named its artifact.status: truncated/coverage: partialandmarked its claim MEDIUM rather than laundering a partial run into a complete-looking one.
The probe also caught two contract defects that static checks could not, both now fixed: the
run wrote its ledger with a prose
Statuscolumn instead of theDonecheckbox column the gateparses, and improvised a sidecar header with one document-level
confidenceinstead of per-claimclaims[]. Both because the detail lived only in spokes it never opened. The gate correctly failedclosed (exit 2) on the drifted ledger;
SKILL.mdnow carries the exact ledger shape inline andmakes the sidecar-schema read imperative before the first sidecar is written.
TDD on the one piece of executable code:
check-coverage-complete.test.shwas written first andcaught three real bugs — awk's
exitinside a rule still runsEND, which was overwriting afail-closed
exit 2with a pass (twice), and a row with extra columns shifted theDonepositionundetected.
Contract (pruned with pointer)
docs/topics/<slug>/is the contract tier — committed on the task branch as contracts lock, pruned before merge, with the contract pasted here in its place (docs/conventions/topic-docs/README.md, "Contract-slice lifecycle"). PLAN.md is 113 KB against a ~64 KB body cap, so per that same section this pastes the contract and references the rest: the Brief (the decisions a reviewer needs) and Phase 0's measured facts (what execution actually found) are below; the eight phase bodies, the two review passes, and their 28 dispositions are in the branch history atdocs/topics/discovery-subagent-dispatch/PLAN.mdbefore the pruning commit.Actionable follow-ups graduated through the tracker seam: #1426 (apply the sweep to the remaining plugins — carries the full 138-row ledger in its body) and #1427 (the
playbooks:fable-5delegation conflict).Brief — goal, constraints, the 14 ratified decisions, and acceptance criteria
Brief
TLDR
Make
/discovery:researchand/discovery:exploredispatch a purpose-built plugin subagent bydefault instead of executing in main context. The subagent runs the full discipline, writes an
index-plus-sidecar artifact set into the topic's memory slice, and returns only a file pointer plus a
one-paragraph summary. Add a corpus-enumeration phase and a coverage-ledger artifact so bounded
corpora are exhaustively accounted for rather than skimmed. Then sweep the other 138 marketplace
skills for the same treatment.
Goal
Move exploration and research execution off the orchestrator's context window. The orchestrator's
job becomes routing file pointers between stages and deciding, per stage, whether it needs to read
an artifact at all. Artifacts are structured for progressive disclosure so any consumer — parent or
sibling agent — reads only the slice it needs.
Constraints
Version floor: Claude Code 2.1.219 (the version these facts were verified on). Every claim below
is version-gated in the source docs, and several are false on versions still in the field — record the
floor with the claims or the contract silently misleads:
is the default filter" premise fails outright.
background: falseon acontext: forkskill — v2.1.218. Below it, forked skills always blockedthe turn, so the escape hatch named below does not exist.
context: forkskill — v2.1.218.CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH— from v2.1.172 through v2.1.216 subagents nested bydefault up to five layers and the limit could not be changed. On that range the env change recorded
below is inert and unnecessary. It is correct on 2.1.219.
/subtask(the forked-subagent command) — v2.1.212; it was/forkbefore.skills:preload exclusion for bundled/verifyand/code-review— v2.1.215.Harness facts verified against official docs this session
(https://code.claude.com/docs/en/sub-agents, https://code.claude.com/docs/en/skills,
https://code.claude.com/docs/en/hooks):
name,description,tools,disallowedTools,model,permissionMode,maxTurns,skills,mcpServers,hooks,memory,background,effort,isolation,color,initialPrompt.skills:preloads full skill content at subagent startup. Requires the target skill to keepdisable-model-invocation: false— all discovery skills qualify today. Preloading is not arestriction: the subagent can still invoke unlisted skills through the Skill tool.
"Forks skip both filters and receive the main conversation's exact tool pool," with
Agenttheonly carve-out inside that exemption ("in a fork the tool stays listed but returns an error instead
of spawning"). A fork IS a subagent, so every unconditional "in every subagent" claim below is
scoped to non-fork subagents. This matters because
history-forkis one of the four mechanismsin the audit vocabulary. Whether
AskUserQuestionfunctions from a background fork isundocumented in either direction — do not assume it does.
Filter 1 (every non-fork subagent):
Agent(unlessCLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHis set),AskUserQuestion,Workflow,EnterPlanMode,ExitPlanMode,ScheduleWakeup,TaskOutput,WaitForMcpServers,EndConversation. Filter 2(background only, and background is the default) reduces built-ins to
Read,Grep,Glob,Bash,PowerShell,Edit,Write,NotebookEdit,WebFetch,WebSearch,TodoWrite,Skill,ToolSearch,EnterWorktree,ExitWorktree,Monitor,TaskStop,SendMessage,Artifact, plus every MCP tool.Workflowis unavailable in every non-fork subagent.research-deep's inline-dispatcherrequirement is still correct, but rests on independent grounds — the skill states it itself
(
research-deep/SKILL.md:19) and its multi-topic path needsAgent, which errors even in a fork.The filter argument alone does not cover a fork.
AskUserQuestionis unavailable in every non-fork subagent./explore's "surface openquestions to the USER" contract degrades to text in the returned summary; the parent must
re-surface them.
TaskCreate/TaskGet/TaskList/TaskUpdatedo not survive the background filter for asubagent spawned through the Agent tool;
TodoWritedoes. Carve-out: teammates in agent teamsadditionally keep the task tools and the cron tools, so this is a property of the dispatch
mechanism, not of dispatch as such — state the carve-out wherever the rule is applied, or it
over-blocks any row whose only blocker is a task tool. Decision 5's "ledger must be a file" holds
regardless, but on durability and parent-readability, not on this filter.
context: forkskill is a regular agent type, not a conversation fork. It receives thenarrow background tool set unless it sets
background: false, which makes it block the invokingturn. Only the
forksubagent type (/subtask,CLAUDE_CODE_FORK_SUBAGENT) inherits theparent's exact tool pool.
hooks,mcpServers, andpermissionModefrontmatterfields. This costs less than it appears:
settings.jsonhooks still fire inside subagent toolcalls (the hook payload carries
agent_id/agent_typeprecisely to distinguish them), subagentsinherit the main conversation's MCP tools, and permission mode is inherited from the parent —
a parent in
automode yields a subagent inautomode. Two further losses, previouslyunderstated: (1)
permissionModeinheritance is total only under specific parent modes — under aparent in the shipped
defaultmode a project or user agent can override toplan/acceptEdits/dontAsk/bypassPermissionsand a plugin agent cannot; the earlier claim generalized fromauto,the one parent mode where the loss is nil. (2) session-level hooks give observability inside a
subagent (
agent_id/agent_typein the payload) but not scoping —PreToolUsematchers filteron tool name, so per-agent behavior must be branched inside the hook script, and frontmatter hooks
have a cleanup lifecycle the settings form lacks.
.claude/topic-docs.yamlis absent from this repo, so defaults apply —memory slice
.work/<slug>/, contract slicedocs/topics/<slug>/. Discovery writes memory tieronly; that does not change.
review/(6) andplugin-quality/(1).Environment change made this session:
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH: "5"added to~/.claude/settings.json(chezmoi-tracked; backfill tomelodic-software/dotfilesis owed). Envvars are read at session start, so nested spawning is inert until the next session.
Decisions
/researchand/exploredispatch a subagent by default, with a documented inline escape hatch for tight turn-by-turn iteration. This deliberately overridesresearch/SKILL.md's current "prefer direct research when results inform decisions" guidance; summarization loss is bounded because the full artifact is on disk and the parent may read it on demand.discovery:researcher,discovery:explorer) withskills:preload, dispatched by the parent skill. Rejected:context: forkon the existing skills (no per-invocation prompt beyond$ARGUMENTS, silent narrow-tool-set trap) and dispatcher-only with a prose discipline reminder (discipline arrives as recall, not content).CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHis an optional detected capability, not a hard requirement.discovery:setuprecommends it; without it the dispatched agent does its breadth sequentially — slower, same coverage. Same graceful-degradation shape asexplore-deep's existingCLAUDE_CODE_FORK_SUBAGENTnote.RESEARCH.md/EXPLORE.mdare always an index, with content in sidecars from the start — not only past the current ~2000-word overflow threshold. The index carries a task restatement, a one-line abstract per sidecar, and a section/claim → file+anchor table. Sidecars carry a machine-readable header (topic, claims, confidence) so a consumer can grep-then-read a single section.research/SKILL.md, its recipe incontext/discipline.md, materialized as aresearch-checklist.mdin the memory slice. Kept distinct from the existing Phase-1 numbered-gap list: that one chases unknowns, this one enforces exhaustive coverage of a bounded corpus. The file is mandatory because dispatched agents have no Task tools.| 7 | Dispatch is the default posture; INLINE-ONLY is the claim needing justification | Preserving the MAIN agent's context is the primary goal of this effort. A skill that would flood main context dispatches unless there is a real reason it cannot. This inverts the sweep's original burden of proof and is what re-derived 15 of the original 57 INLINE-ONLY verdicts. |
| 8 | The orchestration boundary (the unifying principle) | The parent owns the pre-dispatch envelope — precomputed values, scope confirmation, intake answers, budget authorization, capability checks — resolved in main context and passed into the dispatch prompt. The agent owns a bounded middle: no load-time machinery, no user turn, no unresolved scope. The parent also owns the post-dispatch boundary: verification hand-off. A dispatched agent never verifies its own work. Three independent agents converged on the second half without seeing each other. |
| 9 | Nested spawning (supersedes Decision 3's degradation clause) | Classify every nested spawn by what it buys. Throughput nesting (N independent units, identical epistemic standing) — Decision 3 stands: absent nesting the agent goes sequential, slower with the same coverage. Independence nesting (a context that has not seen what the parent produced) — Decision 3's clause is false: self-critique is not a slower control, it is the absence of one. Remedy is neither the env var nor blocking dispatch: the dispatched agent does not run the step, returns
verification: pendingplus a verification request, and the orchestrator dispatches the verifier as a sibling. Independence is a property of context provenance, not spawn parentage — a verifier reading the artifact off disk has never seen the producing context, whoever spawned it.CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHreverts to a recommended optimization. || 10 | Dispatch and producer ≠ critic | Dispatch satisfies the requirement by construction under a criteria-only envelope; the dispatched agent then runs the checklist inline rather than re-dispatching, because it is the fresh pair of eyes. Hoisting, not nesting. Distinguish two guarantees: independence (who renders the verdict — dispatch buys it) from decorrelation (how many priors examine it — dispatch does not, and never claimed to; the remedy is a cross-vendor reviewer, orthogonal to dispatch). |
| 11 | Interactive gates — the three-cell test (supersedes the positional "mid-flow" wording) | Parameter question: answerable from intent, arguments, and the conversation before the run starts — never a blocker. Test: could the parent ask this without having read a single file the skill reads? Discovered question: existence or content depends on what the run finds — blocks only if it steers. Elicitation question: blocks when the answer IS the deliverable. Batches split because "mid-flow" was read positionally (inside the step list) rather than temporally. |
| 12 | Discipline delivery to a dispatched agent | Preload the existing
discovery:researchskill via the agent'sskills:field. Author no new contract skill: the thin-mandate / heavy-reference split already exists in the file tree (SKILL.md carries the bars, phases, and outcome gate;context/discipline.mdcarries tier tables, recipes, calibration). Measured: preload injects the SKILL.md body only — supporting files stay on demand — and${CLAUDE_PLUGIN_ROOT}expands on the preload path, so the pointer to the sibling arrives working at turn zero. The mandate must arrive guaranteed, not on request, because the skill exists to stop an agent doing less than the bars require. Dispatch the skill by name; never transcribe it into a prompt (that breaks${CLAUDE_PLUGIN_ROOT}expansion, drops!precompute, and freezes a drifting copy). || 13 | Dispatch granularity (revises Decision 1) | Phase-level. The dispatch unit is a phase or action; the whole-skill verdict is a roll-up, so the 138-row ledger survives as an index. No new frontmatter — two shipped declaration shapes suffice: an execution-site column on an action-router table, and per-step annotation plus a handoff contract. For
/discovery:research: one dispatched span covering Phase 0 through Phase 4 and the outcome gate's mechanical criteria; parent keeps topic resolution at the front and presentation at the back; the gate's confidence criterion moves to a parent-dispatched sibling verifier; project-fit stays with the parent, which alone holds the consuming project's conventions. || 14 |
-deepvariants | Split, not symmetric. Keepresearch-deep— Tier 1 needsWorkflowand the multi-topic path needsAgent, which errors even inside a true fork, so its heaviest tier is genuinely not runtime-selectable from a dispatched context. The governing convention's operative test is same execution path vs. a second execution path, not frontmatter-vs-runtime, so runtime dispatch does not void it. Retireexplore-deepconditionally — relocate intoplugins/discovery/agents/explorer.md, but only once that agent reproduces its project-memory loading and sidecar-on-collision behavior.plugins/discovery/agents/does not exist yet. |Amendments (ratified 2026-07-24)
discipline via
skills:preload or by granting theSkilltool and invoking at runtime. Allseven agents this marketplace ships today use runtime invocation; none uses
skills:. Whether!-precompute blocks,allowed-toolsgrants, and${user_config.…}substitution fire underpreload is unverified — the docs specify them for when a skill runs. Proposed: prefer
runtime invocation, reserving
skills:preload for skills with no load-time machinery.disable-model-invocation: trueblocks BOTH paths, not just preload. It bars preloading andbars the
Skilltool from invoking the skill at all. Skills carrying it are undispatchablewithout flipping the flag:
dometrain:sync,education:teach,firecrawl:update,planning:questionnaire(sweep incomplete).subagent_type: "fork"is the only one inheritingthe live transcript;
plugin-agentandcontext-forkboth discard it. Skills whose input is theconversation itself require it. It is rollout-gated by
CLAUDE_CODE_FORK_SUBAGENT, degrades tostop rather than inline, and its cost scales with transcript length — inverting this Brief's
context-saving premise on a long session.
mandates its own fresh-context fan-out as a control (
planning:planStep 3, labelled "MANDATORY —never skip";
planning:audit-answersStep 2) silently degrades that step to inline self-critiquewhen dispatched without
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH. Proposed: nesting is a hardprerequisite for dispatching that subset, optional elsewhere.
/education:quiz-me's report contract explicitly forbids linking.work/ordocs/topics/paths — the sidecar shape. Index-plus-sidecars applies toartifact-producing skills, not to every dispatched skill.
AskUserQuestion. Severalskills gate that tool behind a
use_ask_user_questionconfig defaulting OFF and fall back toinline prose rounds, equally unreachable from a subagent.
!precompute may optimize, never enable — fleet-wide, independent of dispatch. The managedsetting
disableSkillShellExecution: truedisables!substitution for plugin-sourced skills andcannot be overridden. Any plugin-shipped skill whose correctness depends on
!output istherefore broken in exactly the managed/enterprise posture this marketplace designs for. 64 of the
138 non-
setupskills carry!precompute; each must be correct without it. A standing authoringrule, not a dispatch concern.
7b.
CLAUDE_CODE_FORK_SUBAGENTis a control, not a gate — the "rollout-gated" framing is stale.Forks have been enabled by default since v2.1.161; the variable now only forces on (
1) or off(
0), and the command is/subtaskas of v2.1.212. Sohistory-forkis less caveated thanrecorded, not more. The residual caveat that does stand: "Letting Claude itself spawn forks is
experimental and may change in future releases." The same stale requirement is reproduced in
shipped skill text at
plugins/discovery/skills/explore-deep/SKILL.md:3— which is doubly wrong,since it is also attached to the wrong mechanism (
context: forkis not theforksubagent type).Readthe bulk. Supersedes the earlierpreload-vs-runtime framing, which posed a false binary — and the binary was false in a second way:
plugin-quality:auditoruses neither path. Itstoolslist omitsSkillentirely and itdeclares no
skills:, so its discipline arrives as method in the agent body plus files itReadsfrom paths handed to it in the dispatch prompt. That third shape is immune to both the preload
uncertainty and the
disable-model-invocationblock, and it is essentially what this amendmentconverges on. The six
review/agents do grantSkill, so "runtime invocation is themarketplace's proven default" survives; "all seven use it" does not. The documented supporting-files pattern is
strictly better:
skills:preloads ONE small always-applies contract skill (phase gates, outcomegate, non-negotiables; well under the 500-line guidance; authored to need zero
!,${user_config.…}, orallowed-tools), while the heavy multi-phase reference lives in siblingfiles read with
Readat the phase that needs them. This beats runtime-invoking a heavy skill ontwo counts: the bulk no longer depends on the model electing to call
Skill, and a phase-scopedfile read costs less than landing a whole skill in context. Discovery is already shaped this way —
skills/research/context/discipline.mdis already a bundled reference — so this is a small delta,not a rewrite. Keep
Skillin the agent'stoolsregardless. The contract skill must NOT setdisable-model-invocation: true, which silently blocks preload;user-invocable: falseis thecorrect flag for hiding it from the slash menu while keeping it preloadable.
9a. Three preload behaviors now settled empirically (probe plugin loaded via
--plugin-dir,headless
-p, subagent defined withtools: []andtool_uses: 0so it could not have shelledout to forge the values):
!shell substitution FIRES on the preload path, and its output is byte-identical to thenormal
Skill-tool invocation. Preload is not a degraded injection path. This retires thelargest part of the risk — 36 of the 49 dispatch candidates had
!as their only concern.allowed-toolsgrants DO NOT fire on the preload path, verified against a positive control(slash invocation permits the declared command, exit 127) and a no-skill baseline (identical
refusal). Broader finding: the grant does not fire on the
Skill-tool path either — in thisbuild it appears honored only on slash invocation. So any skill relying on its own
allowed-toolswhen invoked by a model rather than typed by a user is already silentlydegraded today, dispatch or not. 13 skills corpus-wide carry one.
${user_config.…}remains INCONCLUSIVE. The placeholder survived literally on every pathtested including slash invocation, so no positive control was achieved; the probe rig's
--plugin-dirplugin likely has no resolvablepluginConfigsidentity. A real verdict needs amarketplace-installed plugin with a confirmed-live value. 25 skills carry the substitution.
9b. Two further preload behaviors settled empirically (probe against installed discovery v0.8.2
via plugin-agent frontmatter; scripts and transcripts in the session scratchpad,
run11/run12):SKILL.mdbody ONLY. Supporting files under the skill directory stayon-demand — they are not dragged into the agent's startup context. This is the property that
makes the recommended shape work: the mandate arrives guaranteed while the heavy reference stays
lazy, so preload and progressive disclosure are not in tension.
${CLAUDE_PLUGIN_ROOT}expands on the preload path. The pointer a preloaded skill carries toits sibling reference file therefore arrives as a working absolute path at turn zero, with no
resolution step required of the agent.
9c. Two preload behaviors remain undocumented and untested. Whether preload still fires when
Skillis absent fromtoolsor listed indisallowedTools(strongly implied by two docsentences read together, never asserted); and whether preloaded content survives auto-compaction —
the re-attachment budget is defined over "the most recent invocation", and a preloaded skill was
never invoked. Amendment 8 is chosen so neither is load-bearing.
Note that
!firing does not argue for preloading precompute: it fires at every spawn beforethe agent knows it needs the data, which multiplies under fan-out.
Acceptance criteria
/discovery:research <topic>with no other arguments dispatches a subagent; the mainconversation gains a file pointer and a summary, not the research transcript.
/discovery:explore <scope>.discovery:researcheranddiscovery:exploreragent definitions exist underplugins/discovery/agents/, preload their skill viaskills:, and declare nohooks/mcpServers/permissionMode(ignored for plugin agents).research-checklist.mdenumerating every corpusitem with a per-item depth criterion and a completion mark, and the outcome gate fails when any
item is unmarked.
RESEARCH.mdandEXPLORE.mdare indexes with per-sidecar abstracts and a section → file+anchortable, regardless of total size.
discovery:setupdetectsCLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHand recommends setting it;absence degrades rather than blocks.
research-deepstill dispatches Tier 1 from main context (Workflowis subagent-unavailable).call
AskUserQuestion.Captured assumptions
RESEARCH.md/EXPLORE.mdtolerate an index-plus-sidecar shape withoutcode changes. Unverified — consumers across
planning,implementation, andsession-flowhavenot been audited. Flagged for the plan step.
.claude/topic-docs.yamlstays absent in this repo, so slice defaults hold.was requested).
Out of scope
.work/<slug>/) — unchanged.vendor/directory — upstream-owned.setupskills across the marketplace (39 of them) — install/config surface, never dispatchcandidates.
Phase 0 — measured facts, and why the version moved twice
Design contracts C1–C5 — the cross-boundary shapes this PR implements
Contract spec — discovery-subagent-dispatch
The five cross-boundary contracts this design owes. Companion to
design-threads.md; the ratified decisions live in../PLAN.mdand are not restated.
Upstream harness facts are pointed at, never restated — per issue #1225's locked pointer-not-copy
rule, the link index is
docs/OFFICIAL-DOCS.mdand the canonical pagefor every frontmatter field below is https://code.claude.com/docs/en/sub-agents.
C1 — Agent-definition frontmatter contract
Two definitions under
plugins/discovery/agents/. Shape follows the seven already shipped inplugins/review/agents/andplugins/plugin-quality/agents/— quotedtoolsstring,memory: local,explicit
effortandmaxTurns— with one addition none of them use:skills:.Field rationale:
tools—Editis absent, and that absence is real only becausememoryis not declared(see the amendment above). What the cage actually buys: no single-call in-place mutation of an
existing repo file. What it does not buy: read-only status, or mechanical enforcement of the
memory-tier invariant —
BashandWriteboth write, per the doctrine's own tool-cage wording.State it that way in the agent body; do not call the agent read-only.
Skillstays regardless ofskills:preload, per Amendment 8.skills— Decision 12.research/SKILL.mdwas verified preload-suitable this session: 187lines, one trivial
!precompute (git branch --show-current), zeroallowed-tools, zero${user_config.…}. Amendment 9b's measured behavior applies — the SKILL.md body only, with${CLAUDE_PLUGIN_ROOT}expanded, socontext/discipline.mdstays lazy.model: inherit— stated explicitly rather than omitted. A research verdict is consequential,and the doctrine's ladder requires session tier or above;
inheritguarantees exactly sessiontier and never below. A hard pin would fight
CLAUDE_CODE_SUBAGENT_MODELand the doctrine's owndated tier table, which carries a recheck trigger this design should not duplicate.
hooks/mcpServers/permissionMode— omitted. Plugin-shipped agents ignore all three.memory— omitted deliberately, and the omission is load-bearing. See the amendment above.background— omitted; background is the default from v2.1.198 and is wanted here.Named-agent bar conformance (PR #1096): multi-site is satisfied — the same worker dispatches
from
/discovery:researchand from the marketplace's DISPATCH-DEFAULT rows. The second conjunct isargued from the tool cage, not met — the cage narrows the write surface without enforcing the
memory-tier invariant, and the F1 amendment makes clear how close that argument came to collapsing
outright. The genuinely load-bearing capability is
skills:preload, which the bar does notenumerate; the upstream proposal to admit it as a third qualifier rides on #304 / #1096. Do not
overstate this conjunct anywhere downstream.
C2 — Return payload (verification request)
An instance of issue #496's return-payload contract: identifiers plus verdict plus parked payload,
never the transcript. The agent returns one fenced YAML block followed by at most one paragraph of
prose.
preload_token— the preload-liveness sentinel (amendment 2026-07-25, finding F2). A missing ordisabled
skills:entry is skipped silently, logging only to the debug log — verified verbatimat https://code.claude.com/docs/en/sub-agents. Without a liveness signal, a preload miss produces
an undisciplined run that still writes an artifact and still self-reports
coverage: complete: thefailure mode is indistinguishable from success at every seam this design builds, which is precisely
the guarantee Decision 12 exists to provide. The preloaded skill therefore carries a sentinel string
the agent must echo verbatim into this payload. The parent treats a missing or mismatched
preload_tokenas a hard failure and discards the run — it does not downgrade, warn, or accept theartifact. This is the one seam that makes "the mandate arrived" observable rather than assumed.
status— the truncation contract (amendment 2026-07-25, finding F3).maxTurnshas nodocumented partial-return semantics: the docs define it only as "Maximum number of agentic turns
before the subagent stops." Because this design writes the ledger and sidecars incrementally, a
turn-limit stop otherwise leaves a half-marked ledger, orphan sidecars, and an index naming files
that were never written — with no payload at all, so the parent never learns the run died. Rules:
the agent writes
status: truncatedplus a partial payload before its budget is exhausted; adispatch that returns no payload is treated as truncated-without-warning; in both cases the
parent discards the partial slice rather than resuming it, because a half-run ledger cannot be
distinguished from a complete one by the coverage script alone.
verification: pendingis Decision 9's non-negotiable: the producing agent renders no verdict onits own confidence criterion. The orchestrator dispatches the verifier as a sibling, which is
why nesting stays an optimization rather than a correctness prerequisite.
Outcome-gate row assignment
Decision 13 splits the gate three ways but does not enumerate it. The split rule: a row the producer
can read off an artifact stays with the producer; a row where the producer would judge the
quality of its own choices goes to the sibling verifier; a row needing the consuming project's
conventions stays with the parent, which alone holds them.
Row 4 lands with the verifier rather than the producer despite looking mechanical: "independent"
is a judgment over the source set the producer itself assembled, which is the same self-grade class
as row 7.
Amendment 2026-07-25 (finding F7) — row 4 was not gradeable as specified. The verifier reads the
persisted artifact and has never seen the run, and the skill's own gate demands every criterion be
read off an artifact. Row 7 clears that bar: C3's header carries
claims[].confidence. Row 4 —"≥2 independent corroborators, not one upstream pool" — did not, because C3 persisted only
tiers: [0, 1], which encodes neither independence nor pool provenance. C3's header is thereforeextended (below) to carry per-claim source URLs with independence attribution. Without that
extension the only honest alternative was to move row 4 back to the producer as a declared
self-grade; the extension is preferred because row 4 is the corroboration bar the whole discipline
rests on. Rows 9 and 10 are counted here because PR #1260 is changing this table's row count before
this design is implemented — the assignment is written against the post-merge table deliberately.
Open tension this contract must resolve —
research/SKILL.md:148currently reads: "Subagentreturns are Tier 3 (synthesis), not corroborators, until their cited primaries are fetched this
turn." Read literally, dispatch-by-default demotes every research run to Tier 3, because the
orchestrator's view of the work IS a subagent return. The rule was written against an ad-hoc
subagent summary, not against a dispatched agent that ran the full discipline and captured every
primary URL into the artifact. The tier belongs to the artifact and its captured sources, not to
the transport. The rule needs a scoped exception naming the discipline-running dispatched case;
without it, Decision 1 contradicts the skill it is modifying. This is a required edit to
research/SKILL.mdand therefore lands in PR #1260's collision surface.C3 — Sidecar header schema
YAML frontmatter, chosen over an HTML comment block: it parses with tooling the repo already runs
and matches the skill/agent frontmatter convention used marketplace-wide. Vocabulary is reused,
not invented —
HIGH | MEDIUM | LOWandTier 0..3are the research skill's own(
SKILL.md:42,context/discipline.md:9-12).The index (
RESEARCH.md/EXPLORE.md) carries a task restatement, the per-sidecarabstractverbatim, and a section → file+anchor table. A consumer greps headers, then reads exactly one
sidecar.
Amendment 5 scopes this: index-plus-sidecars applies to artifact-producing skills, not to every
dispatched skill.
C4 — Coverage ledger (
research-checklist.md)Written in Phase 0, before any query. One row per corpus item.
The depth criterion is fixed at enumeration time and is per-item, not global — that is what
Decision 6 buys by giving enumeration its own phase.
Gate is a script, not a model read. A
check-coverage-complete.shreturns non-zero when anyDonecell is unmarked; the outcome-gate row cites the script's exit status. Two consequences:the verdict is deterministic and survives a context that wants to be done, and the row earns check
21's
deterministic-gateexemption class honestly rather than needing a delegation declaration.C5 — Execution-site declaration
Decision 13 already fixed the shapes — an execution-site column on an action-router table, and
per-step annotation plus a handoff contract. No new frontmatter. This contract fixes only the
enforcement.
Extend the existing declaration contract owned by
plugins/skill-quality/skills/check/reference/fresh-eyes-declarations.md(PR #1096, check 21)rather than standing up a second scanner. Check 21 declares who judges; this adds where a phase
executes — an adjacent proposition over the same greppable, deterministic substrate:
dispatch|inline|either.set and a mandatory
-- <reason>, per the ESLint-description precedent that contract cites.skill-quality; discovery is a consumer, not a second spec owner.This is an upstream contribution to #304's program, sequenced after #1096 merges.
Related
No linked issue.
Context this work touches, none of which it closes:
execution of it, scoped to the discovery plugin. The 138-skill marketplace sweep is promoted to
its own tracked topic rather than ridden along here.
against
mainat time of writing: noDelegation mechanicssection, no check 21, noskill-quality/skills/check/reference/. Every reference to that doctrine in the plan is markedaspirational, and no skill text here claims its exemption.
in this PR is an instance of that contract's shape, not an independent invention.
why the manifest and CHANGELOG edits are serialized into the last commit.
Builds directly on #1260, merged earlier today; this branch is rebased onto it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01QExBnEHWTRCzUUxFY4t5Dz