Skip to content

What this is

roadkeep owns the writes to a project’s ROADMAP.md, CHANGELOG.md, IMPROVEMENTS.md and STRATEGY.md. A task line is inserted by a command that validates it, not typed by whoever is holding the file — so the format is a schema at the moment the text is created, and drift is refused before it is written rather than reported after.

The author it constrains is usually an agent. It ships as a Claude Code plugin, and the same engine answers on the command line, in a hook, in CI and over MCP.

Every design question in this project is settled by one of these. They are rendered from agents.md, which is where they live and where the gate holds a budget over them — a copy typed into this page would be the accretion the tool exists to refuse, and the copy nobody is looking at is the one that drifts.

L1
Schema enforced where the text is created; lint is only the backstop.
L2
The store is the repository — Markdown, greppable, no database, no service.
L3
Round-trip or don't write — parse → render → byte-identical, or refuse the file.
L4
The tool never writes prose — it validates and renders.
L5
Query instead of read — every question is a command, so answering costs no context.
L6
Configuration, not convention — prefix, paths, markers, limits are per-project.

The other half of a scope, and the half most projects never write down. These come from roadkeep non-goal list, which is the verb that owns them: they are bullets in this repository’s own roadmap, printed with every task briefing so a suggestion that violates one is refused before it is worked on.

  • No web UI and no server.
  • No model and no prompts.
  • No enforced id scheme beyond <prefix><n>.
  • No dates or quarters.
  • No backlog in an issue tracker
  • No multi-line task line.
  • No supported Python API.
  • No effort or size field.

This area is for the reads that decide an adoption, which are the ones an installed copy would otherwise gate. Everything narrower than the whole README used to live inside a checkout: --help is a terminal read, explain answers a finding code from an installed copy, config describes roadkeep.toml from a build, and the skill is written for an agent that already has the plugin.

Reference pages here are generated from the package, not written beside it. A page that retyped a flag, a finding code or a config key would be wrong at the first rename and would report nothing; the build derives them from the same declarations the tool enforces, and fails where the two disagree.

For everything else, the repository is the source and this area does not hold a second copy of it:

  • The README — the measured problem, the six laws, the installation routes and the non-goals.
  • The backlog — what is open, in the format the tool enforces on itself.
  • The ledger — what shipped, indexed by block.
Terminal window
uvx roadkeep init # scaffold the files and roadkeep.toml
uvx roadkeep add --block A --symptom "" --why ""
uvx roadkeep lint # exits 1 on anything that drifted

add refuses a line that would not validate, so the question “what would I cut?” never arrives — the ceiling was known before a sentence was composed to fill it. lint is the backstop for whatever bypassed it, and its exit code is the whole difference between a gate and advice.

Nothing is installed to run those three. The package is on PyPI and takes no runtime dependenciesargparse and tomllib, both stdlib — so uvx resolves a single name and there is no tree to solve behind it. pip install roadkeep puts the same console script in an environment you keep, and requires-python in the published metadata is the only floor. A checkout is the exception now rather than the route: uvx --from git+https://github.com/alegauss/roadkeep roadkeep lint is how you reach a fix that has not been released yet.