Skip to content

Asking instead of reading

Query instead of read. This is the law the rest of the tool pays for: if every question about the backlog is a command, then answering one costs a fixed, small amount rather than a file printed into a context window. A format nothing can query is a format whose only reader is a person scrolling.

The read to start from is brief. It composes the line, its rationale, its resolved dependencies, the blocker chain, what shipping it unblocks and the non-goals that bind it — in one call. With no id it briefs whatever pick would choose, which makes the first call the only one.

pick is the choice itself: the lowest ready id, unless the project declared a priority order that outranks it, with anything still blocked or undesigned set aside. show, deps and list are the narrower questions under it.

Several of these answer about the history rather than the files. origin says which commit proposed a task and which shipped it; weight says what a task cost in lines and files, and which entries were batched into one commit; unclosed finds open lines whose work the history already names, which is the state a session that shipped the code and forgot the line leaves behind.

budget and cost are two tenses of one subject: what a write may spend before a word of it exists, and what a surface does spend every session already. config says what roadkeep.toml may declare, and commands — the read every table on this page is generated from — says what may be typed.

Every command takes --json, which carries provenance: which file and line the answer came from. An answer an agent cannot audit gets verified by reading the file, which is the cost the command existed to remove.

list

Reads. Served to an agent as list.

Print the lines a filter selects, exactly as the file spells them. A marker-bearing line the grammar did not accept is reported on stderr with the count, so a filtered listing can never look complete when it is not. `block list` names the labels this takes and cannot enumerate — unscoped over a long ledger, this prints the whole file.

ArgumentNotesWhat it is
--block BLOCKonly this block, e.g. C
--role ROLEdefault "roadmap"which governed file (default: roadmap)
--jsondefault falsemachine-readable form
--marker, --status MARKERonly this status marker
--idsdefault falseprint ids alone, one per line
--have REQUIREMENTrepeatable; default []declare a requirement this caller has, repeatable: an open line naming anything undeclared counts as waiting rather than as startable

stats

Reads.

Count the file. Every count carries the number of marker-bearing lines it could *not* read, printed even when it is zero: a grep reports the remainder with no indication that anything is missing. Where the project declares `[requirements]`, the open count is split into what nothing absent is holding up and what the rest are waiting for.

ArgumentNotesWhat it is
--block BLOCKonly this block, e.g. C
--role ROLEdefault "roadmap"which governed file (default: roadmap)
--jsondefault falsemachine-readable form
--have REQUIREMENTrepeatable; default []declare a requirement this caller has, repeatable: an open line naming anything undeclared counts as waiting rather than as startable

audit

Reads.

Print the misses. This is what makes a count trustable rather than an extra: exit stays 0, because reporting is not the gate (`lint`, RK14) — an audit that failed a build would be a gate nobody could adopt first.

ArgumentNotesWhat it is
--block BLOCKonly this block, e.g. C
--role ROLEdefault "roadmap"which governed file (default: roadmap)
--jsondefault falsemachine-readable form

claims

Reads — and writes when --prune is given. Served to an agent as claims.

List the claim registry against the roadmap: held, expired — stepped over, so the line is offered again — or stale, meaning the marker moved and nothing reads the entry. Ranks nothing and offers nothing: `pick` decides what to work on, and the release is a marker.

ArgumentNotesWhat it is
--prunedefault falsedrop the rows that are not claims and keep the ones that are, which is the reconciliation a marker write performs and the only other remedy is the file
--jsondefault falsemachine-readable form

claim

Reads — and writes when --path--add-path is given. Served to an agent as scope.

Say which paths this task will touch, and read them back at the moment of committing. Without --path it answers what was declared, plus what the tree holds that another live claim says is its own — the analysis `git add -A` cannot make. Declared verbatim: nothing here reads the disk or the task's prose to guess a path, and nothing here dates a claim.

ArgumentNotesWhat it is
idrequiredthe task id, which a live claim must already hold
--path PATHrepeatable; default []a path this task's commit owns, repeatable; replaces the whole scope, so a correction is one call and not a file to edit
--add-path PATHrepeatable; default []a path this task's commit *also* owns, repeatable; keeps what was declared, so a file the work turned up is one argument and not the whole scope again
--porcelaindefault falsethe paths alone, one per line — what a commit script feeds to `git add --`
--jsondefault falsemachine-readable form

writes

Reads. Served to an agent as writes.

Read the write record against the files: attested — the bytes a verb left — unattested, meaning something else produced them, or unrecorded, meaning no verb has run here yet. Moves no baseline, so asking twice answers twice; the `Stop` hook states it once and consumes it (RK175).

ArgumentNotesWhat it is
--jsondefault falsemachine-readable form

unclosed

Reads. Served to an agent as unclosed.

Which open lines already have commits naming them, and no ledger entry. A session that shipped the code and forgot the line leaves a state `gaps` cannot see — that verb explains an id in neither file, and this one is in the roadmap — and `origin` answers one id at a time, so it is a confirmation and never a discovery. The commit that *filed* each id is dropped: `add` mints the id, so nothing could name one before the line existed. A report and never a gate: work under way is exactly this shape, and what a partial landing wants is `ship --part`.

ArgumentNotesWhat it is
--jsondefault falsemachine-readable form

brief

Reads — and writes when --claim is given. Served to an agent as claimbrief.

Compose the line, its rationale, its resolved deps, the blocker chain, what shipping it unblocks and the non-goals that bind it. With no id, briefs whatever `pick` would choose, which makes the first call the only one.

ArgumentNotesWhat it is
idthe task; omitted, `pick` chooses it
--block BLOCKscope the pick to one block, e.g. C (only without an id)
--designeddefault falseoffer only work whose design is written, setting aside the markers `[markers] undesigned` names (only without an id)
--have REQUIREMENTrepeatable; default []declare a requirement this caller has, repeatable: a ready line whose `(requires: …)` names anything undeclared is set aside and named, never offered (only without an id)
--claimdefault falsetake the line as well as describing it: the marker moves to in-progress in the same transaction, and a named id another worker holds is refused
--jsondefault falsemachine-readable form

budget

Reads. Served to an agent as budget.

Report what a line leaves its prose fields, derived from the id, the marker, the deps and the pointer — all known before the first word. The drafts (--symptom, --why, --body) are measured, never composed, and exit 1 when over: the refusal, without the write.

ArgumentNotesWhat it is
idan existing line, e.g. RK12 — omitted, the line `add` would write next
--block BLOCKdefault ""the block the line would be filed under, e.g. B
--dep DEPrepeatable; default []a dep the line would carry, repeatable: the group is what moves the number
--requires REQUIREMENTrepeatable; default []a requirement the line would carry, repeatable: `add` puts it on the line
--status, --marker STATUSthe marker the line would carry (default: the first declared)
--symptom SYMPTOMdefault ""the symptom, drafted or written: what it takes is what the why loses
--why WHYa draft of the why, measured against its allowance instead of refused by it; '-' reads stdin, which is how an apostrophe or a backtick survives a shell
--prefix FAMILYcount the derived id in this track (default: the first declared)
--ref REFthe anchor the line would point at, for ref_scheme = 'outline' only: the pointer is structure, so unnamed the budget assumes the widest on file
--anchor ANCHORa section, e.g. RK12: what its body may say in words, and what it spends
--role ROLEone of improvements, strategy, decisionswhich prose file --anchor is priced against (default: the one holding it)
--body, --section-body BODYa draft body: what it costs the section this call is about; '-' reads stdin, which is how an apostrophe or a backtick survives a shell
--body-file, --section-body-file PATHread the draft body from a file instead, with --anchor
--retire SUPERSEDED_BYwhat a retirement's reason has — bare, abandoned; named, superseded by that id, which costs more of the field
--shipdefault falseprice the sentence a `ship` writes instead of this line's: the ledger's limit, which is a different number
--non-goaldefault falsethe two limits `non-goal add` enforces, which are the list's own
--lead LEADa non-goal that exists, with --non-goal: what its reason has left
--file PATHan every-turn file `[budgets]` declares, e.g. agents.md: what it costs and what is left — bare, every declared budget
--jsondefault falsemachine-readable form

cost

Reads. Served to an agent as cost.

Report what a caller already pays: the tool list once at connect, the files loaded on every turn, and what the read that replaces opening a file costs a tool result. `budget` is the other tense — what a write may spend before a word of it exists. Reads; never writes.

ArgumentNotesWhat it is
--tools TOOLwhat the tool list costs a session — bare, every tool ranked; named, e.g. ship, what each of that one's fields spent
--brief IDwhat a brief costs a tool result — bare, every open line, widest first
--sessiondefault falsewhat one session pays: the served schema once at connect and every `[budgets]` file each turn, against the cadence of each
--skilldefault falsewhat the write path costs the turns that load it
--denydefault falsewhat one refused write costs the session that meets it
--jsondefault falsemachine-readable form

show

Reads. Served to an agent as show.

Join what a task is out of the files that hold a piece of it. Nothing is stored to make this possible: the section is found by the pointer, and a pointer that resolves to nothing is reported as the absence it is.

ArgumentNotesWhat it is
idrequiredthe task, e.g. RK12
--no-bodydefault falseomit the section's prose, keeping the line and where the prose is
--jsondefault falsemachine-readable form

pick

Reads — and writes when --claim is given. Served to an agent as pick.

Apply three tiers — work already in progress, the declared priority, then the lowest ready id — and print which one answered. A task blocked outside the backlog is never offered: shipping cannot unblock it.

ArgumentNotesWhat it is
--block BLOCKscope every part of the answer to one block, so 'nothing to pick' is a statement about that block and not about a lower id somewhere else
--designeddefault falseoffer only work whose design is written, setting aside the markers `[markers] undesigned` names (only without an id)
--have REQUIREMENTrepeatable; default []declare a requirement this caller has, repeatable: a ready line whose `(requires: …)` names anything undeclared is set aside and named, never offered (only without an id)
--claimdefault falsetake the line as well as read it: the marker moves to in-progress in the same transaction, so the next caller is answered with something else
--jsondefault falsethe pick, the tier and the counts

export

Writes.

Derive what another file would restate: counts per block and the next ready line. Idempotent and stamped with nothing, so a refresh with nothing to say makes no diff — and every character of content already passed `add`.

ArgumentNotesWhat it is
--readme PATHwrite the block between the roadkeep markers in this file (default README.md)
--site PATHthe same projection as HTML, between the same two markers (default docs/index.html)
--contentsdefault falserefresh the table of contents inside this project's rationale file, between the same two markers: every row is a heading that file already carries, so a `ship` that drops a section leaves the list wrong until this runs. Takes no path — the target is `[files]`' own
--spec IDone task as a document: its claim, what it depends on, what would finish it, the non-goals that bind it and its design section whole. `brief` is the same join bounded to a tool result; this one is bounded by a file, for a reviewer, a second agent or a CI job that cannot run the read
--jsondefault falsethe payload a site build reads

gaps

Reads. Served to an agent as gaps.

Every id below the highest that no line carries. Each resolves to the commit whose message holds the decision, to 'never carried' when a complete history mentions it nowhere, or to 'unresolvable' when there is no history to search — three different answers from 'retired', none of them a weaker one.

ArgumentNotesWhat it is
--jsondefault falsemachine-readable form

govern

Writes. Served to an agent as govern.

Take the reading and write the number in one call. `[limits]`, `[budgets]`, `[tools]` and `[claims]` hold the values that are a judgement about a figure, and each already had the read that decides it somewhere else. With no value it prints the reading alone. A limit this project already breaks is refused rather than written. Why this number and not the next is yours to write and this verb's to place: `--because` stacks your sentence above the key, and `--instead` replaces the argument standing there, for a reading that has moved.

ArgumentNotesWhat it is
keyrequiredthe address, as `config` prints one — e.g. limits.symptom, tools.session
atthe number to declare; omitted, the reading is printed and nothing is written
--role ROLEwhich role's limits, for a `[limits.<role>]` table (default: the shared one)
--file FILEwhich every-turn file, for a `[budgets]` entry — the path the config spells
--because BECAUSEdefault ""your argument for this number, wrapped into comments above the key
--instead INSTEADdefault ""the same sentence, replacing the run above the key instead of stacking on it; the answer names every line it took out
--jsondefault falsemachine-readable form

config

Reads. Served to an agent as config.

Print the shape of this project's own configuration, answered by the package that refuses everything else (RK1270). One row per key — its table, its type, what this build uses when nobody declares it, and whether this project did — with the sentence the source already carries above each table. What is listed is what *this* copy accepts, which is how a key it predates is told from a typo, so the build that answered is named. Last, what this build *fixes* from its own corpus and no project declares, with the reading behind it. It reads and never writes.

ArgumentNotesWhat it is
--table TABLEone table, spelled as the answer spells it — omitted, every one; the top level is the empty string, and a table declared per role or per path carries the placeholder, e.g. rules.<role>
--jsondefault falsemachine-readable form

commands

Reads.

Print this build's own command surface as data (RK1401). One block per verb — whether it reads or writes, the flag that turns a read into a write, and one row per argument with its spellings, what it takes, its default and the sentence the parser already carries — plus which tool an agent is served it as, and which of its arguments that surface exposes on *this* project. `config` answers what roadkeep.toml may declare; this answers what may be typed. What is listed is what *this* copy takes, so the build that answered is named. It reads and never writes.

ArgumentNotesWhat it is
--command VERBone verb, spelled as the answer spells it — omitted, every one; a nested one carries its path, e.g. 'section add'
--jsondefault falsemachine-readable form

anchors

Reads. Served to an agent as anchors.

Read the anchors out of every declared prose file and out of its diffs: live ones a heading declares now, and retired ones a ship deleted while every entry citing them stayed. An address is spent once a heading used it (RK4's rule for ids), so this is the read that says which number a reopened family may take — and which top-level is free, which is what a reused block needs.

ArgumentNotesWhat it is
--family ANCHORdefault ""only this subtree, e.g. XXXVII — omitted, one row per top-level family
--block LABELdefault ""the subtree this block's prose already lives under, e.g. Q — the address a caller knows, since a prose file under an outline declares no block heading; refused with --family, and names both where a block spans two families
--role ROLEdefault ""list only this prose file's addresses (default: every declared one) — the free top-level is per namespace, so it stays the project's where no [refs] declares one and is that file's own where one does
--nextdefault falsethe free address alone, without the listing of spent ones — the `next-id` of anchors, and the read an `add --ref` makes every time
--claimsdefault falseonly the addresses whose ownership is not the ordinary one: a heading binding nobody, and one binding a task no open line claims — the audit, over every family at once, since the rows it leaves out are the ones nobody reads
--retireddefault falselist the retired addresses too, which the wide listing counts and withholds
--jsondefault falsemachine-readable form

deps

Reads. Served to an agent as deps.

Resolve each dep against the roadmap and the changelog. A dep nothing now open will satisfy is reported as unresolvable rather than open — work outside the backlog, a task that retired, and a block label with nothing filed under it.

ArgumentNotesWhat it is
idrequiredthe task to resolve, e.g. RK5
--jsondefault falsemachine-readable form

origin

Reads. Served to an agent as origin.

Resolve a task's history from git. The pointer is derived, never stored: a hash written into the ledger would be rewritten by the first squash or amend, and a dead hash reads exactly like a live one. A leading § asks the same question of a rationale anchor instead — the dangling cross-reference a ship leaves in somebody else's prose, which no file records the answer to.

ArgumentNotesWhat it is
idrequiredthe task to look up, e.g. RK1 — or §<anchor>, as the prose spells it
--whydefault falseprint the shipping commit's full message — the rationale the ledger drops
--jsondefault falsemachine-readable form

weight

Reads. Served to an agent as weight.

What a comparable task cost, so granularity is a query instead of a feel: a block whose last comparables shipped at 800+ lines is a block where the next line is probably two lines. Derived from the commit that wrote each ledger entry, so nothing stores it and `git show` refutes it. Two axes and no score — median to p90 lines vary 2.7× here and files, which is what an agent holds in context, 1.4×. An entry whose commit wrote several is named and left out rather than given a share of it, a divided cost being one no commit contains. This ranks nothing: every tier of `pick` is a fact, and a cheapness tier would defer the architectural tasks, which is where the leverage is.

ArgumentNotesWhat it is
--block BLOCKonly this block's comparables, e.g. C
--recordsdefault falseevery weighed entry, which the percentiles summarise: the evidence for the figure, wanted when you dispute it and not when you are sizing a line (RK264)
--jsondefault falsemachine-readable form

remaining

Reads. Served to an agent as remaining.

The mirror of `weight`, and derived the same way (RK492): that one says what a comparable task cost, from the commits that shipped it, and this says what one has left, from the repository as it is now. A migration declares the query in its rationale section — a fenced `roadkeep-remaining` block, one `<pathspec> :: <regex>` per line — and this runs it. Nothing is stored, so nothing goes stale: the first commit that closes a site changes the answer, which a number written onto a line could not. It is a count and never a verdict — the pattern is the author's, so a query answering 0 says the pattern stopped matching, and whether that is the work being done is a judgement this tool does not make.

ArgumentNotesWhat it is
idrequiredthe task whose design declares the query, e.g. RK12
--jsondefault falsemachine-readable form

evidence

Reads. Served to an agent as evidence.

Run the criterion a design declares, against this tree, now. `remaining` with the sign flipped: a `roadkeep-evidence` fenced block names sites that must **exist** where the other names sites still to change, and both are one `<pathspec> :: <regex>` per line read by one grammar. Never a verdict — the pattern is the author's claim and the count is the answer, so 0 says the evidence is not there yet and whether that is the work being done is yours to judge. Nothing is stored, so nothing goes stale.

ArgumentNotesWhat it is
idrequiredthe task whose design declares the criterion
--jsondefault falsemachine-readable form