Files
claude/skills/tour/SKILL.md
T
bastien d82c06f572 refactor(doctrine): C2 coherence — 30 doctrine/skill tensions resolved, doctrine wins (BDR-099)
One ask policy; mandated executors exempt from the delegation rule; skill plan satisfies the planning rule; journal line exempt from the approval gate; chore = maintenance without new behaviour; small fix on develop = bugfix; BDR-068 written as the one auto-finish exception; deploy routes to /deploy. Skills and agents follow: hotfix types by base + skips the design gate on trivial; capitalize/close create missing registries; commit-change asks the branch type; doc/seo/web-validate/refactor branch through the aiguillage; tour reports BREAKING fixes as needs-decision and runs doc-syncer two-mode; client-handover applies audit bundles from its main loop behind one gate; init-project/onboard use the 200-file graphify signal and bootstrap memory; release-candidate gates the tag push only; push wording aligned with the BDR-095 hooks; stale pointers fixed (§ Language, .gsd/ROADMAP.md, handover script path, design-gate lists).
2026-09-24 20:25:40 +02:00

17 KiB

name, description, argument-hint, allowed-tools
name description argument-hint allowed-tools
tour Use when the user wants ONE grouped pass over a whole project (or a list of projects) covering all hygiene axes together: code cleanup + security (semgrep/cso) + TODO-vs-reality check + doc sync, auto-fixing and re-auditing until a clean pass — even without naming the axes. NOT one axis alone (/code-clean, /cso, /audit-delta, /reconcile, /doc), one bug (/hotfix, /bugfix), dashboard (/health), branch diff (/review). Triggers: "tour", "tir groupé", "grand ménage", "fais un tour sur les projets", "sweep", "full pass", "vérifie et corrige tout". [project paths… — blank = current repo] [--report-only]
Read
Edit
Write
Bash
Grep
Glob
Agent
AskUserQuestion

/tour — grouped multi-axis sweep (clean + security + reconcile + doc)

MODEL GATE (blocking — run before any other step)

Run $HOME/.claude/lib/model-gate.md. Reflection here (planning, audit judgment, loop decisions) requires Fable/Opus. Verdict small → STOP: the gate prints the remedy; end the turn — no later step, no dispatch. Nominal (big) path is silent.

One pipeline per project: security → clean → re-verify → reconcile → doc → convergence re-audit, looping until a full pass applies zero new fixes. Auto mode by design: fixes are committed on a dedicated chore/tour-<date> branch that this skill never merges — the branch plus its report IS the approval gate, reviewed by the human afterwards.

Core principle: autonomy on the working branch, never on shared state. The skill may edit code freely on its own branch; it may NOT silently rewrite declared state (target TODO, memory registries) or integrate anything (merge/finish/push to main/develop).

When NOT to use

Situation Skill
One axis only (cleanup / security / TODO / doc) /code-clean, /cso, /reconcile, /doc
Recurring single-axis audit scoped to the delta /audit-delta
One obvious bug /hotfix, /bugfix
Quality dashboard, no fixes /health
Review a branch/PR diff /review, /code-review
All axes, fix, loop to clean, 1..N projects this skill

STEP 0 — ARGS & PROJECT LIST

  • Paths in $ARGUMENTS → project list. No paths → current repo only.
  • ONE project → run STEP 1 → STEP 3 inline in this loop (nominal path, unchanged).
  • TWO OR MORE projects → parallel fan-out, STEP 0b: the repos are independent working trees on independent chore branches — nothing the runners write can collide.
  • --report-only → run every audit, apply NO fix, write reports only (the flag is forwarded to every runner).
  • A failure in one project never aborts the tour: record it in that project's report section — or as its global-summary row when the runner itself died — and move on.

STEP 0b — MULTI-PROJECT FAN-OUT (one runner per project, BDR-084)

Dispatch ONE runner per project, ALL in a SINGLE message — sequential dispatch of independent repos defeats the purpose.

Model discipline (the user-fixed invariant behind this mode):

  • The runner is dispatched with NO model override — it inherits the session model, already validated big by the MODEL GATE above. The runner carries this skill's reflection (fix decisions, convergence calls); it must never be pinned down to an executor tier.
  • Inside a runner, every dispatched agent keeps the tier this skill already defines: security-auditor (sonnet frontmatter), the Phase B audit (analyzer opus pin or model="opus"), doc-syncer (audit on model="opus", patch on its sonnet frontmatter — BDR-077).

Runner dispatch, one per project:

Agent(subagent_type="general-purpose",
  description="tour runner — <project basename>",
  prompt="Read ~/.claude/skills/tour/SKILL.md and execute STEP 1 → STEP 3
    for EXACTLY ONE project: <absolute path>. Flags: <--report-only|none>.
    Skip STEP 0/0b (routing) and the global summary — the dispatcher owns
    them. Every rule of the skill applies unchanged: max 3 iterations,
    never merge/finish/push main|develop, scoped commits, report appended to that
    project's own .claude/audits/TOUR.md. Return EXACTLY: the project's
    one-line global-summary row (STEP 3 format), then BRANCH: <name|no
    branch>, then REPORT: <path>.")

The main loop then:

  1. Collects each runner's summary row. A dead or mute runner becomes the row <path> : RUNNER FAILED — <reason> | no report — never a silent absence (a mute runner is NEVER a pass).
  2. Prints the global summary (STEP 3 format) once ALL runners returned.
  3. Runs the gated capitalize offer — MAIN LOOP ONLY, never inside a runner: registries are shared state, and gate decisions stay here (LRN-083).

LRN-083 derogation, recorded in BDR-084: the per-project iteration loop (fix decisions, convergence) runs INSIDE its dispatched runner. Bounded because nothing a runner decides touches shared state — independent repos, per-repo chore branches, branches left UNMERGED for human review exactly as in inline mode.

STEP 1 — PRECONDITIONS (per project)

All git commands use git -C <project>. Check, in order:

  1. Is a git repository → else SKIP (recorded, not an error).
  2. Working tree clean (git status --porcelain empty) → else this project runs report-only: never mix the user's WIP with tour fixes, never stash someone else's work.
  3. develop exists and ~/.claude/lib/gitflow.sh is available → start the working branch via the lib, never by hand: bash ~/.claude/lib/gitflow.sh start chore tour-YYYY-MM-DD (append -2, -3… if the branch already exists). Missing develop or lib → report-only + suggest gitflow init in the report.
  4. Detect project checks once (tests, lint, build, type-check — from package.json/Makefile/CLAUDE.md). Record what exists; "none found" is itself a report line.

Report file: .claude/audits/TOUR.md in the target project (create .claude/audits/ if absent). Append-only — never rewrite past runs.

STEP 2 — ITERATION LOOP (max 3 per project)

Each iteration runs phases A→D in fixed order. Convergence = one full iteration that applies zero fixes and finds zero new findings with project checks green. Converged → STEP 3. Not converged after 3 iterations → STOP, residuals stay open in the report, say so honestly in the summary. Never loop past 3.

Phase A — SECURITY (deterministic floor first)

  1. Dispatch the SAST gate (fresh every iteration):
    Agent(subagent_type="security-auditor", description="tour security — semgrep SAST",
      prompt="MODE: audit\nSCOPE: project (full tree, respect .gitignore)\nPROJECT: <path>\nREPORT: .claude/audits/.tour-semgrep.md\nFollow agents/security-auditor.md exactly. Pinned rulesets, no login. Write ONLY to REPORT. End with REPORT_WRITTEN: <path>.")
    
    semgrep ABSENT → DEGRADED (checklist only) is surfaced in the report, not a silent downgrade and not a blocker.
  2. gstack ON (/cso available) → iteration 1 only, dispatch a cso posture audit (deps CVE, OWASP) in audit mode; fold its findings in.
  3. Fix policy (skip in --report-only): CRITICAL/HIGH → fix now. MEDIUM/LOW → fix only if local and behavior-preserving, else leave open. Every fix minimal, CLAUDE.md security defaults apply. A CRITICAL/HIGH fix that changes the API contract (new required header/param, changed status codes, moved paths) is NOT applied — a breaking change is the human's call (CLAUDE.md: confirm before a breaking change). Its report row becomes open — needs decision (BREAKING) with the proposed patch attached, and the global summary line carries the BREAKING count. Behaviour-preserving CRITICAL/HIGH fixes stay auto-applied.
  4. Commit scoped: git add <files touched> (never -A), fix(security): ….

Phase B — CLEAN

  1. Dispatch a read-only cleanup audit (analyzer — opus-pinned, BDR-076 — or general-purpose with model="opus"; NOT the sonnet code-cleaner, which is now a fix executor): dead code, unused imports/exports, commented-out blocks, stale flags, norm violations. Findings as id | file:line | finding | proposed fix.
  2. Apply behavior-preserving fixes only. A finding that would change behavior is a bug, not cleanup → log to .claude/audits/BUGS-FOUND.md, leave the code alone.
  3. Commit scoped: chore(clean): ….

Phase C — RE-VERIFY (after any fix)

  1. Run the project checks found in STEP 1. Lint alone is NOT verification when tests/build exist.
  2. Fresh read-only subagent re-audits the files modified this iteration (same axis prompts). Pass = approved findings resolved AND zero new findings introduced.
  3. Fail → fix → recheck, max 3 attempts inside the iteration; still failing → revert this phase's commits (fail closed), findings back to open, recorded in the report.

Phase D — RECONCILE + DOC

  1. Reconcile — REPORT-ONLY, always, even in auto mode. Confront declared state (target TODO checkboxes, registry statuses) against real state (git log, files, branches) — reuse lib/reconcile.sh oracles when available. Every gap goes in the report as declared X | real Y | suggested edit. Never check a box, never restructure, never edit the target project's TODO.md or .claude/memory/ — an inferred checkbox is exactly the lie /reconcile exists to catch. The human applies suggestions via /reconcile later.
  2. Doc sync — two-mode doc-syncer, mirrors /ship-feature STEP 8 (BDR-077: audit judgment on opus, patch on the sonnet pin): Agent(subagent_type="doc-syncer", model="opus") with MODE: audit
    • auto-mode scope: <files this tour touched>; public docs only (README, INSTALL, USAGE, CHANGELOG…), never .claude/**, never CLAUDE.md. NONE → done. [MINOR] PATCH PLAN → re-dispatch Agent(subagent_type="doc-syncer") (sonnet frontmatter) with MODE: patch + the plan verbatim, then commit its PATCHED_FILES: via bash ~/.claude/lib/doc-commit.sh when available, else a scoped docs: … commit of exactly those paths. SIGNIFICANT → not applied: report row suggested with the plan item (the tour has no human gate mid-run).

End of iteration

Fixes were applied (any phase) OR new findings appeared → run another iteration (fixes can invalidate earlier audits — that is the point of the loop). Otherwise → converged.

STEP 3 — REPORT, CLEANUP & SUMMARY (per project, then global)

Append to .claude/audits/TOUR.md, then close the run in this exact order:

  1. Write the run section (template below).
  2. Delete the scratch audit files this run created (.claude/audits/.tour-semgrep* and similar) — their content is folded into TOUR.md. A tree left dirty here forces the NEXT tour into report-only: the skill must not self-block.
  3. Commit the report as the run's final commit (docs(tour): report) — EXCEPT in --report-only mode: no chore branch exists there, so the commit would land on the user's current branch (possibly develop — the red flag below forbids that). Report-only leaves TOUR.md uncommitted and says so in the summary.
  4. Confirm git status --porcelain is clean (runtime junk the sandbox cannot delete, e.g. __pycache__/, becomes a report residual line).
## Tour 2026-07-04 — branch chore/tour-2026-07-04 — 2 iterations — CONVERGED
| ID | Axis | File | Sev | Finding | Status |
|----|------|------|-----|---------|--------|
| SEC-1 | security | app.py:17 | high | shell=True + concat | fixed |
| SEC-2 | security | app.py:14 | high | no authz on POST /backup | open — needs decision (BREAKING): new required X-Backup-Token header, patch attached |
| CLN-1 | clean | utils.py:9 | - | dead legacy_md5 | fixed |
| REC-1 | reconcile | TODO.md | - | "/health" unchecked, shipped 2d92696 | suggested |
| DOC-1 | doc | README.md | - | phantom /status endpoint | fixed |
Checks: pytest PASS, ruff PASS. Residuals: SEC-2 (needs decision). Commits: 4. BREAKING: 1 (SEC-2).

Global summary inline, one line per project (append BREAKING: n to any project line with contract-changing fixes left open for decision):

TOUR COMPLETE — 2026-07-04
  ~/proj/api    : CONVERGED (2 it.) — 3 fixed, 1 suggested | chore/tour-2026-07-04, 4 commits
  ~/proj/site   : NOT CONVERGED (3 it.) — 2 open residuals  | chore/tour-2026-07-04, 6 commits
  ~/proj/lib    : report-only (dirty tree)                  | no branch
  Branches left UNMERGED — review each, then `gitflow finish` on your GO.
  Reconcile suggestions pending — apply via /reconcile.

Then offer to capitalize (gated, per CLAUDE.md): recurring cross-project patterns → learnings, tour verdict → evals. Never write registries without that approval — neither this repo's nor any target project's.

Rules

  • Branch via the gitflow lib; never gitflow finish, never merge, never push main/develop — "the tour is green" is not a signal. The chore branch's own commits are pushed by the gitflow hooks (BDR-095); a push FAILED hook warning is a report residual, fixed with a plain git push -u origin chore/tour-<date>.
  • Scoped pathspecs only; git add -A is forbidden.
  • Target TODO.md and target .claude/memory/ are READ-ONLY. Reconcile produces suggestions, not edits.
  • Only the four axes. No unrequested bootstrap (.gitignore, registries, configs, features) — infrastructure gaps are report lines, not work.
  • Security floor = security-auditor (pinned semgrep + checklist). An ad-hoc grep is never "the security pass".
  • Max 3 iterations per project; max 3 fix attempts per re-verify. Residuals are reported, not silently retried forever.
  • Dirty tree / no develop / no gitflow lib → report-only, stated in the report. Never stash, never branch by hand.
  • Reports append-only. One report per project, in that project.

Common mistakes

Mistake Fix
Checking TODO boxes "obviously done" during reconcile Report-only. Suggested edits, human applies.
Writing BDR/LRN/journal entries in the target project Registries only via the gated capitalize offer, end of tour.
grep/ruff pass = security done security-auditor agent (pinned semgrep) is the floor, every iteration.
Findings live only in the final chat message TOUR.md is what the human reviews before merging. Write it.
"Bonus hygiene" (.gitignore, templates, bootstrap) Out of scope. Report line, not work.
Loop "until clean" with no bound Max 3 iterations, then honest residuals.
Merging/finishing because everything is green Green ≠ GO. Branch stays; human merges.
Stashing a dirty tree to proceed Report-only for that project.
One TOUR.md for all projects in the config repo Each project gets its own .claude/audits/TOUR.md.
Fixing a behavior-changing "cleanup" finding That is a bug → BUGS-FOUND.md, untouched code.
Scratch audit files left untracked at the end Delete them in STEP 3.2 — a dirty tree self-blocks the next tour.
Contract-changing security fix auto-applied Not applied: row open — needs decision (BREAKING) + proposed patch; BREAKING count in the summary line.

Red flags — STOP

  • About to Edit a target project's TODO.md or .claude/memory/*.
  • About to run gitflow finish, git merge, or push main/develop.
  • About to git add -A or commit on main/develop.
  • Starting iteration 4, or "just one more loop, it's almost clean".
  • Security phase done without the security-auditor agent and without a DEGRADED notice in the report.
  • Creating any file the audit did not require (.gitignore, templates).
  • Ending a project's run with git status --porcelain non-empty and no residual line explaining every leftover path.

TDD note (skill itself)

Baseline-tested per superpowers:writing-skills (2026-07-04, seeded fixture, no skill): the agent branched correctly via gitflow and did not merge, BUT (1) silently rewrote the target TODO (checked boxes, restructured) during "reconcile"; (2) authored BDR/journal registry entries autonomously; (3) ran security as ad-hoc grep + ruff — no semgrep, no pinned rulesets; (4) left findings only in its final chat message — no persistent report to review before merge; (5) bootstrapped unrequested .gitignore + memory registries ("bonus hygiene"); (6) looped without a stated bound (converged at pass 2 by luck). Phase D.1, the registry rule, Phase A.1, STEP 3, the scope rule and the 3-iteration bound counter each observed failure.

GREEN run (same day, fresh fixture, skill followed): all six gaps closed — TODO zero-diff, no registry writes, semgrep every iteration, TOUR.md committed, no scope creep, converged in 3 bounded iterations on an unmerged chore branch. Two new holes surfaced and patched (REFACTOR): scratch semgrep files left untracked (would self-block the next run — STEP 3.2) and a contract-changing security fix not flagged (BREAKING tag in template). The REFACTOR additions are template-structural and were not re-run through a third full fixture pass — re-test on first real use.