--- name: bootstrap description: Generate the maintainerd config contract for a repo — write `.claude/maintainerd.json` and scaffold `.claude/guidelines/{coding,testing,invariants}.md` so the repo-ops, audits, research, and auto-dev skills can run here. Inspects the repo (language, GitHub slug, default branch, source/test dirs, lint/format/build/test commands), confirms anything ambiguous, seeds starter guidelines from existing CLAUDE.md/AGENTS.md, and adopts the coverage ratchet by measuring the default branch on a fresh worktree and recording `coverage.floor`. `--adopt` runs only that last part, for a repo that is already bootstrapped. With `--profile --language `, the PR-template step copies the profile's canonical template (`files.prTemplateSource`) instead of the built-in one, when it resolves. Use when the user asks to "bootstrap this repo", "set up maintainerd", "create the maintainerd config", "configure the maintainer skills", "onboard this repo to maintainerd", or when any other maintainerd skill reports the config is missing. Idempotent — re-running re-confirms and only rewrites changed keys; never clobbers hand-edited guideline prose. --- # Bootstrap a repo for the Maintainerd toolkit This skill writes the **config contract** that every other Maintainerd skill reads. After it runs, the repo has: - `.claude/maintainerd.json` — structured config (schema in [`../../references/config-schema.md`](../../references/config-schema.md)). - `.claude/guidelines/coding.md`, `testing.md`, `invariants.md` — free-form rule files the audits read, and that any reviewer (including Claude Code's built-in `/code-review`) should be given as this repo's standards. The goal is a config that's *correct on the first read* — detect everything you safely can, ask the user only about what's genuinely ambiguous, and be honest in the final report about what still needs human judgment (especially `invariants.md`). Read the schema reference first: [`../../references/config-schema.md`](../../references/config-schema.md). Every key you write must match it. ## Inputs - `/bootstrap` — the full pass: detect, confirm, write the config and the guidelines, and (step 10) measure the coverage floor if the repo doesn't have one yet. - `/bootstrap --adopt` — **just the coverage floor.** Skip straight to step 10 and (re-)measure `origin/`, writing `coverage.floor` and `coverage.floorCommit` into an existing config. This is what you run to put an already-bootstrapped repo under the ratchet, and what `doctor`'s check 13 names when it finds no floor. It requires an existing `.claude/maintainerd.json` — it never writes one. - `/bootstrap --profile --language ` — same full pass (or the same `--adopt`), but step 7 additionally resolves `` ([the repo-profile contract](../../references/profile-schema.md)) for this repo's `` and, when `effective.files.prTemplateSource` resolves to a real file, copies it as the PR template instead of the built-in one. This is the only thing `--profile` changes today — every other command, path, and label bootstrap still detects and confirms exactly as it would without one. (`new-repo` already seeds the rest of bootstrap's answers from a profile when it calls this skill as its own step 6; a bare `/bootstrap --profile` is for bringing an *existing* repo's PR template up to the fleet's canonical shape without running the whole `new-repo` flow on it.) An unresolvable `--profile` path, or a `--language` absent from its `languages`, is reported and treated as no profile — step 7 falls back to the built-in template rather than failing the run. ## Workflow ### 1. Detect whether this is a re-run ```bash cat .claude/maintainerd.json 2>/dev/null ``` - **Exists** → this is an update. Read it, keep every value the user has set, and only re-confirm values that look stale or that the user asks to change. **Never** overwrite `.claude/guidelines/*.md` whose body is more than the scaffold (see step 6). Report what changed. - **Missing** → fresh bootstrap. Continue. ### 2. Detect identity and language Run these and read the results — don't assume: ```bash # repo slug — gh first; if origin isn't a GitHub remote (e.g. a local clone), parse the URL gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null \ || git remote get-url origin 2>/dev/null | sed -E 's#(git@github.com:|https://github.com/)##; s#\.git$##' # default branch — origin/HEAD, else the remote's advertised default git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@' ls pyproject.toml package.json go.mod Cargo.toml 2>/dev/null ``` **Confirm the repo slug and default branch — don't trust detection blindly.** Two traps: (1) if `origin` points at a local path or a non-GitHub host, `gh repo view` yields nothing — fall back to the URL parse, and if that's also empty, **ask the user**. (2) `origin/HEAD` can be stale or, in a clone made off a feature branch, point at that branch instead of `main`/`master` — so if the detected default isn't `main`/`master`, or the current branch isn't it, **confirm with the user** rather than writing a feature branch into the config. - `pyproject.toml` present, no `package.json` → `language: "python"`. - `package.json` present, no `pyproject.toml` → `language: "typescript"`. - Both, or neither → **ask** the user which language the skills should target (this drives the audit/test detection rules). The toolkit currently ships Python and TypeScript rule sets; if the repo is another language, tell the user the audits will fall back to language-generic checks only. ### 3. Detect commands Read the project manifest and pull the real commands rather than guessing: - **Python** (`pyproject.toml`): look for ruff (`format` → `… ruff format --check`, `lint` → `… ruff check`), the test runner (`pytest` → `… pytest`). Honor the project's runner prefix (`uv run`, `poetry run`, `hatch run`, or bare) — check for `uv.lock`/`poetry.lock`. `build` is almost always `null`. `typecheck` → mypy/pyright if configured, else `null`. - **TypeScript** (`package.json` `scripts`): map `format`/`format-check`, `lint`, `build`, `test`, `typecheck`/`typecheck:test` to whatever scripts exist. Use the exact `npm run