Skip to content

fix(discovery): correct nested-spawn availability claims to the current default - #1574

Merged
kyle-sexton merged 3 commits into
mainfrom
fix/discovery-nesting-default-currency
Jul 26, 2026
Merged

fix(discovery): correct nested-spawn availability claims to the current default#1574
kyle-sexton merged 3 commits into
mainfrom
fix/discovery-nesting-default-currency

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Closes #1573

Split out of the session-flow:orchestrate audit work (#1570 / #1572) because it is a different
plugin with its own version and changelog.

What this corrects

Four places asserted the harness "filters Agent out of every non-fork subagent unless
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH is set." That was accurate for exactly two releases,
2.1.217–2.1.218.

Verified 2026-07-26 against the byte-exact raw changelog:

Version Verbatim
v2.1.172 "Sub-agents can now spawn their own sub-agents (up to 5 levels deep)"
v2.1.217 "Changed subagents to no longer spawn nested subagents by default; set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH to allow deeper nesting"
v2.1.219 "Subagents can now spawn nested subagents up to depth 3 by default (was 1); set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 to disable nesting"

Confirmed behaviorally on 2.1.220: a non-fork general-purpose subagent held a fully-schema'd
Agent tool with the variable unset.

Why it mattered enough to fix

The variable's polarity flipped. It used to be the opt-in that turned nesting on; it is now also
the knob that turns nesting off (=1). So "absent" no longer implies "off" — and
skills/setup/SKILL.md's dispatch-capability row was recommending operators set it on exactly that
inference, reporting a capability gap that does not exist and telling them to configure something
already on by default.

The agent definitions were less harmful: their operative instruction — "check whether the tool is
actually there rather than treating the flag as a guarantee" — is correct and survives untouched.
Only the stated reason was wrong. That instruction is, if anything, better supported now: the
default has moved three times in seven weeks, which is the argument for observing rather than
deriving.

Note on provenance

The upstream sub-agents prose page still documents the off-by-default state and has not absorbed
v2.1.219. That is how both this plugin and the audit that reviewed it landed on the same stale
reading — and it is why the fix pins claims to versions and points at behavior rather than restating
a page that is itself lagging.

Changes

  • agents/explorer.md, agents/researcher.md — same paragraph in both. Reason restated; added that
    a denied spawn is a permission verdict rather than a depth one, since spawns are
    classifier-evaluated before launch (v2.1.178) and the error text is what tells them apart.
  • skills/setup/SKILL.md — the dispatch-capability row now reports the value against the running
    version and names which window each reading belongs to, instead of recommending the variable on a
    false premise. Still INFO, never a gate.
  • skills/research-deep/SKILL.md — two spots restated as availability to be observed. The claim
    that Agent "errors even inside a fork" is replaced by the invariant that actually holds: a fork
    cannot spawn a further fork.

Verification

  • check-changed-skills.sh origin/main — 2 skills checked, 0 failed. setup PASS 0 warnings;
    research-deep PASS with 2 warnings confirmed pre-existing (same count on the unmodified file
    at base — they are fresh-eyes proximity warnings against a single very long paragraph, untouched
    by this change).
  • check-changelog-parity.sh --check-bump origin/main — passes; discovery 0.9.0 → 0.9.1.
  • Trigger phrases preserved on both skills (6/6 and 5/5); no frontmatter touched.

Related

…nt default

Four places asserted the harness "filters Agent out of every non-fork subagent
unless CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH is set" — accurate only for Claude
Code 2.1.217 through 2.1.218.

Verified 2026-07-26 against the byte-exact release changelog: nesting shipped at
a fixed five layers (v2.1.172), went off by default (v2.1.217), and returned at
v2.1.219 — "Subagents can now spawn nested subagents up to depth 3 by default
(was 1); set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 to disable nesting."
Confirmed behaviorally on 2.1.220: a non-fork general-purpose subagent held a
fully-schema'd Agent tool with the variable unset.

The polarity flip is what makes the stale wording actively misleading rather
than merely dated: the variable now lowers the ceiling as readily as it raises
one, so "absent" no longer implies "off" — and setup's dispatch-capability row
was recommending people set it on exactly that inference.

The necessary-not-sufficient framing and the check-the-tool-is-actually-there
instruction in the agent definitions were already right and are kept; only the
reason changes, plus a caution that a denied spawn is a permission verdict
rather than a depth one, since spawns are classifier-evaluated before launch.

Claims are now version-pinned so the next default move reads as drift rather
than as settled fact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 49s —— View job


PR Review

  • Gather context and read changed files
  • Review plugin.json and CHANGELOG.md
  • Review agent definitions (explorer.md, researcher.md)
  • Review skill files (research-deep/SKILL.md, setup/SKILL.md)
  • Verify internal consistency across all changed files
  • Post final review

Assessment: Approve

This is a clean, well-scoped documentation correction. The factual claim that nested spawning was disabled by default (requiring CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH to opt in) was stale as of v2.1.219, and the PR applies the correction correctly and consistently across all affected files. No structural or behavioral issues found.


plugin.json

Version bumped 0.9.00.9.1. Appropriate for a prose/documentation fix with no API surface change. Consistent with semver.


CHANGELOG.md

The new [0.9.1] entry at lines 7–28 is accurate and well-sourced:

  • Verbatim changelog quotes for three version milestones match what the PR body cites
  • Behavioral confirmation (2.1.220 observation) is included
  • The polarity-flip consequence is clearly explained
  • Per-file summary accurately describes what each file changed and what was kept

Minor cosmetic note: The [0.9.1] header has no date, unlike some entries (e.g., [0.8.3] — 2026-07-24). Not all entries have them, so this is a style inconsistency, not an error.


agents/explorer.md and agents/researcher.md

The updated "Tool honesty" paragraphs in both files are identical, which the PR claims. Both now read:

Agent is listed, but listing is necessary and not sufficient: the harness also has to be allowing nested spawning at your depth, and that default has moved repeatedly (fixed five layers, then off, then a configurable default of three as of Claude Code v2.1.219 — tunable via CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH, which now lowers the ceiling as readily as it raises one). Both conditions must hold, which is why your dispatch prompt carries a nesting flag rather than leaving you to infer one — and why you check whether the tool is actually there rather than treating either the flag or a version number as a guarantee. A spawn that comes back denied is not an answer about depth: spawns are permission-classified before launch, so read the error text.

This is correct on every factual point and improves on the prior text in two ways:

  1. The polarity-flip is now explicit ("now lowers the ceiling")
  2. The new sentence about permission-classification is a genuinely useful addition — a depth error and a classifier denial look different in practice

The defensive instruction ("check whether the tool is actually there") is preserved unchanged. The "dispatch prompt carries a nesting flag" framing is still correct.

Observation: The mention of "v2.1.219" is a specific version claim that could go stale if the default moves a fourth time. The tradeoff is reasonable — it provides concrete history — but the guarding instruction (observe, don't derive) is the load-bearing part and it survives.

Permalinks to the updated paragraphs:


skills/setup/SKILL.md

The dispatch-capability section (lines 55–84) is the most substantive change and is correct:

  • Three-epoch history named explicitly (2.1.172 → 2.1.217 → 2.1.219)
  • Correctly identifies the 2.1.217–2.1.218 window as the only period where absent meant off
  • Correctly states that on 2.1.219+ absent means available, and the variable now lowers the ceiling ("1" disables)
  • Still INFO, never FAIL — the non-blocking posture is preserved
  • Adds that the variable is only one of two conditions (the tool must also be listed in the agent definition), which was implicitly true before but is now stated

Minor observation: The note "env vars are read at session start, so a value set now takes effect next session" appears at line 78 (inside the dispatch-capability section) and also in the Gotchas section at line 131. Minor duplication, but both locations are appropriate for operator attention.


skills/research-deep/SKILL.md

Two corrections in this file:

  1. Multi-topic check (line 28): Changed from a specific claim about the current nesting state to the more durable formulation: "a nesting default that has moved three times and is not worth designing against." This is a better abstraction — it explains why the code doesn't depend on the default rather than re-stating what the default currently is, which would itself be a bet on stability.

  2. Gotchas — "Dispatching this skill itself" (lines 84–88): The old claim that Agent "errors even inside a fork" is replaced by "inside a fork, cannot spawn a further fork at all." This is more precise — it's not that the tool is absent or errors; it's that the type constraint (fork cannot produce fork) is what applies. The corrected sentence better matches the actual invariant.


Internal consistency

  • The same paragraph is updated identically in both agent definitions ✓
  • The historical version sequence (2.1.172 → 2.1.217 → 2.1.219) is consistent across CHANGELOG, setup/SKILL.md, and the agent prose ✓
  • setup/SKILL.md correctly reflects that the variable's meaning flipped, consistent with the agent files ✓
  • research-deep/SKILL.md uses a more durable framing (moved three times) rather than restating the current default — consistent with the PR's stated approach of observing rather than deriving ✓

No blocking issues.

@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 38s —— View job


Security Review

  • Gather context: fetch PR diff and read changed files
  • Analyze changed files for security issues
  • Report findings

Scope reviewed: 6 files in plugins/discovery/plugin.json, CHANGELOG.md, agents/explorer.md, agents/researcher.md, skills/research-deep/SKILL.md, skills/setup/SKILL.md.

All changed files are Markdown instruction files for AI agents and supporting metadata (version bump, changelog). There are no GitHub Actions workflows, shell scripts, code files, or credential-handling paths in this diff.

Prompt injection surface (no new risk)

Both explorer.md and researcher.md carry an "Untrusted-content posture (standing instruction)" section that explicitly guards against repository content attempting to alter the agent's task, write destination, or return payload. This section is unchanged by the PR. The new text in the "Tool honesty" blocks does not weaken that posture.

Capability claims and spawn depth (no security regression)

The PR corrects the documented polarity of CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH. The old text said the variable was the opt-in that enabled nesting; the new text correctly notes that (≥v2.1.219) nesting is on by default and the variable can now lower the ceiling. This is a documentation accuracy fix; the agents do not derive new capabilities from the correction, and the operative instruction — check whether Agent is actually in the tool list rather than inferring availability from configuration — is preserved intact.

Write-destination controls (unchanged, correct)

explorer.md permits writes only to the memory-slice path and the root .gitignore guard. researcher.md permits writes only to the memory-slice path and the same guard. Neither is altered by this PR.

Fork / non-fork capability boundary

The old research-deep/SKILL.md claimed Agent "errors even inside a fork." That was inaccurate: a fork can spawn non-fork subagents; it cannot spawn a further fork. The new text is more precise: "inside a fork, cannot spawn a further fork at all." The corrected claim is security-neutral — it narrows rather than widens the stated capability boundary.

setup/SKILL.md dispatch-capability row

The old text recommended operators set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH to "5" on the assumption that absent meant off. The new text reports the value against the running version without prescribing a setting. This removes advice that could cause operators to misconfigure an env var in the opposite direction (e.g., setting it to 1 on a future release thinking they are enabling nesting when they are disabling it). No new security risk introduced.


No security findings. The changes are factual corrections to AI agent instructions with no execution surfaces, no credential handling, no authorization logic, no injection vectors, and no GitHub Actions modifications. The prompt-injection defenses that guard against repository content are preserved intact.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e248a484ad

ℹ️ 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".

Comment thread plugins/discovery/skills/setup/SKILL.md Outdated
…ow in setup

Review finding on #1574: the rewritten dispatch-capability row collapsed
everything below 2.1.217 into "absent meant available," which is wrong for
2.1.171 and older — nested spawning did not exist before 2.1.172, so an unset
variable there buys nothing and reporting it as available reproduces the exact
false capability report this change set out to remove. The check explicitly
supports versions below its 2.1.219 floor, so that range is reachable.

Now stated as four windows against the observed version: <2.1.172 unavailable,
2.1.172-2.1.216 available at a fixed five, 2.1.217-2.1.218 off (the only window
where setting the variable turned nesting on), 2.1.219+ available at three.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Right, and it is the same class of error the PR is fixing. Corrected in 6471a75.

I had collapsed everything below 2.1.217 into "absent meant available," which is false for 2.1.171 and older — nested spawning did not exist before 2.1.172, so an unset variable there buys nothing. Since the check explicitly supports versions under its 2.1.219 floor, that range is reachable in practice.

Now stated as four windows against the observed version:

  • < 2.1.172 — nesting does not exist; the variable buys nothing
  • 2.1.172–2.1.216 — absent means available at a fixed five
  • 2.1.217–2.1.218 — absent means off; the only window where setting it turned nesting on
  • 2.1.219+ — absent means available at three

@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 22s —— View job


PR Review (updated commit 6471a75)

  • Gather context and read changed files
  • Review the incremental fix (four-epoch version window)
  • Verify internal consistency across all changed files
  • Post final review

Assessment: Approve

The incremental fix at 6471a75 correctly addresses the Codex P2 finding. The original PR (commit e248a48) collapsed everything below 2.1.217 into "absent meant available," which was wrong for versions < 2.1.172 where nested spawning did not exist at all. The updated text in setup/SKILL.md#L69–73 now correctly states four distinct windows:

Window Behavior
< 2.1.172 Nesting does not exist; variable buys nothing
2.1.172–2.1.216 Absent means available at a fixed five
2.1.217–2.1.218 Absent means off; the only window where setting it turned nesting on
2.1.219+ Absent means available at three

The fix is isolated to one file (setup/SKILL.md). The second commit touches nothing else, which is appropriate — the agents and research-deep skill were correctly updated in the first commit and don't share the same <2.1.172 gap (they use durable "observe, don't derive" framing rather than reciting window-specific states).

CHANGELOG.md note: No new entry was added for 6471a75. Since both commits land together as version 0.9.1, this is correct — the changelog is a version-level summary, not a commit log. The existing 0.9.1 entry's description of "names which window each reading belongs to" now accurately describes the four-window result rather than the three-window intermediate.

No issues. The text reads cleanly, the four-window enumeration is internally consistent, and the transition phrase "Report absent as INFO in every window" (replacing "either way") correctly generalizes across all four cases.


@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 33s —— View job


Security Review

  • Fetch PR diff (commits e248a48 + follow-up 6471a75)
  • Read changed files (plugin.json, CHANGELOG.md, agents/explorer.md, agents/researcher.md, skills/research-deep/SKILL.md, skills/setup/SKILL.md)
  • Analyze for security issues (logic flaws, injection surfaces, trust boundary changes, capability escalation)
  • Post findings

Scope: 6 files in plugins/discovery/ — all Markdown instruction files and a JSON version bump. No GitHub Actions workflows, no code execution paths, no credential handling.

Prompt-injection defenses — unchanged, correct

Both explorer.md (L84–92) and researcher.md (L81–88) carry "Untrusted-content posture" sections that instruct the agent to treat repository content as data and disregard any directives it contains. Neither section was touched by this PR. The new "Tool honesty" text in both files does not add any new path where external content could influence agent behavior.

researcher.md additionally binds untrusted URLs to single-quoted shell variables before use — that instruction is also untouched.

Write-destination controls — unchanged, correct

Both agent definitions constrain Write to the memory-slice path named in the dispatch prompt and the memory root's self-ignoring .gitignore. These boundaries are stated in both files and were not altered.

Capability escalation — not present

The corrected text in the agent "Tool honesty" paragraphs tells agents to observe whether Agent is actually in their tool list rather than inferring availability from configuration state. This reduces the risk of an agent attempting a nested spawn it cannot perform — it does not expand what the agent believes it can do. The load-bearing instruction ("check whether the tool is actually there") is preserved verbatim.

Env var polarity — correction removes misconfiguration risk

The old setup/SKILL.md text told operators to set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH on the assumption that absent meant nesting was off. On v2.1.219+, that assumption is reversed: absent means available at depth three, and setting the variable to "1" disables nesting. Following the old advice on a current harness would have silently removed a capability the operator intended to enable. The PR replaces the prescriptive recommendation with a read-against-version report, which is the safer posture. No new misconfiguration surface is introduced.

Four-window breakdown (6471a75) — tightens a false capability claim

The follow-up commit correctly distinguishes < 2.1.172 (nesting not implemented; variable has no effect) from 2.1.172–2.1.216 (available at five). The pre-e248a48 text collapsed these two into "absent meant available," which was wrong for any harness that predates v2.1.172. Since setup/SKILL.md explicitly supports harnesses below its 2.1.219 floor, that range is reachable in practice. The correction prevents a false positive capability report on those versions — the exact class of error this PR set out to remove.

research-deep/SKILL.md fork constraint

The old claim that Agent "errors even inside a fork" is replaced by "inside a fork, cannot spawn a further fork at all." (L84–88) This is more precise: a fork can spawn non-fork subagents; the invariant is that a fork cannot produce another fork. The corrected statement narrows rather than widens the stated capability boundary. No security regression.


No security findings. The changes are factual corrections to AI agent instructions with no new execution surfaces, no credential handling, no authorization logic, no new injection vectors, and no GitHub Actions modifications. All existing injection and write-destination defenses are preserved intact.

@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 28s —— View job


PR Review

  • Gather context
  • Read changed files and full diff
  • Review correctness and internal consistency
  • Post final review

Assessment: Approve

The latest push (7b312a5) is a no-content merge from origin/main; the substantive changes are the two prior commits (e248a48, 6471a75), which previous review rounds already cleared. This round confirms the full diff is correct as merged.


Commit summary

Commit Content
e248a48 Initial fix — corrects nested-spawn claims across all six files
6471a75 Follow-up — adds the pre-2.1.172 window to setup/SKILL.md
7b312a5 Merge from origin/main — no content changes to plugin files

setup/SKILL.md four-window breakdown (L69–72)

The Codex P2 finding is fully addressed. The four windows are now:

Window Reading
< 2.1.172 Nesting does not exist; variable buys nothing
2.1.172–2.1.216 Absent means available at a fixed five
2.1.217–2.1.218 Absent means off — only window where setting it turned nesting on
2.1.219+ Absent means available at three

The "report absent as INFO in every window" instruction correctly generalizes across all four cases, removing any prescriptive recommendation that assumed a specific default.


agents/explorer.md and agents/researcher.md

Both "Tool honesty" paragraphs updated identically. Polarity-flip is explicit ("lowers the ceiling as readily as it raises one"). The permission-classification caution ("A spawn that comes back denied is not an answer about depth") is a genuine improvement over the prior text. The load-bearing instruction — check whether the tool is actually there — is preserved.


skills/research-deep/SKILL.md

Two corrections, both correct:

  1. Multi-topic check text now uses the durable framing ("a default that has moved three times") rather than restating the current window, which is more stable against further harness changes.
  2. Gotchas — the old "errors even inside a fork" is replaced by the precise invariant: "inside a fork, cannot spawn a further fork at all."

plugin.json / CHANGELOG.md

Version bump 0.9.0 → 0.9.1 is appropriate for a prose/documentation fix. The CHANGELOG [0.9.1] entry accurately describes all per-file changes at version granularity. The entry has no date, consistent with some (not all) prior entries — style inconsistency, not an error.


Two minor cosmetic notes (non-blocking)

  1. setup/SKILL.md L73 — "nesting buys" falls at the end of a line with "throughput" starting the next. Renders correctly in Markdown, but reads awkwardly in the raw source that agents consume. The meaning is unambiguous.

  2. research-deep/SKILL.md L86–88 — "— the two things\n it exists for." is a hanging phrase carried over from the original. Not wrong; slightly choppy in raw form.

Neither issue affects behavior or correctness.


No blocking issues. The full diff is internally consistent, the four-window breakdown resolves the only open finding, and the merge commit introduces no regression.

@claude

claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 28s —— View job


Security Review

  • Gather context
  • Fetch PR diff
  • Read changed files
  • Analyze for security issues
  • Post findings

Scope: 6 files in plugins/discovery/plugin.json, CHANGELOG.md, agents/explorer.md, agents/researcher.md, skills/research-deep/SKILL.md, skills/setup/SKILL.md. All are Markdown instruction files or a JSON version bump. No GitHub Actions workflows, shell scripts, code execution paths, or credential-handling surfaces in this diff.

Prompt-injection defenses — unchanged and correct

Both explorer.md (L84–91) and researcher.md (L81–88) carry "Untrusted-content posture" sections instructing the agent to treat repository content and fetched pages as data, disregarding any embedded directives. Neither section was touched by this PR. The new "Tool honesty" text does not introduce any path by which external content could influence agent behavior.

researcher.md additionally binds untrusted URLs to single-quoted shell variables before use (L90–91) — also untouched.

Write-destination controls — unchanged and correct

explorer.md constrains Write to the memory-slice path named in the dispatch prompt and the memory root's self-ignoring .gitignore guard (L67–68). researcher.md constrains Write to the same two destinations (L62–65). Neither boundary was altered.

Capability escalation — not present

The corrected "Tool honesty" paragraphs in both agent definitions tell agents to observe whether Agent is actually present in their tool list rather than inferring its availability from configuration state or version numbers. This reduces the risk of an agent assuming a spawn it cannot perform — it does not expand what the agent believes it can do. The operative instruction ("check whether the tool is actually there") is preserved verbatim from the prior text.

Env var polarity — correction removes misconfiguration risk

The old setup/SKILL.md text recommended setting CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH to "5" on the assumption that absent meant nesting was off. On v2.1.219+, that assumption is inverted: absent means available at depth three, and "1" disables nesting. Following the old advice on a current harness would have silently removed capability an operator intended to enable. The PR replaces the prescriptive recommendation with a read-against-version report across four named windows (L64–81). This is the safer posture and introduces no new misconfiguration surface.

Four-window breakdown (6471a75) — tightens a false capability claim

The follow-up commit correctly adds < 2.1.172 (nesting not implemented; variable has no effect) as a distinct window, separate from 2.1.172–2.1.216 (available at five). The original commit had collapsed these two, which would have reported a false positive capability on harnesses that predate v2.1.172. Since setup/SKILL.md explicitly supports harnesses below its 2.1.219 floor, that range is reachable in practice. The correction prevents exactly the class of false capability report this PR set out to remove.

Fork constraint precision — narrows, does not widen

The old research-deep/SKILL.md claimed Agent "errors even inside a fork." The replacement states "inside a fork, cannot spawn a further fork at all" (L84–88). This is more precise: a fork can spawn non-fork subagents; the invariant is that a fork cannot produce another fork. The corrected claim narrows the stated capability boundary; no security regression.


No security findings. The changes are factual corrections to AI agent instructions with no new execution surfaces, no credential handling, no authorization logic, no new injection vectors, and no GitHub Actions modifications. All existing injection defenses and write-destination controls are preserved intact.

@kyle-sexton
kyle-sexton merged commit ad95213 into main Jul 26, 2026
31 checks passed
@kyle-sexton
kyle-sexton deleted the fix/discovery-nesting-default-currency branch July 26, 2026 18:24
kyle-sexton added a commit that referenced this pull request Jul 26, 2026
…the changelog (#1572)

Closes #1570
Closes #1571

Works the `plugin-quality:audit` handoff for `session-flow:orchestrate`
(audit filed against #1479).
**The audit's ranked top finding is refuted.** The rest of the ranked
set lands.

## The headline finding was wrong, and that is the main result

The audit reported, as HIGH: `SKILL.md`'s "a configurable default of
three" is factually wrong,
nesting is off by default, and a worker following imperative 5 hits a
missing-tool condition.

It is not wrong. Verified this session against the **byte-exact raw
changelog** — deliberately not a
summarizing fetch, because the audit itself recorded that this page
reads inconsistently through a
summarizer and asked whoever remediated to re-fetch it directly:

| Version | Verbatim |
|---|---|
| v2.1.172 | "Sub-agents can now spawn their own sub-agents (up to 5
levels deep)" |
| v2.1.217 | "Changed subagents to no longer spawn nested subagents by
default; set `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` to allow deeper
nesting" |
| **v2.1.219** | **"Subagents can now spawn nested subagents up to depth
3 by default (was 1); set `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1` to
disable nesting"** |
| v2.1.220 | "Bug fixes and reliability improvements" — does not revert
it |

Installed harness is **2.1.220**. The skill's three-state history is
exactly right.

Cross-checked behaviorally rather than only by reading: a non-fork
`general-purpose` subagent one
layer below a subagent held a fully-schema'd `Agent` tool with
`CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`
unset in its environment. The prose page's account forbids that
outright. (The exact live ceiling was
not pinned — the probe that would have measured it was denied by the
auto-mode permission
classifier, a different gate. Recorded as unverified rather than
asserted.)

**Where the audit went wrong.** It sourced the finding from
<https://code.claude.com/docs/en/sub-agents>, which still reads "By
default, a subagent can't spawn
subagents of its own… While nesting is off, Claude Code withholds the
`Agent` tool from every
subagent except a fork." That page has not absorbed v2.1.219 — it is one
release behind. Its own
version Note ("From v2.1.172 through v2.1.216…") is self-consistent with
the superseded state, which
is what made the stale reading look confirmed. The audit's supporting
empirical reproduction is also
explainable without nesting being off: a restricted agent type whose
`tools` list omits `Agent`
produces "the `Agent` tool was entirely absent" regardless of the
nesting default.

Per the fresh-docs mandate, both pages were fetched this session and the
disagreement is recorded
rather than silently resolved. Every behavioral claim below cites a page
fetched 2026-07-26.

## What actually needed fixing

`context/sources.md:70-84` **was** genuinely stale — just not for the
filed reason. Its quotes "a
background subagent at depth five does not receive the Agent tool" and
"The limit is fixed and not
configurable" appear nowhere in the current page and are contradicted by
the env var existing at
all. Rewritten to current text: version-pinned changelog quotes for the
depth default, the current
tool-list gating sentence (which now carries a "once you allow nested
spawning" qualifier the old
quote lacked), all three separately-overridable caps with defaults
(200/session v2.1.212+,
20 concurrent v2.1.217+, depth), the fork-is-a-leaf constraint, and an
explicit **drift note**
naming which surface to believe for what.

`SKILL.md`'s depth paragraph now attributes the depth-3 default to the
changelog that carries it
rather than the page that currently contradicts it, pins each state to
its version, and adds a rule
the audit's own failure mode argues for directly: **confirm nesting from
behavior, not from one
page** — dispatch one worker, check whether it holds `Agent`, before
committing a design to a second
layer. A tree authored from either source alone can be wrong in *both*
directions. It also records
that a denied spawn is a permission verdict, not a depth verdict (spawns
are classifier-evaluated
before launch, v2.1.178) — a distinction that cost this session its
depth measurement.

## The rest of the ranked set

- **F1.1** — a non-binding size anchor for imperative 7, placed in the
Tiered-delegation section,
which is already export-omitted, so the pasted brief stays model- and
tool-agnostic.
Cites the workflow size guideline and the 25-agent `Large workflow`
flag.
- **F1.2** — `${CLAUDE_EFFORT}` read into the **priming addendum only**,
matching the skill's
existing lane for machine-specific reads. Verified from the skills page
fetched this session.
- **F5.2** — two eval cases that test judgment rather than formatting: a
small ask that must stay
single-agent, and a wide fan-out that must default the fleet to a
cheaper tier while keeping the
  adjudication stage at parent tier.
- **F5.5** — `context/gotchas.md`, clearing the `skill-quality:check`
warning.
- **`docs/OFFICIAL-DOCS.md`** — the changelog and workflows pages are
now indexed. `orchestrate`
cited both as load-bearing evidence and neither was in the indexed set,
which put those citations
outside the fresh-docs mandate's own index. The changelog row carries
handling rules: fetch raw
markdown for byte-exact quotes, always pin the version, pair with the
topic page rather than
  replacing it.

## Deliberately not done

- **F4.1 (handoff-relay convention)** — deferred. #1476 is OPEN, labeled
`needs-human`, and its body
says "Before implementation" with its outcome set explicitly not yet
derived. The audit itself
scoped this "once #1476 locks its exact wording." Writing imperative-4
qualifying text against
  unlocked wording risks contradicting the final convention.
- **F1.2 remediation 2 (`context-guard` wiring)** — deferred; #1479
scoped it assess-only. The
audit's own blindspot note applies: zero `context-guard` references
exist anywhere under
`plugins/session-flow/`, so this is a plugin-wide decision, not an
`orchestrate` one.
- **F5.3** — declined. Softening one trigger phrase would convert a
prose change into a frontmatter
contract change for a NIT the audit calls "optional strengthening only."
- **F2.3, F1.3** — informational / residual risk by the audit's own
verdict; no change implied.

## Verification

- `check-skill.sh orchestrate` — **PASS, 0 errors, 0 warnings** (was 1
warning: no gotchas surface).
  All 7 base-ref trigger phrases preserved; frontmatter untouched.
- `check-changelog-parity.sh --check-bump origin/main` — passes;
`session-flow` 0.17.13 → 0.17.14.
- `evals.json` validates against
`plugins/skill-quality/reference/evals.schema.json` (7 cases).

## Related

- #1574 — the inverted sub-claim, split out. The audit cites
`plugins/discovery/`'s files as
"already state the current, correct fact"; they state the superseded
one. Different plugin, own
version and changelog, so it is a separate PR rather than part of this
one.
- #1573 — the issue #1574 closes.
- #1479 — the read-only work item the audit fulfilled. Not closed by
this PR.
- #1476 — handoff-relay convention. F4.1 depends on its wording locking;
deferred, not closed here.
- #1475 — companion context-guard zone-crossing hooks issue, referenced
by #1476. Untouched.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

discovery: nested-spawn availability claims describe a state that lasted two releases

1 participant