Repo-level AI coding readiness assessment, in Go.
Plumbline scans a repository, looks for the feedback loops that make AI-driven development reliable (instruction files, coverage gates, nightly suites, automated triage, issue-to-PR pipelines), and reports which level of the AI Codebase Maturity Model (ACMM) the repo sits at. Detection is deterministic — no LLM calls, no network.
Based on Andy Anderson's paper The AI Codebase Maturity Model: From Assisted Coding to Self-Sustaining Systems (the paper's .md is included as the_ai_codebase_maturity_model.md, converted from PDF via Microsoft MarkItDown). See Deviations from the source paper below for where this implementation deliberately diverges.
go install github.com/sroberts/plumbline/cmd/plumbline@latestPre-built binaries (darwin / linux × amd64 / arm64) ship on the Releases page once a version is tagged.
# Bare invocation: opens the Bubble Tea TUI on a terminal.
plumbline
# Pipe / CI: brief text summary.
plumbline | tee maturity.txt
# Machine-readable verdict for an LLM tool harness.
plumbline --json
# Stream progress events to stderr while the scan runs.
plumbline --json --events ndjson 2>events.log >verdict.json
# CI gate: fail if not at level 3.
plumbline --fail-below 3 --quiet
# Drill into one signal's status, evidence, and fix recipe.
plumbline inspect l2.agent-instructions
# Scaffold a missing artifact (dry-run; --apply to actually write).
plumbline fix l2.agent-instructions
plumbline fix l2.agent-instructions --apply
# Install a Claude Code skill so AI agents in your repo know how to drive plumbline.
plumbline install-skill --applyThe model assigns a level by feedback loop topology, not by AI autonomy. Levels are sequential — Level N requires Level N−1's artifacts.
| Level | Name | Loop topology | What plumbline looks for |
|---|---|---|---|
| 1 | Assisted | Open loop | (implicit floor — no checks needed) |
| 2 | Instructed | Human → AI | one agent-directive file (CLAUDE.md / AGENTS.md / copilot-instructions / .cursorrules / .windsurfrules), CONTRIBUTING.md, PR template, commit rules |
| 3 | Measured | AI → metrics → human | build/lint gate, coverage gate, scheduled compliance / a11y / perf / security, flaky-test analysis, error monitoring, NPS, acceptance tracking |
| 4 | Adaptive | Loop closes itself | self-modifying configs, sub-daily auto-triage, threshold-driven blocks, worktree agents, error recovery |
| 5 | Self-Sustaining | Codebase is the policy | issue-to-PR pipelines, self-improvement, docs-from-PRs, multi-repo orchestration |
A repo with stellar L3 but missing L2 is L1 — you cannot skip levels.
Run plumbline signals for the 21-signal catalog or plumbline help levels for the long form.
Plumbline mostly follows Table 2 of the paper, but a few signals are intentionally restructured. Full rationale is in SPEC.md §6 → "Deviations from the source paper". Headline deltas:
- L2 agent-instructions is ONE signal, not many. The paper lists
CLAUDE.mdandCopilot instructionsas separate L2 feedback loops (the reference deployment ran both in parallel). Plumbline collapses them, plusAGENTS.md,.cursorrules, and.windsurfrules, into a singlel2.agent-instructionsthat fires on the presence of any one. Most teams use one agent; penalizing a project for not encoding directives for tools nobody uses was the wrong call. - PR-template lives at L2, not L3 — the paper is ambiguous; "encoded judgment via checklist" is the L2 definition.
- L3+ workflow signals are GitHub-Actions only in MVP. GitLab CI / Buildkite / CircleCI / Jenkins are deferred behind
--ci-system; not a philosophical disagreement, just a scope cut.
| Mode | Use case |
|---|---|
| TUI (default on a terminal) | Interactive exploration; drill into signals; apply fixes |
--json |
Machine-readable verdict; LLM tool harnesses |
--report markdown --out maturity.md |
Committable report |
--report sarif --out plumbline.sarif |
GitHub code-scanning |
--events ndjson on stderr |
Per-signal progress events while scanning |
Schemas are published via plumbline schema {verdict, signal-result, event, config} (draft 2020-12).
| Key | Action |
|---|---|
↑ / ↓ (or j / k) |
Move selection in the signal list |
enter |
Open the detail screen for the selected signal |
a |
Apply the signal's fix (only on signals marked ✚) |
r |
Re-run the scan in place |
esc |
Back |
q / ctrl-c |
Quit |
In the fix flow: tab/shift+tab between input fields, enter advances, y/n to confirm or cancel the preview.
plumbline fix is the only path through which plumbline writes inside the target repo. Defaults are conservative:
- Dry-run by default;
--applyis required to actually write. create-filerefuses to overwrite an existing file.append-filerequires the target to already exist.- Paths must be relative and resolve inside the repo root;
..and absolute paths are rejected. - Unknown
FixOpKinds are rejected.
Everything else (assess, inspect, signals, explain, schema, help, version) is read-only.
# .github/workflows/maturity.yml
name: ACMM gate
on: pull_request
jobs:
plumbline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: stable }
- run: go install github.com/sroberts/plumbline/cmd/plumbline@latest
- run: plumbline --fail-below 3 --quiet --signal-set v1--signal-set v1 pins the rule-set version so the gate can't silently flip when plumbline upgrades. plumbline help compatibility documents what each version contains.
Install the plumbline-usage guide into the location your tool expects. Pass --target <name> to pick:
| Target | Path | Notes |
|---|---|---|
claude (default) |
.claude/skills/plumbline/SKILL.md |
dedicated |
cursor |
.cursor/rules/plumbline.mdc |
dedicated |
gemini |
GEMINI.md |
shared |
codex |
AGENTS.md |
shared (also read by other AGENTS.md tools) |
opencode |
AGENTS.md |
shared |
windsurf |
.windsurfrules |
shared |
cline |
.clinerules |
shared |
copilot |
.github/copilot-instructions.md |
shared |
# This repo (default = claude).
plumbline install-skill --apply
# Cursor in this repo.
plumbline install-skill --target cursor --apply
# Gemini, globally (under $HOME).
plumbline install-skill --target gemini --global --apply
# List all targets.
plumbline install-skill --list--global installs at user scope (e.g., ~/.claude/skills/plumbline/SKILL.md, ~/.gemini/GEMINI.md) for tools that have a documented global location. Run --list for the full set; targets without one will error if you pass --global.
The TUI surfaces the same picker: bare plumbline on a terminal → press i → pick a target with ↑/↓ → toggle [g] for global ↔ project scope → enter to preview → y to install.
The body is hand-tuned for AI agents — when to invoke plumbline, the recommended call sequence, the stable signal IDs / schemas / exit codes, and when not to invoke it. The frontmatter is tailored per tool (Claude SKILL.md frontmatter, Cursor .mdc frontmatter, plain markdown for AGENTS.md / .windsurfrules / etc.).
Recommended call sequence:
plumbline schema verdict— fetch the output contract.plumbline signals --json— discover the catalog.plumbline assess --json --events ndjson 2>events.log >verdict.json— run the scan.- For each id in
verdict.next_gap:plumbline inspect <id> --jsonto get evidence + fix recipe. - To scaffold:
plumbline fix <id> --apply --input KEY=VALUE …(or--jsonfor a structured plan).
Stable IDs, stable JSON-Schema $ids, stable exit codes (0 ok / 1 gate-failed / 2 cannot-run / 3 config-error). plumbline help agents has the full guidance.
- SPEC.md — full spec: signal catalog, scoring math, schemas, deviations, milestones
- CLAUDE.md — guidance for AI agents contributing to plumbline itself
the_ai_codebase_maturity_model.md— the source paperplumbline help— topical guides (levels,signals,scoring,output,config,ci,agents,profiles,compatibility,fix)
v0.1.0 — first release. Single-developer project; the catalog covers 21 signals across L2–L5. The fix scaffolder covers the L2 catalog; L3+ fix scaffolders are intentionally deferred (the "merge into existing workflow" case needs more design).
MIT — see LICENSE.