Imported from duc01226/easy-claude (
.agents/skills/docs-update/SKILL.md). Install upstream withnpx skills add duc01226/easy-claude --skill docs-update. Copyright stays with the author.
Codex compatibility note:
- Invoke repository skills with
$skill-namein Codex; this mirrored copy rewrites legacy Claude/skill-namereferences.- Task tracker mandate: BEFORE executing any workflow or skill step, create/update task tracking for all steps and keep it synchronized as progress changes.
- User-question prompts mean to ask the user directly in Codex.
- Ignore Claude-specific mode-switch instructions when they appear.
- Strict execution contract: when a user explicitly invokes a skill, execute that skill protocol as written.
- Subagent authorization: when a skill is user-invoked or AI-detected and its protocol requires subagents, that skill activation authorizes use of the required
spawn_agentsubagent(s) for that task.- Do not skip, reorder, or merge protocol steps unless the user explicitly approves the deviation first.
- For workflow skills, execute each listed child-skill step explicitly and report step-by-step evidence.
- If a required step/tool cannot run in this environment, stop and ask the user before adapting.
Codex Project-Reference Loading (No Hooks)
Codex uses static project-reference loading instead of runtime-injected project docs. When coding, planning, debugging, testing, or reviewing, open project docs explicitly using this routing.
Always read:
docs/project-config.json(project-specific paths, commands, modules, and workflow/test settings)docs/project-reference/docs-index-reference.md(routes to the fulldocs/project-reference/*catalog)docs/project-reference/lessons.md(always-on guardrails and anti-patterns)
Missing/stale context route: If docs/project-config.json, the docs index, lessons.md, CLAUDE.md, AGENTS.md, or any task-required reference doc is missing or stale, auto-run $project-init or the narrow setup route ($project-config, $docs-init, $scan-all, $scan --target=<key>, $claude-md-init) before ordinary project-specific work. If Codex mirrors or AGENTS.md are missing/stale, ask the user to run $sync-codex; do not auto-run it.
Situation-based docs:
- Project structure/architecture/tech-stack/deployment/setup (any layer — backend, frontend, or infra):
project-structure-reference.md - Backend/CQRS/API/domain/entity changes:
backend-patterns-reference.md,domain-entities-reference.md - Frontend/UI/styling/design-system:
frontend-patterns-reference.md,scss-styling-guide.md,design-system/README.md - Spec authoring,
docs/specs/pathing, or TC format:feature-spec-reference.md,spec-system-reference.md,spec-principles.md - Behavior/public-contract changes or spec-test-code sync:
workflow-spec-test-code-cycle-reference.mdplus the spec docs above - Derived spec indexes/ERDs/reimplementation guides:
spec-system-reference.mdand source Feature Specs underdocs/specs/ - Integration test implementation/review:
integration-test-reference.md - E2E test implementation/review:
e2e-test-reference.md - Code review/audit work:
code-review-rules.mdplus domain docs above based on changed files
Do not read all docs blindly. Start from docs-index-reference.md, then open only relevant files for the task.
[BLOCKING] Execute skill steps in declared order. NEVER skip, reorder, or merge steps without explicit user approval. [BLOCKING] Before each step or sub-skill call, update task tracking: set
in_progresswhen step starts, setcompletedwhen step ends. [BLOCKING] Every completed/skipped step MUST include brief evidence or explicit skip reason. [BLOCKING] If Task tools are unavailable, create and maintain an equivalent step-by-step plan tracker with the same status transitions.
Quick Summary
Goal: Keep docs synchronized after every code/spec/test change: triage impact, route each doc type to its owner, and align project-reference/config docs, Feature Specs, §8 TCs, test-code links, and derived indexes with shipped behavior — zero silent drift.
Summary:
- This skill is a ROUTER, not an author — start with Phase 0 triage (git diff → categorize → dedup modules → check existing docs) and delegate each doc type to its owner (
$spec,$spec [mode=tests],$spec [mode=sync],$spec-index,$tech-specfor derived technical views); NEVER write §8,docs/specs/, or derived technical spec content directly. — why: dual authorship diverges spec from index/view. - Main steps (each impact-gated; skipped phase → mark
completedwith reason): Phase 0 triage (git diff → categorize → dedup modules → record existing-doc state) → Phase 1 project context sync (impact-map → PARALLEL verify of the impacteddocs/project-reference/**docs +docs/project-config.jsonsections +README.md) → Phase 2$spec(§1–§7 Feature Spec; doc-first BLOCK when feature behavior changed but no Spec exists) → Phase 2.5$spec-index(derived bucket INDEX/ERD refresh, optional) → Phase 2.6$tech-spec(derived technical view refresh/audit, optional when technical tree is affected) → Phase 3$spec [mode=tests](§8 TCs) → Phase 4$spec [mode=sync](§8 ↔ test code) → Phase 5 summary report → final review (#8 runs the Step 2.4 code↔spec sync-verify). - Create ALL 8 tasks via task tracking before touching any file; run the fixed phase order
0 → 1 → 2 → 2.5/2.6 → 3 → 4 → 5 → final review— fast-exit is a decision, never a silent omission. - The final pass (Step 2.4) is the workflow's last gate: per touched module verify shipped code against §3 ACs, §4 BRs, §8 TCs — a removed/weakened [HARD] BR is a code-vs-spec contradiction that BLOCKS completion.
- Output is tech-agnostic prose (no framework/product names outside evidence fields) and traceability-first (update
FR-/BR-/OP-/TC-logical IDs before prose); ALWAYS write the Phase 5 summary report as the audit trail.
Workflow:
- MUST ATTENTION run Phase 0 triage → Phase 1 impact-scoped context sync → Phase 2
$spec→ Phase 2.5$spec-index(if needed) → Phase 2.6$tech-spec(if needed) → Phase 3$spec [mode=tests]→ Phase 4$spec [mode=sync]→ Phase 5 report → final Step 2.4 code↔spec sync-verify; track each task before/after and record every skip.
Orchestration Model:
git diff → Triage → Phase 1: Project Context Sync (PARALLEL, impact-scoped)
│ ├─ impacted docs/project-reference/** — verify → patch → (escalate to $scan --target=X)
│ ├─ impacted docs/project-config.json sections — verify → merge → validate
│ └─ README.md / project docs (docs-manager)
→ Phase 2: $spec (business feature docs)
→ Phase 2.5: $spec-index (derived index/ERD refresh) [optional]
→ Phase 2.6: $tech-spec (derived technical view refresh/audit) [optional]
→ Phase 3: $spec [mode=tests] (§8 test specifications)
→ Phase 4: $spec [mode=sync] (§8 ↔ test code sync)
→ Phase 5: Summary Report
Key Rules:
- Router only — NEVER duplicate sub-skill logic or write Section 8 /
docs/specs/content - [BLOCKING] Freshness is impact-scoped, never assumed. Phase 1 verifies only the
docs/project-reference/**docs anddocs/project-config.jsonsections the diff can actually rot (routed bynode .claude/scripts/doc-impact-map.cjs), and reports a per-doc verdictFRESH | PATCHED | RESCAN REQUIRED | UNVERIFIED. A doc nobody checked is UNVERIFIED — NEVER FRESH. — why: these docs are injected into every downstream AI context, so a silent stale line teaches every later agent a codebase that no longer exists. - [BLOCKING] An impact-scoped verify NEVER writes
<!-- Last scanned: -->. Only a full$scan --target=Xmay move that stamp; the narrow pass writes<!-- Last verified: ... -->instead — and only in a doc that already carries aLast scannedstamp (Step 1.6). — why:Last scanneddrives the 60-day full-rescan gate (.claude/hooks/lib/session-init-helpers.cjs:769); resetting it from a partial check would buy speed by disabling the very net that catches whole-doc rot. - [BLOCKING] A
PATCHEDdocs/project-reference/**doc MUST run$prompt-enhance <doc>before its verdict is final (Step 1.3) — keeps the doc as concise as possible while staying valuable enough for AI; skip only for a stamp/count-only edit. - Phase 1/docs-manager MUST NOT own any
docs/specs/**, test-spec, spec-index/ERD, or derived technical-view path. - Every excluded artifact is explicitly reserved to its child skill (
$spec,$spec-index, or$tech-spec) so one canonical writer owns it. - Exclude
docs/specs/**and generated technical views from every docs-manager brief and write set. - Each phase checks whether needed before invoking — skip phases with no impact
- Step-to-skill order is fixed — run phases sequentially, never out of order
- ALWAYS report what was checked, even if nothing needed updating
- Pass triage context (changed files, detected modules, impacted sections) to each sub-skill via
$ARGUMENTS - MUST ATTENTION dedup module list — backend + frontend changes for same module = ONE entry
- MUST ATTENTION track step state live:
in_progress-> execute ->completed(orcompletedwith skip reason) - For
.claudeskills/hooks/workflows/sync tooling changes, flag generated mirror sync status (npm run codex:synccompleted or explicit N/A).docs-updateroutes and reports this check; it does not edit generated mirrors directly. - [BLOCKING] Tech-agnostic output: when updating spec/specs/README/INDEX, do NOT introduce framework/product/language/design-pattern names into prose or headings — preserve the evidence-field exception (
**Evidence**,CoveredBy, legacyIntegrationTest,[Source:], frontmatter, Mermaid). Authority:docs/project-reference/spec-principles.md§3. - [BLOCKING] M3 Traceability Update: See
.claude/skills/shared/sdd-artifact-contract.md→ "AI-SDD Mandates (M1-M7)" for BLOCKING criteria. When syncing docs after code changes, update the logical-ID mappings (FR-/BR-/OP-/TC-) FIRST, then the prose. The[Source: namespace/service/id]abstract-anchor evidence is re-resolved ONLY if the logical artifact was renamed/split — a file move or stack change does NOT change the anchor (physical coords live only in the provenance sidecar) — and the logical-ID spine stays stable across the change — never drop or renumber a logical ID just because the code moved. Keep all synced prose M1/M2-clean.
Be skeptical. Apply critical thinking, sequential thinking. Every claim needs traced proof, confidence >80%.
Mandatory Task Creation (ZERO TOLERANCE)
[BLOCKING] Create ALL 8 tasks via task tracking BEFORE touching any file. NEVER consolidate, rename, omit. Conditional tasks skipped: mark
completedimmediately with reason — NEVER silently omit.
| # | Task Subject | Conditional? |
|---|---|---|
| 1 | [docs-update] Phase 0 — Triage: collect git diff, categorize files, detect modules, check existing docs |
No — always first |
| 2 | [docs-update] Phase 1 — Project context sync: impact-map → PARALLEL verify of impacted docs/project-reference/** + docs/project-config.json sections + README/project docs |
No — always, unless Step 0.3 declared a TRUE fast exit (empty impact map). Runs even when Phases 2-4 are all skipped |
| 3 | [docs-update] Phase 2 — Invoke $spec: update business feature docs |
Yes — service/frontend files changed AND module has existing feature docs |
| 4 | [docs-update] Phase 2.5/2.6 — Refresh derived views via $spec-index and/or $tech-spec |
Yes — Feature Spec changed and bucket maintains INDEX/ERD, OR technical tree is affected |
| 5 | [docs-update] Phase 3 — Invoke $spec [mode=tests]: update/add §8 business test specifications |
Yes — business-visible functionality added OR existing business-visible behavior changed |
| 6 | [docs-update] Phase 4 — Invoke $spec [mode=sync]: sync §8 ↔ test code |
Yes — Phase 3 changed §8 TCs |
| 7 | [docs-update] Phase 5 — Write summary report to plans/reports/docs-update-{YYMMDD}-{HHMM}.md |
No — always |
| 8 | [docs-update] Final review — verify all impacted docs updated, no phases skipped without justification, AND run the Step 2.4 code↔spec sync-verify (AC/BR/TC drift) for every touched module |
No — always |
Execution rules:
- Mark each task
in_progresswhen starting,completedwhen done — one active at a time - Multiple modules → add one subtask per module for Phase 2/3 invocations
- Multiple impacted reference docs → add one subtask per doc (or per source-of-truth cluster) under Task 2, so each doc's verdict is tracked individually
- NEVER batch-complete — each sub-skill invocation tracked individually
- Phase 0 TRUE fast-exit (impact map empty) → mark tasks 2-8
completedwith reason "Skipped — impact map empty" - Phase 0 PARTIAL exit (docs/config impacted but no business behavior — e.g. harness, CI, or manifest-only changes) → run Task 2, mark tasks 3-6
completedwith reason "Skipped — no business behavior changed", still run tasks 7-8 - NEVER execute a phase step until matching task status is
in_progress - After each phase/skill call, write one-line evidence in task update (
what ran,what changed,why skipped) - If task tracking/task updates unavailable, maintain equivalent 8-task plan tracker with same status transitions
Step-Skill Call Order (Do Not Reorder)
| Order | Task ID | Step / Phase | Skill Call | Tracking Rule |
|---|---|---|---|---|
| 1 | 1 | Phase 0: Triage | Inline triage logic in this skill | Set Task 1 in_progress before diff scan; set completed after module + impact map recorded |
| 2 | 2 | Phase 1: Project Context Sync | doc-impact-map.cjs + PARALLEL docs-manager sub-agents (one per impacted doc/cluster) + $scan --target=X or $project-config only on escalation |
Set Task 2 in_progress before the impact map; completed only after EVERY routed doc and config section carries a verdict + evidence |
| 3 | 3 | Phase 2: Business Feature Docs | $spec |
Set Task 3 in_progress before invocation; completed after output review |
| 4 | 4 | Phase 2.5/2.6: Derived View Refresh | $spec-index [mode=index] and/or `$tech-spec [mode=generate |
audit]` |
| 5 | 5 | Phase 3: §8 Test Specs | $spec [mode=tests] |
Set Task 5 in_progress before invocation; completed after TC review |
| 6 | 6 | Phase 4: §8 ↔ Test Code Sync | $spec [mode=sync] |
Set Task 6 in_progress before invocation; completed after sync validation |
| 7 | 7 | Phase 5: Summary Report | Inline report write | Set Task 7 in_progress before report write; completed after file path confirmed |
| 8 | 8 | Final Review | Inline verification gate | Set Task 8 in_progress before final audit; completed after all phases justified |
Enforcement: If a required step cannot run, STOP and ask user before adapting order. Never continue with untracked steps.
Phase 0: Triage — Detect Impacted Documentation
Step 0.1: Collect Changed Files
- Run
git diff --name-only HEAD(staged + unstaged changes) - No uncommitted changes →
git diff --name-only HEAD~1(last commit) - Still empty →
git diff --name-only origin/develop...HEAD(branch changes)
Step 0.2: Categorize Changes
| Changed File Pattern | Impact Category | Phases to Run |
|---|---|---|
{backend-source-paths}/** from docs/project-config.json |
spec + spec [mode=tests] + project-docs | 1 + 2 + 3 + 4 |
{frontend-apps-dir}/**, {frontend-libs-dir}/{domain-lib}/** |
spec + spec [mode=tests] + project-docs | 1 + 2 + 3 + 4 |
{legacy-frontend-dir}/**Client/** |
spec + spec [mode=tests] + project-docs | 1 + 2 + 3 + 4 |
{configured-framework-source-paths}/** |
project-docs only | 1 only |
docs/** (outside specRoots) |
project-docs only | 1 only |
.claude/**, .agents/**, .codex/**, CLAUDE.md, AGENTS.md |
harness inventory — skill/hook/agent/workflow counts, catalogs, module registry | 1 only |
Dependency manifests (package.json, *.csproj, pyproject.toml, lockfiles, …) |
project-docs — tech stack, versions, run commands | 1 only |
Infra/CI/env (docker-compose*, Dockerfile, .github/workflows/**, *.tf, appsettings*, .env*) |
project-docs — ports, deployment, env keys | 1 only |
{frontend-libs-dir}/{framework-core-lib}/**, {frontend-libs-dir}/{common-lib}/** |
project-docs only | 1 only |
This table classifies BUSINESS-doc impact (which of Phases 2-4 run). It is deliberately coarse. The precise
docs/project-reference/**+docs/project-config.jsonrouting is produced by the impact map in Step 1.1 — read it there, never guess it here.
Step 0.3: Fast Exit Check — decided by the impact map, never by path intuition
Run the impact map NOW (same command as Step 1.1) and read fastExit from its output:
node .claude/scripts/doc-impact-map.cjs --text
| Map result | Route |
|---|---|
fastExit: true — no impacted reference doc, no impacted config section, no unrouted file |
Report "No documentation impacted by current changes." → mark tasks 2-8 completed with reason "Skipped — impact map empty" → exit early |
| Impacted docs/config but NO business behavior changed (harness, CI, manifests, docs tree) | PARTIAL exit — run Phase 1 in full, mark Phases 2-4 completed with reason "Skipped — no business behavior changed", continue to Phase 5 |
| Any business/service/frontend code changed | Full sequence |
unrouted non-empty |
NOT a fast exit — classify each unrouted file by hand first (add it to the wave, or record why it carries no doc impact) |
[BLOCKING] A
.claude/**-only (or tooling-only) diff is NOT a full fast exit. Harness edits change the skill/hook/agent/workflow inventories thatCLAUDE.md,docs-index-reference.md, andproject-structure-reference.mdderive by globbing.claude/: the counts and catalogs go stale with zero feature impact, and NO other gate in this skill catches them — Phases 2-4 only look atdocs/specs/**. — why: the cheapest way to ship stale docs is to classify the change as "tooling" and skip the only phase that would have noticed.
Step 0.4: Auto-Detect Affected Modules
Extract unique module names from changed paths. MUST ATTENTION dedup: unique() before passing to any sub-skill — backend + frontend same module = ONE entry. Prevents duplicate $spec invocations.
| Changed File Path Pattern | Detected Module |
|---|---|
{backend-module-path}/{Module}/** |
{Module} |
{frontend-apps-dir}/{app-name}/** |
{Module} (map app to module) |
{frontend-libs-dir}/{domain-lib}/{configured-feature-path}/** |
{Module} (map feature to module) |
{legacy-frontend-dir}/{Module}Client/** |
{Module} |
Build project-specific mapping from docs/project-config.json and project reference docs, not from hard-coded skill paths:
node -e "const cfg=require('./docs/project-config.json'); console.log(JSON.stringify({sourcePaths: cfg.codebaseHealth?.sourcePaths, contextGroups: cfg.contextGroups?.map(g => ({name:g.name,pathRegexes:g.pathRegexes})), specRoot: 'docs/specs/'}, null, 2))"
node -e "process.stdout.write('docs/specs/')"
Step 0.5: Check Existing Docs for Each Module
For each detected module:
- Check the matching bucket directory exists under
docs/specs/ - Check that the bucket contains
README.*.mdFeature Specs, or use the project reference doc's feature-doc layout - Check the matching bucket directory under
docs/specs/exists using project reference docs - Record:
hasFeatureSpec(§1–§7 present),hasTestSpecs(§8 present),hasDerivedIndex(bucket INDEX.md present)
Step 0.6: Declare the Doc-Update Wave
Detection is SEQ and comes FIRST — every assignment below is derived from the impacted-doc set, so nothing dispatches until Steps 0.1–0.5 have produced it. Once that set exists, updating N unrelated docs is embarrassingly parallel: one docs-manager sub-agent per doc or per doc cluster, all spawned in ONE message.
- Declare before dispatch —
Parallel plan: wave 1 = [docs-manager: {doc A}, docs-manager: {cluster B}, …] · SEQ = [Phase 0 triage, the Phase 2 → 2.5/2.6 → 3 → 4 spec chain, Phase 5 report] (reason). - STRICT one-writer-per-file. Every impacted doc path appears in EXACTLY ONE agent's brief, stated as that agent's owned file set. A doc owned by nobody is a silent miss; a doc owned by two agents is a lost-update race where the later write wins and the earlier finding vanishes.
- [HAZARD] Two docs that embed the same canonical or derived data MUST go to the SAME agent — never split across the wave. Counts, catalogs, module maps, INDEX rows, ERD entities, and any table copied out of a source of truth have to be regenerated by ONE writer from ONE reading of that source. Split across two agents they diverge inside a single commit — and the divergence survives review because each doc is internally consistent and only the pair is wrong. Cluster by SOURCE OF TRUTH, not by directory.
- Barrier before the spec chain. Phase 2 → 2.5/2.6 → 3 → 4 stays a FIXED SEQ chain:
$specoutput feeds the derived index, and §8 TCs feed[mode=sync]. Parallelism lives INSIDE a phase across independent modules — never across these phases. - Per-module fan-out is PAR only when the modules are disjoint. Two detected modules that map to ONE Feature Spec share a write target and stay a single task — the same reason Step 0.4 dedups the module list.
- Every member returns a summary +
Full report:path; YOU merge them into the Phase 5 report only after ALL members return, a skipped member counting as returned.
Phase 1: Project Context Sync — Reference Docs + project-config.json (PARALLEL, impact-scoped)
Why this phase exists.
docs/project-reference/**anddocs/project-config.jsonare injected into EVERY downstream AI context and route every skill in the framework. When code moves and they do not, the harness keeps teaching a codebase that no longer exists — and nothing else in this skill catches it, because Phases 2-4 only look atdocs/specs/**.$scan-all+$project-configdo repair them, but they re-derive every doc from zero, which is why they run every 60 days instead of every change. This phase does the same job at diff scope: same no-stale guarantee, small enough to afford after every change.
When to run: ALWAYS, unless Step 0.3 declared a TRUE fast exit. Run it even when every one of Phases 2-4 is skipped.
Scope discipline: verify ONLY what the impact map routes; escalate to a full $scan --target=X when a surgical patch cannot make the doc true again. NEVER regenerate all docs, and NEVER hand-author a full reference doc here — scan owns authoring, this phase owns verification and surgical repair.
Step 1.1: Build the Doc-Impact Map (SEQ — everything below derives from it)
node .claude/scripts/doc-impact-map.cjs --json # machine-readable (drives the wave)
node .claude/scripts/doc-impact-map.cjs --text # human-readable (goes in the report)
node .claude/scripts/doc-impact-map.cjs --base=origin/main # branch-scope instead of working tree
The map routes each changed file to the docs and config sections it can rot, and returns per doc: doc, exists, lastScanned/ageDays, scanTarget (the full-rescan escalation), checks (which verifications apply), changedFiles/addedFiles/deletedFiles, and heuristicOnly. Routing is derived from docs/project-config.json (contextGroups, modules, testing, e2eTesting, styling, designSystem, specRoots) plus change-class rules — never from hardcoded project paths.
Handling the map's output — [BLOCKING] rules:
unroutedfiles are not proof of no impact — they are proof the router had no rule. Classify each by hand: add it to the wave, or record in the report why it carries no doc impact. NEVER let an unrouted file silently pass as fresh.- A
heuristicOnlydoc is a GUESS, not evidence. Verify it like any other, and downgrade to "not impacted" only with a stated reason. - Any doc whose
exists: falseis a MISSING doc, not a fresh one → route to$scan --target=<scanTarget>(or$docs-initwhen the whole set is absent). - If the script is unavailable (older checkout, non-Node host), derive the same map by hand from
docs/project-config.json— match changed paths againstcontextGroups[].pathRegexes→guideDoc/patternsDoc/stylingDoc/designSystemDoc,modules[].pathRegex→ project-structure +modules, test/e2e/styling paths → their docs, manifests → tech stack, infra/CI → ports & deployment,.claude/**→ inventory counts. Record that the map was manual.
Step 1.2: Declare the Verify Wave (PAR — one message, all members)
Parallel plan: wave 1 = [docs-manager: {doc A}, docs-manager: {cluster B}, docs-manager: project-config.json, …] · SEQ = [Step 1.1 impact map, the Phase 2 → 2.5/2.6 → 3 → 4 spec chain, Phase 5 report] (reason)
Wave-construction rules — the Step 0.6 hazards apply verbatim, plus:
- STRICT one-writer-per-file.
docs/project-config.jsonhas exactly ONE owning agent in the wave, always. Two agents merging JSON into the same file is a guaranteed lost update. - Cluster by SOURCE OF TRUTH, not by directory.
README.md+project-structure-reference.mdboth restate the module/directory map, andCLAUDE.md+docs-index-reference.md+project-structure-reference.mdall embed.claude/-derived counts — each such set goes to ONE agent so the numbers cannot diverge inside a single commit. - Every routed doc appears in exactly one brief. A doc owned by nobody is a silent miss.
- Every member returns its verdict table +
Full report:path; merge only after ALL members return.
Step 1.3: Per-Doc Verify Contract (what each wave member actually does)
Verify FIRST, patch NARROW. Run only the checks the map listed for that doc:
| Check | Question it answers | How to answer it | On failure |
|---|---|---|---|
claims |
Do the doc's cited paths/examples still exist? | node .claude/scripts/doc-impact-map.cjs claims <doc> (missing = dead, ambiguous = short-form that resolves by suffix), then grep each cited symbol at its cited file |
Repoint or delete a dead citation, repo-root an ambiguous one (a citation is evidence — never leave a dead one). The reference-doc-freshness test suite fails the build on any dead citation |
coverage |
Does every ADDED artifact of this doc's kind appear in it? | Diff the map's addedFiles against the doc's inventory/examples |
Add the missing row/example with file:line |
counts |
Do numeric claims match ground truth? | Re-derive by glob/grep (skills, hooks, agents, workflows, services, docs, tests) | Update the number — and the marker region if the count is generated |
conventions |
Did the diff introduce a pattern the doc does not describe, or violate one it does? | Read the diff against the doc's rules | New pattern → document it. Violation → report it, do NOT document it as a convention |
commands |
Do documented run/test commands still work? | Compare against manifests/scripts (package.json, test config, integrationTestVerify) |
Patch the command |
versions |
Do stated tech/framework versions match the manifests? | Read the manifest — never infer | Patch the version |
ports |
Do documented ports/endpoints match infra config? | Read compose/k8s/appsettings — never infer | Patch the port |
links / catalog |
Do cross-links and catalog rows resolve? | Existence-check each target | Fix or remove the row |
Verdict per doc (exactly one, evidence required):
| Verdict | Meaning | Required evidence |
|---|---|---|
FRESH |
Every applicable check ran and passed; no edit needed | Which checks ran + what was compared |
PATCHED |
Surgical edit applied, then $prompt-enhance <doc> run to keep it concise |
Sections touched + file:line evidence for each new claim + prompt-enhance run confirmation (or stated reason skipped) |
RESCAN REQUIRED |
Beyond surgical repair — a new subsystem/pattern family appeared, most of the impacted section's examples are dead, or the doc's structure no longer fits the code | The scanTarget to run ($scan --target=X), and whether it ran in this session or is queued |
UNVERIFIED |
Could not be checked (missing tooling, blocked read, budget) | Why, and what must run next |
[BLOCKING] Never fabricate freshness. "Looks fine", "probably unchanged", and "the diff was small" are not check results. A doc that was not verified is
UNVERIFIED, neverFRESH— a false FRESH is worse than no check, because it retires the suspicion that would have caught the drift later.
[BLOCKING] Every
PATCHEDdocs/project-reference/**doc MUST run$prompt-enhance <doc>(default--op=enhance) before the verdict is recorded. These docs are injected into every downstream AI context — a surgical edit that adds correct prose without re-compressing still leaves the doc bloated.$prompt-enhancekeeps content as concise as possible while staying valuable enough for AI (caveman compression + attention anchoring), closing the same gap on the narrow patch path that$scan --target=X's own mandatory final step (scan/SKILL.mdFinal Step) already closes on a full rescan — so aRESCAN REQUIREDdoc that escalates to$scangets it for free and needs no separate call here. Skip ONLY for a single stamp/date/count-only edit, and record the skip reason.
Step 1.4: project-config.json Drift Check (single writer, schema-validated)
Verify ONLY the sections the map flagged. For each:
- Re-derive from evidence — read the changed files, not the old config value.
- Surgical merge — add/update entries; NEVER rename, remove, or restructure a top-level section (the
$project-configSchema Protection Rules apply here unchanged). - Prove every touched
pathRegex/path still matches something real — a regex that matches zero files is stale config that silently disables every downstream router that depends on it, and no schema check catches it:
node -e "const c=require('./docs/project-config.json');const {execSync}=require('child_process');const files=execSync('git ls-files',{encoding:'utf8'}).split('\n').filter(Boolean).map(f=>'/'+f);for(const m of c.modules||[]){const re=new RegExp(m.pathRegex,'i');const n=files.filter(f=>re.test(f)).length;console.log((n?'OK ':'DEAD')+' modules.'+m.name+' -> '+n+' file(s)')}"
- Validate the schema after the merge:
node -e "const {validateConfig}=require('./.claude/hooks/lib/project-config-schema.cjs');console.log(JSON.stringify(validateConfig(require('./docs/project-config.json')),null,2))"
- Escalate, don't improvise — a NEW top-level section, a new module class, a new tech stack, or a failed validation means the change is a re-scan, not a patch → run
$project-config(and report that it is required if it cannot run in this session).
Step 1.5: README & Project Docs (docs-manager)
Pass the Phase 0 diff context to a docs-manager sub-agent (agent_type="docs-manager") for the prose project docs in the same wave:
README.md— update if project scope or setup changed (keep under 300 lines)docs/project-reference/project-structure-reference.md— update if service architecture or cross-service patterns changed (same agent as README: shared source of truth)
Standalone invocation (not a workflow step) may first delegate 2-4 read-only landscape threads to researcher; as a workflow step, use the Phase 0 diff context directly.
Exclusions unchanged: this agent NEVER owns docs/specs/**, test specs, spec-index/ERD, or derived technical views.
Step 1.6: Stamp Discipline (BLOCKING)
| What ran | Stamp to write |
|---|---|
Full $scan --target=X |
<!-- Last scanned: YYYY-MM-DD --> (owned by scan, top of doc) |
Impact-scoped verify/patch on a doc that carries a Last scanned stamp |
<!-- Last verified: YYYY-MM-DD (docs-update, impact-scoped) --> on the line immediately AFTER that stamp |
Impact-scoped verify/patch on a doc with no Last scanned stamp — CLAUDE.md, .claude/docs/**, and any other AI-facing instruction file |
Write NO stamp. Record the doc's verdict in the Step 1.7 output only. — why: those files read as live instruction, and .claude/agents/docs-manager.md:35 forbids provenance metadata in them; the no-meta-log rule wins over the stamp rule, it is not overridden by it. |
[BLOCKING] An impact-scoped pass MUST NOT touch
Last scanned. That stamp is the input to the 60-day full-rescan gate (getStaleReferenceDocs→refreshScanStaleFlag,.claude/hooks/lib/session-init-helpers.cjs:769-810). Moving it from a partial check would buy speed by switching off the net that catches whole-doc rot — the two mechanisms are complementary, not interchangeable.
After any doc in this run WAS fully rescanned, re-evaluate the gate:
node -e "require('./.claude/hooks/lib/session-init-helpers.cjs').refreshScanStaleFlag()"
Step 1.7: Phase 1 Output
Emit the freshness table into the Phase 5 report — one row per routed doc plus one per config section, each with verdict, checks run, and evidence. Docs with RESCAN REQUIRED or UNVERIFIED are carried into Recommendations so the next session inherits the debt explicitly instead of silently.
Phase 2: Business Feature Documentation — Invoke $spec
When to run: Triage detected modules with hasFeatureDocs = true AND service/frontend files changed.
When to skip: No service/frontend feature files changed. Report: "No business feature docs impacted."
Step 2.1: Determine Create vs Update
| Scenario | Action |
|---|---|
| Module has existing feature docs | Invoke $spec — auto-detect triggers update flow |
| Module has NO feature docs AND change adds/changes a feature (new endpoint, command/query, entity, business rule, user-facing behavior) | BLOCK — Report: "Module {Module} has NO Feature Spec but this change introduces feature behavior. Create the tech-free 8-section Feature Spec FIRST via $spec, then re-run docs-update." Do NOT skip. This is the doc-first gate. |
| Module has NO feature docs AND change is tooling/style/config-only (no behavioral impact) | Skip with reason "No feature behavior changed — no Feature Spec required." (matches Phase 0 fast-exit at :113-120). |
| User explicitly asked for full doc creation | Invoke $spec with explicit module name |
Step 2.2: Invoke $spec
$spec Update feature docs for modules: {detected modules}.
Changed files: {list from triage}.
Impacted sections based on change types: {section impact from triage}.
Mode: update (existing docs only, do not create from scratch).
What $spec handles (DO NOT duplicate here):
- 8-section tech-free structure enforcement
- Diff analysis → section impact mapping
- Codebase analysis (entities, commands, queries, controllers)
- Update impacted sections with evidence
- Bucket
INDEX.mdcatalog row update - 3-pass verification (evidence audit, domain model, cross-reference)
- Tech-free principles (no implementation details in §1–§7; evidence carriers in §8 +
[Source:]only)
Step 2.3: Review $spec Output
- Updated sections align with triage's section impact mapping
- No sections missed that triage flagged as impacted
- Gaps found → re-invoke
$specfor missed sections
Step 2.4: Code↔Spec Sync-Verify (final pass — runs because docs-update is last in every sequence)
Purpose: docs-update already runs LAST in feature/bugfix/big-feature, so this is the workflow's final gate. It is the order-time partner of the Phase 4 commit hook (this step guides; the hook enforces). Verify the SHIPPED code actually matches the mapped tech-free 8-section Feature Spec before the workflow completes.
For each module touched in this run, diff the changed code against its Feature Spec and check three sets:
| Spec set (Feature Spec section) | Sync check against changed code | On drift |
|---|---|---|
| §3 Acceptance Criteria (AC-{FC}-NN) | Every changed user-facing behavior maps to an AC; new behavior with no AC = missing AC. | Report drift; re-invoke $spec to add the AC. |
| §4 Business Rules (BR-{FC}-NNN, [HARD]/[SOFT]) | Each changed validation/invariant matches a BR; a [HARD] rule whose code path was removed/weakened = regression. | BLOCK — surface as a code-vs-spec contradiction for the author to resolve. |
§8 Test Specifications (TC-{FC}-NNN + CoveredBy:) |
Each new/changed business-visible behavior has a TC; each Tested TC's CoveredBy: {File}::{Method} or approved coverage carrier still resolves. Legacy IntegrationTest: is migration input only. |
Report; route to $spec [mode=sync]. |
Derived technical views (specRoots.technical.path) |
Technical-only coverage or component topology changes may require a regenerated/audited derived view. The view is generated from code/tests and is never hand-authored. | Report; route to `$tech-spec [mode=generate |
Output: a short sync-verify table (module · AC drift · BR drift/contradiction · TC drift) appended to the docs-update report. Clean = no drift across all three. A [HARD]-BR contradiction blocks workflow completion until resolved or explicitly accepted by the owner.
Scope: business code↔spec drift only. Technical contracts (API routes/DTOs, bus/job mechanics) are code-canonical and intentionally NOT re-verified against prose. No new sequence step and no
verify-syncmode is added — this responsibility lives inside docs-update's existing final pass.
Phase 2.5: Derived Index / ERD Refresh (OPTIONAL — spec-index)
[SINGLE-HOME] There is no separate "engineering spec bundle". The canonical artifact is the 8-section Feature Spec updated in Phase 2.
spec-indexis repurposed to regenerate only the DERIVED bucketINDEX.md/ cross-capability ERD from those Feature Specs — it never re-extracts an A-E tree. Run this phase only if the bucket maintains a derived index/ERD that the Phase 2 change made stale.
When to run: Phase 2 changed one or more Feature Specs AND the bucket maintains a derived INDEX.md / ERD aid that now lags.
When to skip:
- Only
docs/,.claude/, or config files changed - No Feature Spec under
docs/specs/{Bucket}/was touched - Phase 2 was skipped (no feature impact)
- The bucket maintains no derived index/ERD, OR
project-config.jsoncontains"spec_discovery_update": false specalready refreshedINDEX.mdin Phase 2 (no separate refresh needed)
Step 2.5.1: Resolve the Bucket
- Map the changed services to an App Bucket using the canonical table in
docs/project-reference/spec-system-reference.md→ App Bucket Mapping. - Confirm
docs/specs/{Bucket}/holds the updated Feature Spec(s).
Step 2.5.2: Invoke spec-index (Derived Index Mode)
$spec-index mode=index bucket={Bucket} artifacts=INDEX[,ERD]
Source: the canonical Feature Specs in docs/specs/{Bucket}/.
Output: regenerated DERIVED docs/specs/{Bucket}/INDEX.md (+ {Bucket}.erd.md if maintained), each carrying the DERIVED banner.
Step 2.5.3: Verify Refresh Complete
- Confirm
INDEX.mdrows match the current set of Feature Specs (no dangling links, no missing capabilities). - Confirm the DERIVED banner + regenerate date are present.
- Report:
"Derived index refreshed: {Bucket} — {N} capabilities catalogued".
Separation of concerns:
docs-updateorchestrates — passes the bucket scope to spec-index. NEVER hand-edits the derived index, and NEVER recreatesM##/A-E artifacts (retired).
Phase 2.6: Derived Technical View Refresh (OPTIONAL — tech-spec)
[SINGLE-HOME] The derived technical root comes from
docs/project-config.json→specRoots.technical.path.$tech-specowns that output;docs-updateroutes and verifies it, but never hand-edits a generated view.
When to run: The impact map or source anchors show that a code/test change affects the configured technical tree. Technical-only framework tooling changes may still need a generator freshness check.
When to skip: The change is docs/config-only, no technical source or annotation is affected, the
technical scan is not configured for this project, or the derived tree is demonstrably unaffected.
Record the evidence and skip reason in the Phase 5 report; an absent techSpecScan is not a reason to
invent a project-specific annotation pattern.
Step 2.6.1: Resolve the Technical Scope
- Resolve
specRoots.technical.pathand anytechSpecScansettings from project configuration. - The generator's CLI owns a full configured-root generation mode and a read-only
--checkmode. Do not route to unsupported--scopeor--allarguments. - If a technical source change affects the derived tree, invoke
$tech-specwith the component context and let that skill determine its mechanical output. Keep this router's write set empty.
Step 2.6.2: Invoke and Verify
npm run tech-spec:generate
Equivalent standalone invocation:
node .claude/skills/tech-spec/scripts/generate-tech-specs.mjs
For a read-only gate, use npm run tech-spec:check or the direct --check command. If the project
does not declare techSpecScan, the sync orchestrator records an explicit SKIP (not configured);
direct generator invocation remains fail-closed so a malformed declared contract cannot look fresh.
Verify the result through $tech-spec: every emitted view has the DERIVED banner, the configured
technical root contains no retired artifacts, anchors are traceable, and a second unchanged check is
byte-stable. Report output paths, files written/removed/unchanged, and the freshness verdict.
Phase 3: Test Specifications — Invoke $spec [mode=tests]
When to run: New business-visible functionality added OR existing business-visible behavior changed. Technical-only changes with no changed user/QC-visible outcome produce no business Section 8 edits; route any technical coverage need to tests and $tech-spec for the derived technical view.
When to skip: Changes purely cosmetic (styling, comments, docs-only) with no behavioral impact.
Step 3.1: Determine TC Mode
| Context | TC Mode |
|---|---|
| New feature code, no existing TCs | implement-first |
| PBI/story exists, code not yet written | TDD-first |
| Existing TCs + code changes / bugfix | update |
| User says "sync test specs" | sync |
| Tests exist with annotations, no docs | from-integration-tests |
PBI/idea artifact route: when changed artifacts match configured PBI/idea artifact roots from docs/project-config.json or project reference docs, docs-update performs detection/delegation only. It may identify affected module, feature doc, and TC scope, then route to $spec, $spec [mode=tests], or $spec [mode=sync]. It must not generate TC content directly from PBI/idea artifacts or edit Section 8 itself. If artifact roots are not configured, ask the user to initialize project config/reference docs before assuming a path.
Step 3.2: Invoke $spec [mode=tests]
$spec [mode=tests] Mode: {detected mode}.
Modules: {detected modules}.
Changed files: {list from triage}.
Business-visible functionality detected: {new or changed user/QC-visible outcomes from diff analysis}.
What $spec [mode=tests] handles (DO NOT duplicate here):
- 5 modes: TDD-first, implement-first, update, sync, from-integration-tests
- TC-{FEATURE}-{NNN} format with decade-based numbering
- Interactive TC review (ask the user directly)
- Cross-cutting categories: authorization, seed data, performance, data migration
- Phase-mapped coverage (plan phases → TCs)
- Graph context analysis for cross-service impact
- Evidence verification per TC
- Write to feature doc Section 8 (canonical business TC registry)
Step 3.3: Review $spec [mode=tests] Output
- New TCs cover all new business-visible functionality from triage
- TC IDs don't collide with existing ones
- Evidence fields populated (not template placeholders)
Phase 4: Test Spec ↔ Test Code Sync — Invoke $spec [mode=sync]
When to run: Phase 3 produced new/updated TCs in §8 of a Feature Spec.
When to skip: No §8 test-spec changes.
Step 4.1: Invoke $spec [mode=sync]
$spec [mode=sync] Sync test specs for capabilities: {detected features}.
Direction: forward (Feature Spec §8 Test Specifications → executing test code).
Updated TCs from Phase 3: {list of new/changed TC IDs}.
What $spec [mode=sync] handles (DO NOT duplicate here):
- Forward/reverse sync: §8 Test Specifications ↔ executing test code
- 2-way comparison: Feature Spec §8 vs test code (code is the technical source of truth)
- Test cross-reference (configured test-spec annotation key
TestSpecacross all executing test tiers and the per-TCCoveredBy:field; legacyIntegrationTest:is migration input only)
The retired QA dashboards (
docs/specs/README.md,docs/specs/PRIORITY-INDEX.md) and the hand-maintainedA-E/M##engineering tree no longer exist — §8 is the canonical business TC registry. Derived aids are the bucketINDEX.mdcount (Phase 2.5) and the regenerable technical view underspecRoots.technical.path(Phase 2.6).
Step 4.2: Review Sync Results
- All new TCs from Phase 3 are reflected in test code (or flagged Untested with rationale).
- No orphaned TCs (referenced by test code's
TestSpecannotation but absent from §8).
Section Ownership Reference
Which skill owns which doc sections — docs-update delegates only, NEVER writes directly:
| Section | Owner Skill | docs-update Role |
|---|---|---|
docs/project-reference/** (authoring) |
$scan --target=X |
Verify impact-scoped + surgical patch; escalate to the scan when a patch cannot make it true — NEVER hand-author a full reference doc |
docs/project-config.json (structure) |
$project-config |
Verify + surgical merge of impacted sections with schema validation; escalate whole-section/new-tech changes |
| §1–§7 (Feature Spec, tech-free) | $spec |
Pass triage context; review output |
| §8 (Test Specifications) | $spec [mode=tests] |
Pass TC mode + changed files; NEVER write TCs here |
| §8 ↔ test code sync | $spec [mode=sync] |
Pass capability list + direction; NEVER edit directly |
Derived bucket INDEX.md / ERD |
$spec-index (optional) |
Pass bucket scope; NEVER hand-edit the derived index |
| Derived technical spec view | $tech-spec (optional) |
Pass service/component scope; NEVER hand-edit the derived technical file |
Phase 5: Summary Report
ALWAYS write full report to plans/reports/docs-update-{YYMMDD}-{HHMM}.md:
### Documentation Update Summary
**Triage:** {N} files changed → {categories detected}
**Modules detected:** {module list}
**Generated mirror sync:** {Completed / N/A / Required before close}
**Phase 1 — Project Context Sync (impact-scoped freshness):**
Impact map: {N} changed files → {D} docs, {S} config sections, {U} unrouted ({map source: working tree / last commit / branch})
| Reference doc | Verdict | Checks run | Evidence / action |
| ------------- | ------- | ---------- | ----------------- |
| {doc} | FRESH / PATCHED / RESCAN REQUIRED / UNVERIFIED | {claims, coverage, counts, …} | {what was compared; sections patched; scan target queued} |
| project-config.json section | Verdict | Evidence / action |
| --------------------------- | ------- | ----------------- |
| {section} | FRESH / PATCHED / RESCAN REQUIRED / UNVERIFIED | {re-derived from …; schema validation result; dead pathRegex found} |
- Unrouted files classified: {file → why no doc impact}
- README / project docs: {Updated/Skipped}: {reason}
- Stamps: {docs given `Last verified`} · {docs fully rescanned and given `Last scanned`} · staleness flag refreshed: {yes/no}
**Phase 2 — Feature Specs ($spec):**
- {Capability X}: {Updated §1–§7 / No existing Feature Spec / Not impacted}
- {Capability Y}: {Updated §4 Business Rules, §5 Domain Model / Skipped: no Feature Spec}
**Phase 2.5 — Derived Index Refresh ($spec-index, optional):**
- {Refreshed {Bucket} INDEX.md ({N} capabilities) / Skipped: no derived index maintained / Skipped: spec_discovery_update=false}
**Phase 3 — Test Specifications §8 ($spec [mode=tests]):**
- Mode: {mode used}
- New TCs: {list of TC IDs added}
- Updated TCs: {list of TC IDs modified}
- Skipped: {reason if skipped}
**Phase 4 — Test Spec ↔ Test Code Sync ($spec [mode=sync]):**
- {Synced N TCs to test code / Skipped: no §8 changes}
- Discrepancies: {§8-vs-test-code comparison issues}
**Recommendations:**
- {New docs that should be created}
- {Stale docs flagged but not auto-fixed}
- {TCs flagged as Untested}
Decision Matrix: When to Use docs-update vs Direct Skill
| Scenario | Use docs-update? | Use skill directly? |
|---|---|---|
| Post-implementation doc sync (any code change) | Yes — full orchestration | — |
Keep project-reference docs + project-config.json fresh after a change |
Yes — Phase 1 impact-scoped verify | $scan --target=X or $project-config when a single doc/section needs a full rebuild |
| Refresh every reference doc regardless of the diff | No | $scan-all (+ $project-config) |
| Create new feature docs from scratch | No | $spec |
| Generate TCs for specific PBI (TDD-first) | No | $spec [mode=tests] |
| Route PBI/idea artifact changes | Yes — detection/delegation | $spec + $spec [mode=tests] owner skills |
| Sync dashboard only (no code changes) | No | $spec [mode=sync] |
Workflow step after $plan-execute or $fix |
Yes — full orchestration | — |
| User asks "update docs after my changes" | Yes — full orchestration | — |
Additional Requests
Pass caller context via $ARGUMENTS to skip redundant triage or narrow scope:
| Key | Example | Effect |
|---|---|---|
modules |
modules=ModuleA,ModuleB |
Skip auto-detect; use provided list |
changed_files |
changed_files=<configured-source-path>/ModuleA/... |
Skip git diff; use provided file list |
phases |
phases=2,3 |
Run only specified phases |
mode |
mode=update |
Override spec mode detection |
tc_mode |
tc_mode=implement-first |
Override spec [mode=tests] mode detection |
skip_phases |
skip_phases=1,2.5 |
Skip specific phases |
freshness |
freshness=impact (default) / full / off |
impact = Phase 1 as specified; full = escalate every routed doc to its $scan --target=X (and $project-config); off = skip Phase 1 — allowed ONLY on explicit user instruction, and the report MUST record every routed doc as UNVERIFIED |
base |
base=origin/main |
Scope the impact map to a branch diff instead of the working tree |
<additional_requests> $ARGUMENTS </additional_requests>
Escalation: When docs-update Is Not Enough
| Situation | What to do instead |
|---|---|
| Feature Spec missing but capability exists | Run $spec [mode=init] to author the 8-section Feature Spec, then docs-update |
Derived bucket INDEX.md/ERD missing |
Run $spec-index mode=index bucket={Bucket} to (re)generate it |
| Integration tests don't match TCs | Run $integration-test-review to diagnose, then $integration-test to fix |
| Bug caused by wrong spec | Run $spec [mode=update] (fix the canonical spec) BEFORE docs-update; optionally $spec-index mode=index to re-derive the bucket index |
| One reference doc is wrong beyond a surgical patch | Run its $scan --target=<key> (the map's scanTarget), then re-run Phase 1 to confirm |
| Most reference docs are stale, or the 60-day gate fired | Run $scan-all — impact scope cannot repair rot that predates the diff |
| A reference doc does not exist at all | Run $docs-init (whole set missing) or $scan --target=<key> (single doc) |
project-config.json needs a new section, module class, or tech stack, or fails schema validation |
Run $project-config — that is a re-scan, not a merge |
| Suspect long-standing rot that no current diff touches | Run $scan-codebase-health (count-drift, dead config references, broken cross-links) |
[BLOCKING] Create ALL 8 tasks via task tracking BEFORE any action — see Mandatory Task Creation table. NEVER skip, batch-complete, or mark done without invoking sub-skill. [BLOCKING] Follow fixed step-skill order:
Phase 0 -> Phase 1 -> Phase 2 -> Phase 2.5/2.6 -> Phase 3 -> Phase 4 -> Phase 5 -> Final review. NEVER reorder, merge, or skip without explicit user approval. [BLOCKING] Per-step task lock: BEFORE each step, mark taskin_progress; AFTER each step, mark taskcompletedwith evidence or explicit skip reason. [BLOCKING] If Task tool unavailable, create equivalent 8-step plan tracker and keep statuses synced for every step.
Critical Purpose: Single orchestrator for ALL documentation sync after code changes. Triages impact, delegates to specialized skills.
Evidence Gate: [BLOCKING] — every claim requires
file:lineproof or traced evidence, confidence >80% to act.
Critical Thinking Mindset — Apply critical thinking, sequential thinking. Every claim needs traced proof, confidence >80% to act. Anti-hallucination: Never present guess as fact — cite sources for every claim, admit uncertainty freely, self-check output for errors, cross-reference independently, stay skeptical of own confidence — certainty without evidence root of all hallucination.
Sub-Agent Return Contract — When this skill spawns a sub-agent, the sub-agent MUST return ONLY this structure. Main agent reads only this summary — NEVER requests full sub-agent out
Truncated - read the full file at https://github.com/duc01226/easy-claude/blob/e46c5f1a56e43f9a04e7704ede06824623450bf6/.agents/skills/docs-update/SKILL.md.