Purpose
Settle the topic-docs seam for the consuming repo, the marketplace-wide convention for where
plugin-generated documents land. The discovery plugin writes memory-tier artifacts (EXPLORE.md,
RESEARCH.md, one <slug>/ slice per topic) to <memory_dir>/<slug>/, never committed. The
consumer-side single source of truth is the tracked concern file .claude/topic-docs.yaml; its shape is
the convention's topic-docs.schema.json: every key optional, absent keys mean the documented defaults
(contract_dir: docs/topics, memory_dir: .work, contract_tier: branch, vault_backend: docs). This
plugin's binding, how the discovery skills consume what this skill persists, and the pointer to the
published convention that owns the schema, lives in
${CLAUDE_PLUGIN_ROOT}/reference/topic-docs.md.
Check-centric per the uniform contract: check inspects and reports, apply persists. Idempotent:
re-running reads the current state and offers an update rather than overwriting blind.
Action routing: no argument or check runs the check; apply runs the check first, then persists.
apply is non-interactive when complete <key>=<value> arguments are supplied
(memory_dir=, contract_dir=, contract_tier=, vault_backend=). Automation and headless use
pass the full set and are never prompted. With incomplete arguments, apply interviews one question
at a time, recommendation first.
check (read-only)
Report the effective concern and the guard result as a PASS/FAIL/INFO table. Do not write anything.
- Current state. If
.claude/topic-docs.yaml exists, report its effective values (absent keys =
defaults). If it does not exist, INFO: the plugin runs on the documented defaults; apply persists
an explicit concern only if the consumer wants different values.
- Inferred convention. Look for a working-docs convention declared in the repo's own
CLAUDE.md,
AGENTS.md, or .claude/rules, or an existing conforming layout (.work/ with a self-ignore,
docs/topics/). Surface it as INFO. Prose is an inference source; the concern file is the runtime
authority.
- Committed-tier guard. Only when the effective
contract_tier is branch (local mode has no
committed tier to guard): run git check-ignore -v on a representative file path inside the
contract root (e.g. <contract_dir>/probe/PLAN.md, a bare directory misses ** patterns). FAIL
if a consumer ignore rule matches, an uncommittable "committed" tier, and surface the exact rule
and source line. Resolving the rule is the consumer's edit.
- Deferred backend. If the effective
vault_backend is gitbook, INFO: it is reserved but not
enabled. Git remains the storage layer because GitBook offers no concurrency-safe,
lossless write path, so it is deferred and non-writable; durable writes target docs.
- Dispatch capability.
/discovery:explore and /discovery:research dispatch a subagent by
default, and that posture degrades rather than breaks on a session that cannot support all of it.
Report these as PASS/INFO rows. Never FAIL, and never a blocker:
- Harness version against the 2.1.219 floor (
claude --version). Below it, several behaviors
the dispatch design relies on are false rather than merely absent: background became the default
subagent execution mode in 2.1.198, and below 2.1.218 a context: fork skill always
blocked the invoking turn and the narrow background tool set did not apply to it. The dated
record for background as the default is
${CLAUDE_PLUGIN_ROOT}/reference/parent-contract.md,
"Harness facts the dispatch design rests on". Report the
observed version and, when it is under the floor, name which of those the session does not have.
The skills still run, inline is always available, so this is INFO, not FAIL.
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH. Report the value, present or absent, and say what
the running harness does with it rather than assuming. Read absent against the observed
version, in four windows: below 2.1.172 nesting does not exist and the variable buys
nothing; 2.1.172 to 2.1.216 absent means available at a fixed five; 2.1.217 to
2.1.218 absent means off, and setting the variable is the only way to turn nesting on;
2.1.219 and later absent means available at a configurable default of three, and the
variable lowers the ceiling ("1" disables nesting) as readily as it raises one.
Report absent as INFO in every window: nesting buys
throughput, not coverage, without it a dispatched agent fans out sequentially, slower for
the same result. The variable is still only one of two conditions: it cannot add a tool an
agent definition left out. The shipped discovery:explorer / discovery:researcher definitions
list Agent for exactly this reason; a third-party agent that does not is unaffected by setting
it. It is not a correctness prerequisite here, because the one control that needs a context
which has not seen the work is the outcome-gate verifier, and the parent dispatches that as a
sibling rather than the agent as a child. Note that env vars are read at session start, so a
value set now takes effect next session.
- Fork availability. Report it as a control, not a gate:
CLAUDE_CODE_FORK_SUBAGENT=1 turns fork
mode on in non-interactive mode and the SDK as well, and =0 turns it off in every kind of
session. When the variable is unset, the documented default is on in interactive sessions and
off in non-interactive mode and the SDK, and the interactive default needs 2.1.232 or
later. A default is not a runtime guarantee, so the only authoritative probe is still a live
inheritance check (see discipline:sweep-all's preflight). Report the env var when set; never
claim forks are unconditionally available on every build. The user-facing command is
/subtask as of 2.1.212. Verified 2026-09-06 against Claude Code 2.1.263, the subagents
documentation page and the environment-variables page as fetched that day; recheck when either
page states a different default or a release note names fork mode.
apply (idempotent)
Run check, then persist the chosen values. Re-running with the current values changes nothing and
reports "already configured".
- Resolve the values. With complete
<key>=<value> arguments, use them directly (non-interactive).
Otherwise interview one question at a time, recommendation first: present the inferred or documented
defaults (memory_dir: .work, contract_dir: docs/topics, contract_tier: branch,
vault_backend: docs, RECOMMENDED) and let the user accept or edit. contract_tier: local is the
solo/offline mode (contract kinds join the memory tier); a non-docs vault_backend names a
consumer-documented knowledge-vault backend. Offer every schema key and preserve every key an
existing file carries, a re-run never drops one; do not invent options beyond the schema. gitbook
is reserved but not enabled as a vault_backend value (check step 4 states why). When offering or
preserving it, report that it is deferred and non-writable, never configure or test a GitBook API,
MCP, or Git Sync writer, and offer to replace the key with docs only if the user chooses that
change.
- Guard, then persist. Re-run the committed-tier guard from
check for the chosen tier; if a
consumer ignore rule matches, STOP and surface the exact rule and source line rather than
configuring an uncommittable "committed" tier. Only then write the chosen values to the tracked
.claude/topic-docs.yaml (create or update; omit keys the user leaves at their defaults, but always
write at least one explicit key, a comment-only YAML document parses as null and fails the contract
schema's type: object). Verify-or-create the memory root's self-ignoring .gitignore (announce the
creation). Never edit the consumer's root .gitignore.
- Verify. Re-read
.claude/topic-docs.yaml and report its effective values, never claim
persisted on the write alone. Then run the tracked-file pair on it: git check-ignore -v
reports no match (a match is FAIL with the pattern) AND git ls-files --error-unmatch exits 0
(non-zero right after a fresh write means "written but untracked: commit it to share with the
team", never success).
Output
A tracked .claude/topic-docs.yaml carrying the chosen values, plus a one-line summary of what was
written and how to re-run this setup to reconfigure. Note in the summary that the concern file governs
where every discovery skill that writes a memory-tier artifact (/discovery:explore,
/discovery:research, /discovery:research-deep, /discovery:trace-intent) and the agents they
dispatch land handoff artifacts.
Gotchas
- A comment-only YAML document parses as
null and fails the contract schema's type: object.
When every chosen value is a default, still write at least one explicit key.
git check-ignore on a bare directory misses ** patterns. Probe a representative file path
inside the contract root, or an uncommittable "committed" tier passes the guard.
- Prose is an inference source, never the runtime authority. A working-docs convention described
in
CLAUDE.md is reported as INFO; only .claude/topic-docs.yaml governs where artifacts land.
apply re-runs must preserve keys this invocation does not set. Dropping an unmentioned key
silently reconfigures a consumer that had chosen it deliberately.
- Env vars are read at session start. A capability the check reports as missing stays missing for
the rest of this session even after it is set, the recommendation takes effect next session.
- Never edit the consumer's root
.gitignore. The memory root gets its own self-ignoring guard.
What this skill does NOT do
- Run an exploration, research, or intent-tracing pass. Those are the plugin's discovery skills
(
/discovery:explore, /discovery:research, /discovery:research-deep, /discovery:trace-intent).
- Write machine-local state. Configuration lives in the consumer's tracked concern file, never in the
plugin directory or the plugin data directory (
${CLAUDE_PLUGIN_DATA} is for caches and generated
state only).
- Write Claude Code user settings or
pluginConfigs.
1---2name: setup-93description: Verify or configure where discovery artifacts land in this repository: report the effective topic-docs concern, or persist it to the tracked .claude/topic-docs.yaml. Use when: 'set up discovery', 'configure the discovery plugin', 'is discovery configured', 'discovery setup', 'where do EXPLORE.md / RESEARCH.md land', or a discovery skill reports missing or thin config. Actions: check (read-only, default) | apply (persist the concern file). Re-runnable. Safe to invoke again.4---56## Purpose78Settle the **topic-docs** seam for the consuming repo, the marketplace-wide convention for where9plugin-generated documents land. The discovery plugin writes memory-tier artifacts (`EXPLORE.md`,10`RESEARCH.md`, one `<slug>/` slice per topic) to `<memory_dir>/<slug>/`, never committed. The11consumer-side single source of truth is the tracked concern file `.claude/topic-docs.yaml`; its shape is12the convention's `topic-docs.schema.json`: every key optional, absent keys mean the documented defaults13(`contract_dir: docs/topics`, `memory_dir: .work`, `contract_tier: branch`, `vault_backend: docs`). This14plugin's binding, how the discovery skills consume what this skill persists, and the pointer to the15published convention that owns the schema, lives in16[`${CLAUDE_PLUGIN_ROOT}/reference/topic-docs.md`](${CLAUDE_PLUGIN_ROOT}/reference/topic-docs.md).1718Check-centric per the uniform contract: `check` inspects and reports, `apply` persists. Idempotent:19re-running reads the current state and offers an update rather than overwriting blind.2021Action routing: no argument or `check` runs the check; `apply` runs the check first, then persists.22`apply` is non-interactive when complete `<key>=<value>` arguments are supplied23(`memory_dir=`, `contract_dir=`, `contract_tier=`, `vault_backend=`). Automation and headless use24pass the full set and are never prompted. With incomplete arguments, `apply` interviews one question25at a time, recommendation first.2627## `check` (read-only)2829Report the effective concern and the guard result as a PASS/FAIL/INFO table. Do not write anything.30311. **Current state.** If `.claude/topic-docs.yaml` exists, report its effective values (absent keys =32 defaults). If it does not exist, INFO: the plugin runs on the documented defaults; `apply` persists33 an explicit concern only if the consumer wants different values.342. **Inferred convention.** Look for a working-docs convention declared in the repo's own `CLAUDE.md`,35 `AGENTS.md`, or `.claude/rules`, or an existing conforming layout (`.work/` with a self-ignore,36 `docs/topics/`). Surface it as INFO. Prose is an inference source; the concern file is the runtime37 authority.383. **Committed-tier guard.** Only when the effective `contract_tier` is `branch` (local mode has no39 committed tier to guard): run `git check-ignore -v` on a representative file path inside the40 contract root (e.g. `<contract_dir>/probe/PLAN.md`, a bare directory misses `**` patterns). FAIL41 if a consumer ignore rule matches, an uncommittable "committed" tier, and surface the exact rule42 and source line. Resolving the rule is the consumer's edit.434. **Deferred backend.** If the effective `vault_backend` is `gitbook`, INFO: it is reserved but not44 enabled. Git remains the storage layer because GitBook offers no concurrency-safe,45 lossless write path, so it is deferred and non-writable; durable writes target `docs`.465. **Dispatch capability.** `/discovery:explore` and `/discovery:research` dispatch a subagent by47 default, and that posture degrades rather than breaks on a session that cannot support all of it.48 Report these as PASS/INFO rows. **Never FAIL, and never a blocker**:49 - **Harness version against the 2.1.219 floor** (`claude --version`). Below it, several behaviors50 the dispatch design relies on are false rather than merely absent: background became the default51 subagent execution mode in **2.1.198**, and below **2.1.218** a `context: fork` skill always52 blocked the invoking turn and the narrow background tool set did not apply to it. The dated53 record for background as the default is54 [`${CLAUDE_PLUGIN_ROOT}/reference/parent-contract.md`](${CLAUDE_PLUGIN_ROOT}/reference/parent-contract.md),55 "Harness facts the dispatch design rests on". Report the56 observed version and, when it is under the floor, name which of those the session does not have.57 The skills still run, inline is always available, so this is INFO, not FAIL.58 - **`CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH`**. Report the value, present or absent, and say what59 the running harness does with it rather than assuming. Read absent against the observed60 version, in four windows: below **2.1.172** nesting does not exist and the variable buys61 nothing; **2.1.172** to **2.1.216** absent means available at a fixed five; **2.1.217** to62 **2.1.218** absent means *off*, and setting the variable is the only way to turn nesting on;63 **2.1.219** and later absent means available at a configurable default of three, and the64 variable lowers the ceiling (`"1"` disables nesting) as readily as it raises one.65 Report absent as INFO in every window: nesting buys66 **throughput**, not coverage, without it a dispatched agent fans out sequentially, slower for67 the same result. The variable is still only one of **two** conditions: it cannot add a tool an68 agent definition left out. The shipped `discovery:explorer` / `discovery:researcher` definitions69 list `Agent` for exactly this reason; a third-party agent that does not is unaffected by setting70 it. It is not a correctness prerequisite here, because the one control that needs a context71 which has not seen the work is the outcome-gate verifier, and the parent dispatches that as a72 **sibling** rather than the agent as a child. Note that env vars are read at session start, so a73 value set now takes effect next session.74 - **Fork availability.** Report it as a control, not a gate: `CLAUDE_CODE_FORK_SUBAGENT=1` turns fork75 mode on in non-interactive mode and the SDK as well, and `=0` turns it off in every kind of76 session. When the variable is unset, the documented default is on in interactive sessions and77 off in non-interactive mode and the SDK, and the interactive default needs **2.1.232** or78 later. A default is not a runtime guarantee, so the only authoritative probe is still a live79 inheritance check (see `discipline:sweep-all`'s preflight). Report the env var when set; never80 claim forks are unconditionally available on every build. The user-facing command is81 `/subtask` as of **2.1.212**. Verified 2026-09-06 against Claude Code 2.1.263, the subagents82 documentation page and the environment-variables page as fetched that day; recheck when either83 page states a different default or a release note names fork mode.8485## `apply` (idempotent)8687Run `check`, then persist the chosen values. Re-running with the current values changes nothing and88reports "already configured".89901. **Resolve the values.** With complete `<key>=<value>` arguments, use them directly (non-interactive).91 Otherwise interview one question at a time, recommendation first: present the inferred or documented92 defaults (`memory_dir: .work`, `contract_dir: docs/topics`, `contract_tier: branch`,93 `vault_backend: docs`, RECOMMENDED) and let the user accept or edit. `contract_tier: local` is the94 solo/offline mode (contract kinds join the memory tier); a non-`docs` `vault_backend` names a95 consumer-documented knowledge-vault backend. Offer every schema key and preserve every key an96 existing file carries, a re-run never drops one; do not invent options beyond the schema. `gitbook`97 is reserved but not enabled as a `vault_backend` value (check step 4 states why). When offering or98 preserving it, report that it is deferred and non-writable, never configure or test a GitBook API,99 MCP, or Git Sync writer, and offer to replace the key with `docs` only if the user chooses that100 change.1012. **Guard, then persist.** Re-run the committed-tier guard from `check` for the chosen tier; if a102 consumer ignore rule matches, STOP and surface the exact rule and source line rather than103 configuring an uncommittable "committed" tier. Only then write the chosen values to the tracked104 `.claude/topic-docs.yaml` (create or update; omit keys the user leaves at their defaults, but always105 write at least one explicit key, a comment-only YAML document parses as null and fails the contract106 schema's `type: object`). Verify-or-create the memory root's self-ignoring `.gitignore` (announce the107 creation). **Never edit the consumer's root `.gitignore`.**1083. **Verify.** Re-read `.claude/topic-docs.yaml` and report its effective values, never claim109 persisted on the write alone. Then run the tracked-file pair on it: `git check-ignore -v`110 reports no match (a match is FAIL with the pattern) AND `git ls-files --error-unmatch` exits 0111 (non-zero right after a fresh write means "written but untracked: commit it to share with the112 team", never success).113114## Output115116A tracked `.claude/topic-docs.yaml` carrying the chosen values, plus a one-line summary of what was117written and how to re-run this setup to reconfigure. Note in the summary that the concern file governs118where every discovery skill that writes a memory-tier artifact (`/discovery:explore`,119`/discovery:research`, `/discovery:research-deep`, `/discovery:trace-intent`) and the agents they120dispatch land handoff artifacts.121122## Gotchas123124- **A comment-only YAML document parses as `null`** and fails the contract schema's `type: object`.125 When every chosen value is a default, still write at least one explicit key.126- **`git check-ignore` on a bare directory misses `**` patterns.** Probe a representative *file* path127 inside the contract root, or an uncommittable "committed" tier passes the guard.128- **Prose is an inference source, never the runtime authority.** A working-docs convention described129 in `CLAUDE.md` is reported as INFO; only `.claude/topic-docs.yaml` governs where artifacts land.130- **`apply` re-runs must preserve keys this invocation does not set.** Dropping an unmentioned key131 silently reconfigures a consumer that had chosen it deliberately.132- **Env vars are read at session start.** A capability the check reports as missing stays missing for133 the rest of this session even after it is set, the recommendation takes effect next session.134- **Never edit the consumer's root `.gitignore`.** The memory root gets its own self-ignoring guard.135136## What this skill does NOT do137138- Run an exploration, research, or intent-tracing pass. Those are the plugin's discovery skills139 (`/discovery:explore`, `/discovery:research`, `/discovery:research-deep`, `/discovery:trace-intent`).140- Write machine-local state. Configuration lives in the consumer's tracked concern file, never in the141 plugin directory or the plugin data directory (`${CLAUDE_PLUGIN_DATA}` is for caches and generated142 state only).143- Write Claude Code user settings or `pluginConfigs`.