gy 0.5.1

good,yes — the ledger of what work rests on before a requirement is confirmed
gy-0.5.1 is not a library.

gy — good,yes

English | 日本語

gy records the state before a requirement is confirmed. It holds the needs, questions, decisions, requirements, and acceptance criteria that a piece of work rests on, as a graph of nodes and edges, with one way to use it and almost nothing to configure. Agents write it as they work, and publish writes the record to a file that is committed and read back later. The canonical ledger lives outside the repository, and gy makes no network calls.

What gy is for

Work handed to an agent does not need to be read while it goes well. Because it is not read, it stops being read. How far the work gets then depends on how much fits in the context window, how large the target is, and how strong the model is, and none of that shows while things go well.

It shows at the end. A requirement has to be declared complete. A decision that earlier work relied on has been replaced without anyone noticing. Leftover work has to go somewhere. And the one person accountable is holding several projects at once and cannot read them all. None of the four happens while things go well. When one does, nobody remembers what the work was based on.

gy exists for that end. It holds no plan and no schedule. It records what each piece of work rests on and what must hold before the work can be called done, and it reports where those records contradict each other. There is no lint pass to run later: an invalid write is refused when it is made, and what needs attention is counted by handover.

The five nodes and twelve edges

There are five kinds of node. Four of them form a ring that follows one turn of the work: a decision spawns needs, a need is filed as a requirement, the work raises questions, and a question closes as the next decision. The fifth kind, the acceptance criterion, measures the work from outside the ring.

Node ID Meaning
need n-… Work that must be done, aimed at acceptance criteria
question q-… Something undecided, with a decider and at least two options
decision d-… A decision with the conditions under which it applies
requirement r-… A need turned into an approval request, with an outward reference
criterion ac-… An acceptance criterion that work is counted against

Edges are stored on the node they start from; the reverse direction is derived, never written twice. An edge is one of twelve relations, and each relation is only allowed between the kinds shown here.

From → to Relation Reverse
question → decision closes closed-by
decision → decision narrows, widens, supersedes, completes narrowed-by, widened-by, superseded-by, completed-by
need, requirement → criterion targets targeted-by
need → decision spawned-by spawns
need → requirement filed-as files
need → need depends-on depended-on-by
requirement → decision relies-on relied-on-by
requirement → question raised raised-by
need → question, requirement waits-on awaited-by

A decision is stored with its applicability conditions, so a later reader can tell where it does and does not hold. narrows and supersedes also name the passage of the older decision that loses effect; the mark is checked against that decision's text when the edge is written.

How a requirement moves

A requirement has four states: filed (registered), approved (design confirmed), done (shipped), and cancelled. Approval, revision, completion, and cancellation are each one command that records who heard the design, the evidence, and the reason, and every other transition is refused.

From To Command
filed approved req approve
approved filed req revise
approved done req done
filed, approved cancelled req cancel

gy holds nothing about the work after approval except these four records. Where the implementation is tracked, how it is designed, and when it is audited belong outside gy, in the issue and pull request that the requirement's reference points at.

Where the ledger lives

The canonical ledger is an append-only event log outside the repository, under $XDG_DATA_HOME/gy/<hash of the repository root>/. The repository itself holds only gy.toml. Every write is one transaction appended to the log with the sequence number, time, actor, reason, and source; nothing is edited in place.

undo --reason <text> inverts the last transaction as a new one, so the history keeps both the mistake and the correction. The log is the ledger; a snapshot file alongside it only speeds up opening and can be deleted.

The twenty operations

Reads (5):

Operation Result
show <ID|ref>... [--full] One or more nodes by ID, alias, or reference, with what each still lacks
list [--type] [--status] [--targets] [--grep] [--actor] [--since] Node rows, or write units when --actor or --since is given
next The needs whose prerequisites are settled
handover In-progress requirements and the counts a session needs to resume
publish [--scope] [--since] [--out] Write the record at a point and range: every node verbatim, the write history, and the diagnostics

Writes (15):

Operation Result
need add "<title>" --targets <AC>... [--spawned-by <D>] File a need against acceptance criteria
need close <ID> --by fact|external --evidence <text> Close a need without a requirement
question add "<title>" --decider <name> --options <text>... Open a question with a decider and at least two options
question close <ID> --by fact|decision|non-decision --evidence <text> [--decision <D>] Close a question and, when decided, record the decision
criterion add "<title>" Add an acceptance criterion
criterion satisfy <AC> --evidence <text> [--revoke] Record that a criterion holds, or revoke it
req add "<title>" --need <N>... [--relies-on <D>]... [--targets <AC>]... [--ref <ref>] File a requirement against needs, decisions, and criteria
req approve <ID|ref> --design <text> --heard-by <name> --evidence <text> Confirm the design of a requirement
req revise <ID> --reason <text> --source <text> Send an approved requirement back to filed
req done <ID> --evidence <text> Record that an approved requirement shipped
req cancel <ID> --reason <text> --source <text> Cancel a requirement that was not done
decide "<title>" --scope-note <text> [--body-file <path>] [--closes <Q>]... [--relate <relation> <D> --mark <text>] Create a decision, close questions, and record one lineage edge
link <from> <relation> <to> [--mark <text>] [--remove] Add or remove one edge
edit <ID> --reason <text> [--title] [--body-file] [--set k=v] [--append k=v] Change a node's title, body, or free attributes
undo --reason <text> Invert the last transaction

Every write prints what it changed, what the node still lacks, and the shape of the command that could come next, so the next step is visible without a separate instruction sheet. Pass --json for the same content as data.

Resuming a session

A new session starts with three commands. handover shows the in-progress requirements with their references, the number of open questions, the number of ready needs, and the errors and warning counts. next lists the needs whose prerequisites are settled, and the agent presents one of them to the master. show reads one node in full.

gy handover
gy next
gy show n-3f9a

gy.toml

The only configuration is a scope name and, if wanted, an output path for publish. Anything else is refused when the file is read.

[scopes.myproject]

# Optional. publish writes here when --out is not given.
output = "docs/gy.md"

Reads cover every scope. A write needs a scope only when the file names more than one; pass --scope <name> to choose. The first write creates the ledger, and reads never do.

Who writes

Every write names its actor in GY_ACTOR. An unset or blank value is an error, and the name is kept in the history beside the reason and source.

export GY_ACTOR=leader

Each agent writes its own records with its own name, so the history shows who changed what and why.

IDs, aliases, and refs

gy allocates each ID itself, as a kind prefix and a short hash, such as n-3f9a. No counter is shared, so two agents writing at once cannot collide; a collision just mints a longer hash. show also accepts a zero-padded ID, an alias, or a requirement's outward reference by exact or suffix match.

An existing ledger keeps its old IDs as aliases, so show D-164 and show '#6027' both reach the renamed node. A requirement's reference (--ref) is opaque: gy stores it and never reads what it points at.

publish

publish writes the ledger at a point and range as one Markdown file to commit. It is a development artifact: later, an agent reads it to review what was decided and why, and diffs one publication against the next. It is not a reading for the master, and gy adds no human-facing output format.

The file holds the generated time, the log sequence, the scope and range, the writer, and the canonical location; a short "how to read" section; every node in range verbatim (IDs with aliases and references, titles, scope, creation date, state, applicability conditions, body, both edge directions with marks, closure and evidence, requirement records, and free attributes); the write history; and the diagnostics. Every reference carries the target's title, so the document stands on its own without the ledger.

--out writes to a path, gy.toml's output names a default, and without either it goes to standard output. {seq} in the path becomes the write sequence, so docs/publication/{seq}.md keeps one file per publication.

Install

cargo install gy --locked

From a checkout, run cargo install --path crates/gy --locked. The binary is gy.

Coming from 0.4, move the ledger with gy-migrate; see docs/migration-0.5.md.

Development

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test --workspace --locked

The workspace holds gy-ledger (the store, model, and operations) and gy (the CLI). gy-migrate and its private gy-core reader stay until the remaining 0.4 ledgers have moved, then are removed. CI tests on Linux; other platforms are unverified.