setup
Configures a repo once for the compost skills, recording its issue tracker, domain doc layout, core docs, test convention, verify gates, and observability st...
npx skills
npx skills add JoshuaOliphant/compost --skill setup
Works for Codex, Cursor and other harnesses. Use -a <agent> to target one, e.g. -a codex.
Claude Code
/plugin marketplace add JoshuaOliphant/compost
/plugin install compost@compost
Setup
The other compost skills assume a few facts about the repo: where issues live, where the glossary
and ADRs live, which docs are core, how tests are written, which gates must pass before
anything counts as done, and how to read what the running code emits.
Setup finds those facts, confirms the ones that branch, and writes them to docs/agents/, where
every skill reads them. It also points the repo's instructions file at those docs and offers to
consolidate the instructions into AGENTS.md.
Setup is idempotent. Running it again updates what changed and keeps everything else, including edits the user made by hand.
Steps
- Explore. Read what exists; assume nothing.
git remote -v: GitHub, GitLab (gitlab.com or a self-hosted host), or none.- Instruction files in the repo root and in every directory above it:
CLAUDE.md,.claude/CLAUDE.md,CLAUDE.local.md,AGENTS.md,.claude/AGENTS.md. Note any existing## Agent skillsblock and whether aCLAUDE.mdis an@AGENTS.mdimport or a symlink. docs/agents/: the output of an earlier run.CONTEXT.md,CONTEXT-MAP.md,docs/adr/, and any*/docs/adr/in subpackages..scratch/: a sign a local tracker is already in use.- Markdown outside the core docs (
docs/, architecture notes, plan files), files that are product rather than prose (skill or prompt files, templates), and a published docs site (mkdocs.yml,docusaurus.config.*). - Monorepo signals:
pnpm-workspace.yaml, aworkspacesfield inpackage.json,[tool.uv.workspace]inpyproject.toml, a Cargo[workspace],go.work, or a populatedpackages/*whose members have their own sources. - Tests and gates: the test layout and framework in use, coverage configuration, linters, type
checkers, formatters,
.pre-commit-config.yaml,Makefileorjustfiletargets, package scripts, the commands CI runs in.github/workflows/or.gitlab-ci.yml, and mutation testing config (cosmic-ray.toml,[tool.mutmut],stryker.config.*,.cargo/mutants.toml, a pitest plugin). -
Telemetry:
.claude/harness/observability/, and Logfire, Sentry, or OpenTelemetry in the dependencies or the app's startup code. -
Present findings and ask only where the answer branches. Summarize what is present and what is missing, then take the sections below in order, one answer each. Lead with the recommendation so it can be accepted in a word. Skip a section entirely when exploration settled it. On a rerun, show what would change against the existing files instead.
-
Issue tracker. Recommend GitHub when a remote points there, GitLab when one points there, and otherwise offer GitHub, GitLab, local markdown under
.scratch/, or other (Jira, Linear: the user describes the workflow in a paragraph and you record it as prose). Before recording GitHub or GitLab, confirm the tracker has issues turned on: GitLab,glab api projects/:idreportsissues_enabled: true; GitHub,gh api repos/{owner}/{repo}reportshas_issues: true. When issues are off, record nothing and create no labels yet; ask whether to enable them (GitLab: Settings > General > Visibility, project features and permissions; GitHub: Settings > General > Features) or pick another tracker. When the check can't run (no auth, host unreachable), say so and ask; don't record on a guess. Otherwise the disabled tracker only surfaces whencompost:specfails to post. Writedocs/agents/issue-tracker.mdfrom the matching template: GitHub, GitLab, or local. Each carries the label vocabulary compost uses; if the tracker already has labels for the same roles, map them in the table rather than creating duplicates. For GitHub or GitLab, list the tracker's labels (gh api repos/{owner}/{repo}/labels --paginate --jq '.[].name'/glab label list) and create every label in the table that it lacks (the template's label command /glab label create) now, so the first issue labelledspecdoesn't fail. -
Domain docs. Default to a single context: one
CONTEXT.mdanddocs/adr/at the root. Write that without asking. Offer aCONTEXT-MAP.mdwith oneCONTEXT.mdper context only when exploration found monorepo signals, and confirm the layout then (ubiquitous language). Writedocs/agents/domain.mdfrom domain. Don't createCONTEXT.mdordocs/adr/now;compost:speccreates them when the first term or decision settles. -
Core docs. Write
docs/agents/docs.mdfrom docs: the core docs that exist, any the repo needs beyond the defaults, and the patterns that are product rather than documentation. Don't ask; the user edits the file if a default is wrong. Then runuv run ${CLAUDE_PLUGIN_ROOT}/scripts/doc_refs.py scanwith those patterns. If it lists non-core docs, tell the user how many, how many name paths that no longer exist or files that changed since, and thatcompost:prunewill check them against the code, move what is worth keeping into names, types, tests, and comments, and delete the rest. Offer it as the next move after setup; pruning is its own change, never part of this commit (core docs). -
Test convention and gates. Work out the convention with the detection ladder in testing: adopt the pattern already in use, default by stack when there are no tests, and ask only for a greenfield repo with no clear stack. Then list the gates
compost:verifywill run: the suite command, the coverage command and threshold (100% line coverage unless the project already sets one), linters, type checkers, and anything CI treats as required. Run each gate once. Record the ones that pass as gates; record a gate that fails or doesn't run as broken, with its output's first error, rather than dropping it. Record the mutation tool the same way: adopt one already configured, or offer the stack's default from mutation testing, and run it once over the last commit that changed source. Writedocs/agents/testing.mdfrom the template in the same reference. -
Observability. Find the telemetry the repo's running code emits with the detection ladder in observability: the observability harness, another stack already wired, or, with nothing found, one question offering the harness, the user's own stack, or none. Run one query against what you record, and record a stack you cannot read as broken with its first error. Write
docs/agents/observability.mdfrom the template in the same reference (read the running system). Another skill that finds the file missing runs this step on its own: then also add the### Observabilityentry to the## Agent skillsblock (step 8) and commit both aschore: record the observability stack, so the next skill finds them. -
Instructions file and the AGENTS.md migration. Claude Code reads
AGENTS.mdnatively only when noCLAUDE.md,.claude/CLAUDE.md, orCLAUDE.local.mdexists in the working directory or above it;~/.claude/CLAUDE.mddoesn't count and still loads alongside. Follow instruction files for each combination you found. In short: - A project
CLAUDE.mdand noAGENTS.md: offer to move it intoAGENTS.mdwithgit mv, so both are never present. Personal preferences in it belong in~/.claude/CLAUDE.md; show which lines and move them only with the user's yes. - Both present: offer to fold
CLAUDE.mdintoAGENTS.mdand remove it. - Neither present: ask which to create, recommending
AGENTS.md. - Never create one file while the other exists without offering first.
Then add or update the ## Agent skills block in whichever file holds the project
instructions. Replace an existing block in place; leave the surrounding sections alone.
-
Check the Jev key. Run
uv run ${CLAUDE_PLUGIN_ROOT}/scripts/jev.py status. It looks for a TypeSafe key (TYPESAFE_API_KEY, then the macOS Keychain itemtypesafe) and builds the client, but sends no request; its line names the model and server. When the user would rather keep diffs on their machine or has no key, offer Ollaya, a local server with TypeSafe's wire format: compost's README, "Running on Ollaya instead", has the variables to export (includingNO_PROXYfor a machine behind a system proxy). Tell them its thresholds were measured on Jev and that a model with a small option budget falls back on the asks it cannot fit. WithTYPESAFE_BASE_URLset, status says "configured (not contacted)": it cannot tell whether that server is running, so say so. Exit 0 with "ready" means the Jev tools will answer. Exit 3 means every Jev step will fall back to your own judgment: tell the user what they lose (cheaper test placement, review triage, the Stop guard in unattended runs) and pass on the fix its one line names. With no key, that is a command for them to run themselves, for example as! security add-generic-password -s typesafe -a "$USER" -w; when the client could not start, it is the key's format or the proxy setting it quotes. Never ask for the key in chat or write it anywhere. The key belongs to the machine, not the repo, so record nothing. -
Switch off what compost replaces. Run
uv run ${CLAUDE_PLUGIN_ROOT}/scripts/pile.py replaced. It reads the[replaces]table in compost'spile.tomland reports which superseded plugins and skills are still active on this machine; it changes nothing. Leaving them on gives Claude two answers to every request. Show the user the report and, with their yes, run it again with--apply: it disables the plugins throughclaude plugin disableand sets the skills to"off"inskillOverridesin~/.claude/settings.json, keeping everything else there. Plugins synced from claude.ai can only be turned off in the user's claude.ai settings, so pass those on. None of this deletes anything: re-enabling a plugin or removing an override turns it back on.compost itself can be enabled twice, as
compost@compostandcompost@oliphant-plugins, which loads every skill twice. The report marks the id that isn't running this script as compost itself wherever it lists it (to disable, to turn off on claude.ai if synced, or to uninstall if orphaned), and never lists the one that is. It lists neither when it can't tell which copy runs (a checkout run with--plugin-dir, or a copy already disabled earlier in this session) or when the running copy is itself orphaned, since the other is then the one to keep.The report also lists, under its own heading, orphaned installs: plugins still installed whose marketplace's clone no longer lists them, enabled or not. They load stale copies and fail every marketplace update.
--applyuninstalls them throughclaude plugin uninstall, keeping their data directories, and unlike disabling this cannot be undone, since the marketplace no longer offers them. Ask about them as a separate yes: if the user wants the superseded ones turned off but the orphans kept, run--apply --keep-orphans. This is per machine, so on a second repo the report usually says nothing is active. -
Check and commit. Re-read every file you wrote. List the directories above the repo that still hold a
CLAUDE.md, since any of them stopsAGENTS.mdfrom loading. Rungit check-ignore -von every file you wrote in the repo: eachdocs/agents/*.md, the instructions file, and anyCONTEXT-MAP.mdorCONTEXT.md. It prints asource:line:patternline for each ignored path, and a broad rule (agents/also matchesdocs/agents/) leaves a file out of the commit without a word. For each hit, show the user the rule and offer to anchor it (/agents/) or narrow it, editing the file it came from only with their yes; if they keep it, say which files the commit leaves out. Commit the changes as onechore: configure agent skillscommit. Tell the user which compost skills now read these files, that they can editdocs/agents/*.mddirectly, and, after a migration, to look for theAGENTS.md loadedline at the start of their next session. Also tell them that in manual permission mode the/compost:review-changesworkflow asks for permission on every run until they pick "Yes, and don't ask again", or until they addWorkflow(compost:review-changes)to their allow rules.
Next moves
compost:prunewhen the core-docs step found docs outside the core, so the repo starts with docs the code backs.compost:specwhen there is a feature or change to define.compost:slicewhen a spec already exists as an issue or doc.compost:diagnosewhen a gate came back broken and the repo should be green before other work.