Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions .agents/skills/proof/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ Critical semantics:
`superseded_by` and `invalidated_by` reverse projections; `derives_from`
writes no reverse edge.
- External sources: create a `WriteCitation` record (its body may be a URL,
with optional `blob` and `role` fields), then add
with optional `blob` and `role` fields; `role: code` with a body such as
`src/a.ts#symbol@sha` ties the citing records to that code for
`proof find --path`), then add
`cites: ["<cit-id>"]` when creating an Issue, Finding, Decision,
Constraint, or Risk. Both the Citation in `cites` and the Blob in
`Citation.blob` must belong to the same Effort as the record that links to
Expand Down Expand Up @@ -194,7 +196,23 @@ Pick the read by what you need, in this order:
3. **Read one record in full: `proof get <id>`.** On a compaction, `get`
also says whether it is stale, and why, gives the exact number of
records that changed since it was written, and lists up to 25 of them.
4. **Page through records: `proof records`.** `find` shows only the top
4. **Before opening code: `proof find --path <file|dir|symbol>`.** It
lists the records that govern that code, each at its chain head, with a
`via:` line naming the tie: a code Citation (`role: code`, body
`src/a.ts#symbol@sha`) the record cites, a commit touching the path with
a `Proof: <id>` trailer, or a body that names the path. Add words to
rank them. Run it before you change a file, so you build on the accepted
Decisions and Constraints instead of crawling the codebase or the graph.
5. **Before building on a Decision: `proof find --refs all`.** It overlays
the Proof records other branches change, without a checkout, tags each
card `main`, `only on <ref>`, or `differs on <ref>: <here> vs <there>`
(with the draft PR when `proof branches --refresh-prs` has run), and ends
with a `CONFLICTS` block: two accepted Decisions on one question, one
Issue resolved two ways, a record superseded twice, a state two branches changed differently, a
retraction of something another branch relies on, two head compactions.
Without words it lists what the branches propose. It composes with
`--path` and `--effort`.
6. **Page through records: `proof records`.** `find` shows only the top
hits, so never count from it; count from `state`. `--state` and
`--status` match only the stored field. `--standing invalidated` (or
`superseded`, `retracted`, any standing a card prints) lists records by
Expand All @@ -213,6 +231,14 @@ byte cap). Zoom in with `get`, then Read/grep that digest — do not open
flatbread proof find "tern history buffer precision" --effort <effortId>
flatbread proof find "shadow pool overflow" --as-of 2026-03-01T00:00:00Z

# The records that govern a file, folder, or symbol, before you open it
flatbread proof find --path src/render/shadows.ts
flatbread proof find "pool size" --path src/render/shadows.ts#allocate

# What other branches propose, and where they conflict, without a checkout
flatbread proof find --refs all --effort <effortId>
flatbread proof find "shadow pool" --refs feat/pool-v2,origin/feat/atlas

# Counts, open blockers, Risks, contested topics, dead evidence, lifecycles
flatbread proof state <effortId>

Expand Down Expand Up @@ -273,7 +299,10 @@ server-side.
`dec-adopt-a-bounded-status-briefing-fast-path-for-ef--kcw0rw39g3b2ym2h`).
2. **When you need a particular record or fact:** run `proof find` first,
then `proof get` the hit whose card fits. Do not page through `records`
to look for it. **When you need a count, a list of open, closed, or
to look for it. **When you are about to change code:** run
`proof find --path <file>` first. **When you are about to build on a
Decision, or accept one:** run `proof find --refs all` (scoped with
`--effort`) and read its `CONFLICTS` block. **When you need a count, a list of open, closed, or
rejected records, a status history, the blockers, or what rests on dead
evidence:** run `proof state <effortId>` instead.
3. **When a browse digest shows `[…truncated]` and you need the body:** run
Expand Down
119 changes: 118 additions & 1 deletion .agents/skills/proof/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ flatbread proof relations <effortId> <fromId> --relations r1,r2 [--limit n] [--c
flatbread proof blocking-decisions <effortId> [consistency flags]
flatbread proof brief <effortId> [consistency flags]
flatbread proof find "<words>" [--effort <effortId> | --all] [--kinds k1,k2] [--as-of iso] [--retracted exclude|include|only] [--limit n] [consistency flags]
flatbread proof find ["<words>"] --path <file|dir|symbol|file#symbol> [--refs r1,r2|all] [find flags]
flatbread proof find ["<words>"] --refs <r1,r2|all> [find flags]
flatbread proof branches [--refresh-prs]
flatbread proof state <effortId> [consistency flags]
flatbread proof cache prune
flatbread proof serve [--socket .flatbread/proof/serve.sock]
Expand Down Expand Up @@ -420,9 +423,123 @@ Each card has these lines:
```

The card header reads `find "<words>" in <effortId|all Efforts> (<searched> records searched, <matched> matched, <shown> shown)`, then `matched: … | missing: …`. The envelope adds `cards` (that Markdown) and `find`:
`{"query","effort_id","searched","matched","shown","terms":{"matched","missing"},"efforts"?,"hits":[{"id","matched_id"?,"score"}]}`.
`{"query","effort_id","searched","matched","shown","terms":{"matched","missing"},"efforts"?,"hits":[{"id","matched_id"?,"score","via"?,"branch"?}],"path"?,"refs"?,"conflicts"?,"conflicts_total"?}`.
`find` shows only the top hits; use `state` or `records` to count.

### `proof find --path`: the records that govern a piece of code

`--path <target>` returns the records that govern that code, without
reading the code or the whole graph. Words are optional. The target is a
file or folder (relative to the current folder when it exists there, else
to the repository root), a symbol (`startFrame`, `startFrame()`,
`Planner.plan`), or both (`src/fuse.ts#budget`). A folder matches the files
under it. The repository root itself (`.`) is refused. Three sources tie a record to code, strongest first:

1. **Code Citations:** a Citation with `role: code` whose body names the
code as `<path>`, `<path>#<symbol>`, or `<path>#<symbol>@<sha>`. The
records that cite it govern the code, and so do the records it
`derives_from`; a code Citation nothing cites stands for itself. A file
anchor with no symbol covers every symbol in the file. Write one when a
Decision or Constraint is about specific code:
`{"type":"WriteCitation","effort":"<eff-id>","title":"Fuse budget","body":"src/fuse.ts#budget@1a2b3c4","role":"code"}`,
then put its id in the record's `cites`.
2. **Commit trailers:** commits that touch the path and carry one or more
`Proof: <id>` trailers (`git log` from the Proof root's repository;
skipped quietly outside git, and for a bare symbol).
3. **Body text:** a record body that names the path as a whole token
(`src/a.ts` does not match `src/a.tsx`), or the symbol as `name(`,
`obj.name(`, or `#name`.

Each governed record resolves to its chain head, as `find` shows chains;
retracted records follow `--retracted`. With words, BM25 ranks the
governed set (records no word matches still list, after the matches).
Without words, the strongest tie ranks them, then the newest; the header
drops `score` and the `matched:` line. Default 5 cards, `--limit` up to 10.
Each card adds, after its title:

```text
via: cites <cit-id>: src/fuse.ts#budget@1a2b3c4; commit 1a2b3c4 "<subject>" (on <older version id>); body names src/fuse.ts
```

The header reads `find ["<words>"] --path <target> in <scope> (<n> governing, <shown> shown)`.

### `proof find --refs`: what other branches propose

`--refs feat/a,origin/feat/b` or `--refs all` overlays records from other
git refs without checking them out (`git ls-tree` and `git cat-file`,
cached by commit). No git command it runs fetches: in a partial clone, a
record whose blob is not on disk is left out, and the `refs:` line says
`N records not available locally`. `all` skips local and remote branches
whose Proof folder HEAD's history already had, looks at the 50 others with
the newest commits (the `refs:` line says so when there are more), and
keeps those that change a Proof record, at most 12. Of a local branch and
its remote-tracking ref, `all` keeps only the newer one when one contains
the other. A ref counts only for the records it changed since its merge
base with HEAD, so a branch that is merely behind adds nothing, and a
version already in HEAD's history does not count, so a branch left behind
after a squash merge adds nothing. When two refs hold different versions
of a record and one is the version at the two refs' own merge base, as
with a branch stacked on another, the older version is dropped. With no
merge base (a shallow clone), HEAD stands in for it, the `refs:` line says
`no merge base: shallow clone?`, and `git fetch --deepen=200` finds one.
The base is the working tree. In the combined graph, supersession and invalidation come
from the forward edges (`supersedes`, `invalidates`) of every version; the
stored `superseded_by` and `invalidated_by` on either side are ignored. An
Issue's `resolved_by` is the union over every version, so a Decision that
resolves a question only on a branch still shows `in: resolves`. With
words, `find` searches the combined graph; without words or `--path`, the
cards are the records the refs add or change, newest first. Each card adds
a `branch:` line:

```text
branch: main (same as the working tree)
branch: only on feat/a (draft #12 by ana) (draft PR from prs.json)
branch: differs on feat/a: proposed vs accepted (<base standing> vs <ref standing>)
branch: deleted on feat/a (the ref removed the record file)
branch: only on feat/b; rival heads: <id> (only on feat/a)
```

The last form is a chain that two branches each supersede: the chain line
marks every head `(head)`, and no head replaces the other.

A `refs:` line after the header names each ref, its commit, and how many
records it adds, changes, or deletes (Efforts counted apart). The cards end
with `CONFLICTS (<n>)` and one `- ` line each (at most 12, then
`+n more`), or `CONFLICTS: none`. With `--effort`,
only that Effort's conflicts show. A conflict names its refs (`base` is the
working tree) and ids:

- two accepted Decisions on one question Issue, tied to it by
`derives_from` or by the Issue's `resolved_by` on any side (a ref that
accepted one and rejected the base's accepted one is a proposal, not a
conflict);
- one Issue resolved by different records on two sides, when the line
above does not already name it;
- one record superseded by two different records;
- one id with a different stored `state` or `status` on two sides that
both changed it since they split (a change only one ref made shows on its
card's `branch:` line instead);
- a retraction on one side of a record another side relies on
(`derives_from`, `cites`, `evidence`), when that side added or changed
the relying record since they split;
- two head compactions for one Effort.

`--refs` composes with `--path`, `--effort`, and `--all`; with `--path`,
commit trailers on the refs count too. The envelope's `find` adds `refs`
(`[{"name","sha","changed","pr"?}]`), `conflicts` (the same 12 the cards
list), and `conflicts_total`. Narrow with `--effort` or fewer refs to see
the rest.

`proof branches` lists the refs `--refs all` would overlay, with their
pull requests. Pull requests come from a gitignored
`.flatbread/proof/prs.json` (an array of
`{number, headRefName, isDraft, author}`). A ref matches a pull request
whose `headRefName` is its branch, or is its branch with a remote name in
front (`origin/feat/a`). `proof branches --refresh-prs`
rewrites it from `gh pr list --json number,headRefName,isDraft,author`, the
only step that uses the network; it fails with a plain message when `gh` is
missing or not signed in, and warns when the file is not gitignored.

### `proof state`

`state` shows where one Effort stands, in one read of at most about 4,000
Expand Down
4 changes: 3 additions & 1 deletion packages/flatbread/bin/flatbread.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ function loadCli() {
}

// Reads `flatbread proof serve` answers. Keep in step with SERVED_READS in
// src/cli/serve.ts; anything else, writes included, runs locally.
// src/cli/serve.ts; anything else, writes included, runs locally. Options
// are forwarded as given, so `find --path` and `find --refs` are served too.
// `proof branches` runs locally: `--refresh-prs` calls gh and writes a file.
const SERVED_READS = new Set([
'list',
'records',
Expand Down
Loading
Loading