Filed by an automated plugin-quality audit (session-based, not a maintainer) — see reasoning and verify independently before acting; this is a report, not a mandate.
Audited: discipline 0.9.0, read from ~/.claude/plugins/cache/melodic-software/discipline/0.9.0/. claude plugin validate passed clean.
Finding (IMPORTANT) — no runtime preflight before fanning out forks
Location: skills/sweep-all/SKILL.md step 1 (Fan out, audit-only); cross-referenced against skills/setup/SKILL.md step 6.
The skill's own claim (step 1): fork-spawning is a rollout-gated capability (CLAUDE_CODE_FORK_SUBAGENT); so if forks are unavailable, the text says to report that the inheriting audit fan-out cannot run and stop, rather than auditing blind. That sentence sits inline in the fan-out step's prose — there is no separate numbered pre-step that gates the loop on a check before spawning. setup/SKILL.md step 6 separately reports the same fact as an install-time INFO note (where it is off, only the session-start posture digest runs), but that is a one-time setup report a user may never re-read, not a runtime invariant sweep-all itself enforces per invocation.
Observed: in the audited session, CLAUDE_CODE_FORK_SUBAGENT was unset (confirmed via echo, independently reproduced by the auditor in a fresh Bash invocation). Six subagent_type: fork agents were spawned in parallel before any check. The degradation was discovered only because one fork (sweep-follow-standards) self-reported back that its context held only the system prompt and task message — no parent turns came across. The other five were stopped once the pattern was recognized, but all six had already been spawned.
Doc citation: https://code.claude.com/docs/en/sub-agents — "Fork the current conversation" section (fetched 2026-07-26). Verbatim:
"Before v2.1.212, the forked-subagent command was /fork. It was enabled by default on v2.1.161 or later; on v2.1.117 through v2.1.160 it required setting the CLAUDE_CODE_FORK_SUBAGENT environment variable to 1, unless a server-side rollout enabled it... This capability may also be enabled in interactive sessions as part of a staged rollout."
"Setting CLAUDE_CODE_FORK_SUBAGENT=1 enables fork mode... setting it to 0 disables fork mode everywhere, including any server-side rollout."
The important nuance the doc adds: an unset value does not reliably mean "off" — it defers to an undocumented server-side staged rollout. A client-side env-var read is therefore a necessary-but-not-sufficient probe: it can prove "definitely off" (=0) or "definitely on" (=1), but "unset" is genuinely ambiguous from inside the session.
Failure scenario: the skill's own text states this outcome directly, not as a hedge — sweep-all/SKILL.md step 1: "Fork-spawning is a rollout-gated capability (CLAUDE_CODE_FORK_SUBAGENT); where it is off, requesting the fork type falls back to a fresh general-purpose subagent that cannot see the conversation — so if forks are unavailable, report that the inheriting audit fan-out cannot run and stop, rather than auditing blind." The skill already documents both the failure mode and the required response; the gap is purely that nothing enforces the check before the fan-out loop runs. Nothing in sweep-all detects this before spawning. The cost is the skill's own documented figure — roughly 170K tokens per fork (its Gotchas section), and up to ~1.4M tokens for an 8-in-scope pass run in two waves of four — multiplied by the fan-out width, plus a full round-trip of manual investigation before the fan-out can be aborted.
Severity: IMPORTANT. Not a correctness failure (the fork honestly self-reported; no audit result was silently trusted), but exactly the "silently expensive" class the audit lens flags: 6 wasted spawns before abort.
Candidate remediations (cheapest first)
- Cheapest, and the auditor's recommended adoption: insert an explicit step 0 in
sweep-all's batch pass — dispatch ONE fork first as a canary, instruct it to report whether it can see prior conversation turns, and only fan out the remaining N-1 forks once that's confirmed. This is more robust than an env-var read precisely because "unset" is ambiguous per the doc above — a canary reflects the true runtime resolution (local override plus server rollout combined) rather than only the local override.
- Cheap adjunct, explicitly not a substitute: also read
CLAUDE_CODE_FORK_SUBAGENT as a fast short-circuit — a 0 read can skip the canary and stop immediately at zero cost; a 1 or unset read still needs the canary. State this asymmetry explicitly in the skill text so a future editor doesn't simplify it back to an env-var-only check.
- More ambitious: promote
setup/SKILL.md step 6's install-time awareness into something sweep-all itself re-checks every run, rather than trusting a report the user saw once, if ever.
Named assumptions and blindspots (stated as such, not as fact)
- The exact silent-fallback mechanic (falls back to a fresh general-purpose subagent with empty context) is stated by
sweep-all/SKILL.md itself, and corroborated by the audited session's own empirical observation (the self-reporting fork) — but it is not independently confirmed in the fetched official doc's own wording, which documents the CLAUDE_CODE_FORK_SUBAGENT gate and staged-rollout ambiguity but not the specific fallback-to-empty-context behavior in those terms. This review did not re-fetch the doc a second time to double-check that specific gap.
CLAUDE_CODE_FORK_SUBAGENT's true resolution in any given session also depends on an undocumented server-side staged-rollout state per the official doc's own wording ("may also be enabled... as part of a staged rollout"). The empirical echo check only proves the local env var is unset, not that fork mode is definitively off for that machine's sessions overall. This is a limit of the plugin's own detectable surface, not something the audit pass could close.
- The auditor did not check whether
discipline's other fan-out correctors (do-your-research-deep, recheck-against-upstream-deep) share sweep-all's exact capability-dependency pattern on forks — plausible given the shared method doc, but unverified. Worth a follow-up pass if this plugin is revisited.
Filed by an automated plugin-quality audit (session-based, not a maintainer) — see reasoning and verify independently before acting; this is a report, not a mandate.
Audited:
discipline0.9.0, read from~/.claude/plugins/cache/melodic-software/discipline/0.9.0/.claude plugin validatepassed clean.Finding (IMPORTANT) — no runtime preflight before fanning out forks
Location:
skills/sweep-all/SKILL.mdstep 1 (Fan out, audit-only); cross-referenced againstskills/setup/SKILL.mdstep 6.The skill's own claim (step 1): fork-spawning is a rollout-gated capability (
CLAUDE_CODE_FORK_SUBAGENT); so if forks are unavailable, the text says to report that the inheriting audit fan-out cannot run and stop, rather than auditing blind. That sentence sits inline in the fan-out step's prose — there is no separate numbered pre-step that gates the loop on a check before spawning.setup/SKILL.mdstep 6 separately reports the same fact as an install-time INFO note (where it is off, only the session-start posture digest runs), but that is a one-time setup report a user may never re-read, not a runtime invariantsweep-allitself enforces per invocation.Observed: in the audited session,
CLAUDE_CODE_FORK_SUBAGENTwas unset (confirmed viaecho, independently reproduced by the auditor in a fresh Bash invocation). Sixsubagent_type: forkagents were spawned in parallel before any check. The degradation was discovered only because one fork (sweep-follow-standards) self-reported back that its context held only the system prompt and task message — no parent turns came across. The other five were stopped once the pattern was recognized, but all six had already been spawned.Doc citation: https://code.claude.com/docs/en/sub-agents — "Fork the current conversation" section (fetched 2026-07-26). Verbatim:
The important nuance the doc adds: an unset value does not reliably mean "off" — it defers to an undocumented server-side staged rollout. A client-side env-var read is therefore a necessary-but-not-sufficient probe: it can prove "definitely off" (
=0) or "definitely on" (=1), but "unset" is genuinely ambiguous from inside the session.Failure scenario: the skill's own text states this outcome directly, not as a hedge —
sweep-all/SKILL.mdstep 1: "Fork-spawning is a rollout-gated capability (CLAUDE_CODE_FORK_SUBAGENT); where it is off, requesting theforktype falls back to a fresh general-purpose subagent that cannot see the conversation — so if forks are unavailable, report that the inheriting audit fan-out cannot run and stop, rather than auditing blind." The skill already documents both the failure mode and the required response; the gap is purely that nothing enforces the check before the fan-out loop runs. Nothing insweep-alldetects this before spawning. The cost is the skill's own documented figure — roughly 170K tokens per fork (its Gotchas section), and up to ~1.4M tokens for an 8-in-scope pass run in two waves of four — multiplied by the fan-out width, plus a full round-trip of manual investigation before the fan-out can be aborted.Severity: IMPORTANT. Not a correctness failure (the fork honestly self-reported; no audit result was silently trusted), but exactly the "silently expensive" class the audit lens flags: 6 wasted spawns before abort.
Candidate remediations (cheapest first)
sweep-all's batch pass — dispatch ONE fork first as a canary, instruct it to report whether it can see prior conversation turns, and only fan out the remaining N-1 forks once that's confirmed. This is more robust than an env-var read precisely because "unset" is ambiguous per the doc above — a canary reflects the true runtime resolution (local override plus server rollout combined) rather than only the local override.CLAUDE_CODE_FORK_SUBAGENTas a fast short-circuit — a0read can skip the canary and stop immediately at zero cost; a1or unset read still needs the canary. State this asymmetry explicitly in the skill text so a future editor doesn't simplify it back to an env-var-only check.setup/SKILL.mdstep 6's install-time awareness into somethingsweep-allitself re-checks every run, rather than trusting a report the user saw once, if ever.Named assumptions and blindspots (stated as such, not as fact)
sweep-all/SKILL.mditself, and corroborated by the audited session's own empirical observation (the self-reporting fork) — but it is not independently confirmed in the fetched official doc's own wording, which documents theCLAUDE_CODE_FORK_SUBAGENTgate and staged-rollout ambiguity but not the specific fallback-to-empty-context behavior in those terms. This review did not re-fetch the doc a second time to double-check that specific gap.CLAUDE_CODE_FORK_SUBAGENT's true resolution in any given session also depends on an undocumented server-side staged-rollout state per the official doc's own wording ("may also be enabled... as part of a staged rollout"). The empiricalechocheck only proves the local env var is unset, not that fork mode is definitively off for that machine's sessions overall. This is a limit of the plugin's own detectable surface, not something the audit pass could close.discipline's other fan-out correctors (do-your-research-deep,recheck-against-upstream-deep) sharesweep-all's exact capability-dependency pattern on forks — plausible given the shared method doc, but unverified. Worth a follow-up pass if this plugin is revisited.