github setup
User-invoked only. Two actions: check (report, change nothing) and apply (write consumer
config). No action given: run check, then offer apply if anything is missing.
check, verify, report, change nothing
Report a PASS/FAIL/INFO table with one remediation line per FAIL. Modify nothing.
ghpresent? If not: FAIL, stop with a concise message naming the missing prerequisite and the official install page (https://cli.github.com). Remediation is the user's to run.gh auth status. Confirm an authenticated session; name the account and host in the report. Never store, echo, or persist credentials or token values.Credential-modality picture. For the areas the consumer cares about (ask, or take them from the invocation), run the diagnosis method from
${CLAUDE_PLUGIN_ROOT}/reference/method-ladder.md(rung 0): what the live session's credential can and cannot reach, resolved against fresh official docs. Never a shipped scope table. When a needed scope is missing, report it as the honest-degradation gate and recommend the exactgh auth refreshcommand for the user to run themselves. Never auto-run a re-consent, no matter what standing "fix it automatically" instructions exist.Config layers. Resolve both surfaces (
routing.yaml,conventions.md) per${CLAUDE_PLUGIN_ROOT}/reference/change-routing.mdand${CLAUDE_PLUGIN_ROOT}/reference/conventions-file.md, anchored at the repo root, and report a PASS/FAIL/INFO row per layer, with one remediation line per FAIL:Layer Verdict user-global INFO exists or INFO absent. No git verdict applies outside the worktree team PASS when the pair ( git check-ignore -vno match ANDgit ls-files --error-unmatchexit 0) holds. Present but ignored: FAIL, report the matching rule and say to unignore it. Present but untracked: FAIL, "commit it to share with the team"local overlay PASS when present, gitignored, and never staged. Tracked or staged: FAIL, remediation is git rm --cached <path>plus rotating any credential that was committed (adding a gitignore line does not untrack it). Present but unignored: FAIL, recommend.claude/**/*.local.*for the user to add themselves. Tracked outranks unignored: when both hold, name the tracked findingAll three layers absent is INFO: "unconfigured: routing resolves to propose-only", not FAIL. A malformed layer is named and skipped, per the contract.
Report the effective routing per scope block with the layer that supplied each value (policy-floor provenance included), and the recursive overlay gitignore line (
.claude/**/*.local.*) when it is missing from the consumer's.gitignore. Recommend it; never edit the consumer's.gitignore.
apply, idempotent, interview-driven config write
- Read first. Load every existing layer of
routing.yamlandconventions.md.applyconverges the config on the interview's answers. It never blindly rewrites. Converging is state-assessing, so arouting.yamlrewrite is bounded two ways:- Preserve every key the existing file carries that this schema does not recognize. A consumer extension or a newer plugin version may own it; a re-run never drops one. Write the merged document rather than a fresh one built from the answers alone.
- Report a recognized key whose value this version cannot reconcile. Never silently rewrite
it. An obsolete
default, a scope block naming an area this version does not know, ahandoffchannel whosetargetno longer parses: name the key, the value, and why it did not reconcile, and let the user decide. Silently converging an unreconcilable value is config loss the consumer only discovers when routing misbehaves.
- Interview the routing posture, with a recommendation per question: which scopes to
declare (repo / org / enterprise), the
defaultper scope, per-area overrides worth declaring, and, when any answer ishandoff, the channel'starget/instructions. Unanswered postures fall back topropose. When the invocation already supplies complete answers, skip the interview and run non-interactively. - Write to the team layer (
${CLAUDE_PROJECT_DIR}/.claude/github/), or the layer the user explicitly chooses. Local-layer precondition: before writing any*.local.*overlay, verify the target path is ignored (git check-ignore -q <path>); when it is not, surface the recommended gitignore line first and wait for the user to either add it themselves or explicitly accept writing an unignored overlay. Never write silently, never stage it, and never edit their.gitignore.routing.yamlconforming to the schema in${CLAUDE_PLUGIN_ROOT}/reference/change-routing.md.default: proposeunless the user chose otherwise.conventions.mdstub (what the file is for + a pointer to${CLAUDE_PLUGIN_ROOT}/reference/conventions-file.mdsemantics). Only if none exists; never overwrite or append to a consumer's existing conventions.
- Idempotency check: when the merged answers equal the existing config, report "no changes
needed" and write nothing. A second run with the same answers must produce zero file changes.
After a team-layer write, re-run the tracked-file pair on each written path
(
git check-ignore -vno match ANDgit ls-files --error-unmatchexit 0); non-zerols-filesright after a fresh write means "written but untracked: commit it to share with the team", never success. - Recommend the recursive gitignore line (
.claude/**/*.local.*) if the consumer's.gitignorelacks it. The edit is theirs to make.
Hard rules
checkperforms zero writes of any kind.- Neither action ever stores credentials, runs a re-consent flow, or edits the consumer's
.gitignore. - Config written by
applyis the consumer's artifact: plain, minimal, no generated boilerplate beyond the stub's two-line purpose note.