OKF Explorer

Drag to orbit · scroll to zoom · click a concept to focus & fly in · Esc to reset. Neighbors brighten; distance dims.

Concepts

  • Cells — the coverage modelconcepts/concept-cell A cell is one sparse, evidence-asserted point in a declared quality space — proof read backward, roadmap read forward. Covers pack, dimension, member, state/grade, gate, evidence.
  • Dependencies — what depends-on asserts, and which end you start fromconcepts/concept-dependency depends-on and blocks are two independent task-reference lists. An edge is stored on the DEPENDENT and names its prerequisite; query graph reads them as a DAG to report cycles, the critical path, and which tasks are ready to start.
  • Dimensions and membersconcepts/concept-dimension A dimension is one quality axis; members are its enumerated values. Dimensions group into families with applicability, and are closed or open. Effective set = pack ⊕ project-declared layer.
  • Graphs — authored process, enacted on the ledgerconcepts/concept-graph A graph-def is the authored, versioned shape of a repeatable process; a graph-run-case is one event-sourced enactment of it on the real ledger. Definitions are sound by construction and composable; runs carry write-once evidence and a reproducibility pin.
  • Methodology catalog — the orientation boardconcepts/concept-methodology-catalog The orientation board for the coverage pack: the 6-facet methodology contract (Procedure · Best practices · Tools · Current approaches · Evaluation · Hardened evidence bar), a family-by-family map of all 88 dimensions, and worked exemplars — what you could/should do for a dimension to be properly considered, and the evidence-quality bar a hardened grade demands.
  • Milestones and Definition of Doneconcepts/concept-milestone-dod Milestones are a staged hypothesis ladder; a Definition of Done declares the grade floor a project must reach. Together they give board next its verdict line.
  • The shipped convention — coverage as dataconcepts/concept-pack Coverage is the one convention lettuce ships: its states, transitions, gates, dimensions, and families are data, not code. Every project runs it by default; you inspect it and tune it per project — you do not swap it.
  • The plain format — what --format plain emits, and when it emits the whole objectconcepts/concept-plain-format plain is the scriptable surface: one primary reference per line. Two rules decide what a command emits — an EXPLICIT projection renders the requested columns instead (LET-909), and an object with no primary reference has nothing to collapse to. Both are keyed on the command and its flags, never on the data.
  • Querying with FQLconcepts/concept-query FQL reads the store: from SOURCE where EXPR select fields order/limit. Sources include tasks, events, cells; the cells source exposes DoD-derived axes (freshness, depth, dod).
  • Scopes — the DoD/board partitionconcepts/concept-scope scope is a reserved dimension that partitions the coverage board and Definition of Done. Cells without a scope fall into the synthetic unscoped bucket, never silently outside the DoD frame.
  • The store and the two data planesconcepts/concept-store The store is a path-jailed root of ordinary validated files. Objects fall into two planes: Work (projects/tasks/leases/runs/artifacts) and Coverage (packs/dimensions/cells).
  • Tasks and the work planeconcepts/concept-task A task is the unit of work: created under a project, moved along validated workflow transitions, claimed with leases, and evidenced by runs and artifacts.
  • Workflow — states, transitions, and gatesconcepts/concept-workflow Workflow is the pack-supplied model of legal states and transitions for tasks and cells. Transitions are validated; gated transitions require a satisfied gate or explicit --facilitate.
  • Getting startedgetting-started Create your first lettuce store and task in fewer than five commands, then learn where to go next.
  • Running lettuce in autonomous agentic cyclesguides/guide-agentic-cycles Use the store as your loop — read forward it is the plan, written backward it is the proof. The orient→act→reflect→file cycle via board next, and the invariant that keeps it honest.
  • Agentic loop demo — one development cycle, step by stepguides/guide-agentic-loop-demo A single realistic dev loop worked end to end: at each orient→act→reflect→file step, exactly what the agent GETS from lettuce and what it DOES, with real commands and output.
  • Configuring lettuce for useful leverageguides/guide-config-for-leverage Wire lettuce into a real project so an agent gets maximum leverage: root/project/author resolution, the config precedence chain, pack selection, mode choice, author identity, saved queries, and DoD floors.
  • First contact — what a fresh agent sees, reads, and doesguides/guide-first-contact From zero prior context to productively driving lettuce: the exact first moves (skill, docs, usage, status, board), what each returns, and how the shipped default is the 88-dimension coverage taxonomy (with the smaller huru ladder available on request).
  • How to read lettuce — orienting in an existing storeguides/guide-how-to-read Before acting, an agent orients: board next for the frontier, FQL over tasks/cells/events, task show/audit, rollups and timelines, and the leading DoD verdict line — read machine-first with --format json.
  • Retrying a mutation safely: --idempotency-keyguides/guide-idempotent-mutations Make a retried mutation land at most once with --idempotency-key: which commands accept it, how a replay identifies itself, what a reused key with a different payload does, and why the record is runtime-only.
  • Project setup playbook — prepare a project to leverage lettuceguides/guide-project-setup-playbook Do-this-now setup: init and bootstrap, a decision procedure for designing YOUR scopes, choosing and ideating dimensions (with methodology), an evaluable Definition of Done via milestones and tickets, and a per-cycle hygiene checklist.
  • Serving lettuce safely (HTTP)guides/guide-server-security lettuce serve is fail-closed by design (ADR-0008): a non-loopback listener with no shared secret refuses to start. Covers the serve surface, bearer auth, per-actor identity, rate gates, IP allowlists, and what is safe to expose.
  • Driving lettuce from a file: structured external inputguides/guide-structured-external-input Supply command fields from a JSON or YAML envelope with --from-json / --from-yaml: the wrapper, what the envelope may not set, how it merges with CLI flags, how YAML scalars are converted, and the refusals you will actually hit.
  • indexindex reserved
  • What is lettuceoverview lettuce is a local-first, filesystem-native work tracker and coverage/quality store for humans, agents, and small teams — canonical state as ordinary validated files.
  • Authors And Projects — Commandsreference/cmd-authors-and-projects lettuce Authors And Projects commands — 15 entries — author add, author list, project create, project set-name, project rename, project merge, project list, project show, project archive, project unarchive, project delete, project id-block grant, project id-block list, project author add, project au
  • Cells — Commandsreference/cmd-cells lettuce Cells commands — 28 entries — cell list, cell rollup, cell evidence list, cell evidence add, cell evidence remove, cell gate check, cell show, cell set, cell clear, cell set-where, cell clear-where, cell note, cell import, cell transition, cell verify, cell affirm, board export, board next
  • Core And Runtime — Commandsreference/cmd-core-and-runtime lettuce Core And Runtime commands — 12 entries — usage, skill, docs, okf, version, init, status, validate, doctor, recover, cleanup, reconcile.
  • Coverage Grid — Commandsreference/cmd-coverage-grid lettuce Coverage Grid commands — 4 entries — grid scope add-unit, grid scope add-dim, grid scope show, grid show.
  • Definition Of Done — Commandsreference/cmd-definition-of-done lettuce Definition Of Done commands — 10 entries — dod set, dod clear, dod show, defaults show, defaults state declare, defaults state set-default, defaults state hide, defaults transition declare, defaults gate declare, defaults reset.
  • Graph Authoring — Commandsreference/cmd-graph-authoring lettuce Graph Authoring commands — 10 entries — graph-def create, graph-def revise, graph-def show, graph-def list, graph-def compile, graph-def lint, graph-def viz, graph-def catalog list, graph-def catalog show, graph-def use.
  • Graph Run-Cases — Commandsreference/cmd-graph-run-cases lettuce Graph Run-Cases commands — 12 entries — graph-run-case open, graph-run-case advance, graph-run-case close, graph-run-case abandon, graph-run-case show, graph-run-case viz, graph-run-case list, graph-run-case conform, graph-run-case refs-to, carrier produce, carrier list, carrier show.
  • Import Export Repair And Sync — Commandsreference/cmd-import-export-repair-and-sync lettuce Import Export Repair And Sync commands — 10 entries — export, import, repair plan, repair check, repair apply, repair automatic, sync status, sync push, sync pull, conflict bundle.
  • Queries — Commandsreference/cmd-queries lettuce Queries commands — 13 entries — query run, query search, query tasks, query audit, query timeline, query graph, query saved create, query saved update, query saved archive, query saved unarchive, query saved list, query saved show, query saved run.
  • Registries And Workflow — Commandsreference/cmd-registries-and-workflow lettuce Registries And Workflow commands — 14 entries — registry create, registry update, registry list, registry show, milestone create, milestone list, milestone show, milestone close, milestone reopen, milestone set-stage, workflow list, workflow show, workflow transition list, workflow revise.
  • Server And GitHub — Commandsreference/cmd-server-and-github lettuce Server And GitHub commands — 2 entries — serve, github init-repo.
  • Task Local Objects — Commandsreference/cmd-task-local-objects lettuce Task Local Objects commands — 35 entries — comment add, comment edit, comment status, comment list, comment show, comment archive, comment unarchive, comment delete, lease acquire, lease renew, lease release, lease steal, lease show, lease list, run start, run finish, run log add, run summar
  • Tasks — Commandsreference/cmd-tasks lettuce Tasks commands — 19 entries — task create, task show, task list, task exists, task set, task set-where, task unset, task set-list, task transition, task clone, task reopen, task archive, task unarchive, task delete, task body add, task audit, task graph, custom set, custom clear.
  • Command Referencereference/command-reference Exhaustive lettuce CLI reference — 184 commands across 13 groups, generated from the binary.
  • reference/indexreference/index reserved
  • Why lettuce (and not just Markdown + a convention)why-lettuce lettuce moves the guarantee from instruction-following to code — validated transitions, atomic leases, and evidence-gated coverage cells the binary refuses to fake.

Relationships

Cells — the coverage model

↑ top

concepts/concept-cell

A cell is one sparse, evidence-asserted point in a declared quality space — proof read backward, roadmap read forward. Covers pack, dimension, member, state/grade, gate, evidence.

Cells — the coverage model

The coverage plane grades how proven each part of a product is — and, read the other way, what work remains. It is lettuce's defining capability beyond a task list.

Vocabulary
  • Convention — coverage, the convention-as-data lettuce ships: states, transitions, gates, dimensions, families. Bundled in the binary and active on every project by default; you inspect it and tune it per project with the defaults layer rather than swapping it.
  • Dimension — one quality axis (e.g. test-coverage, input-validation). Grouped into families; each has an applicability (universal | conditional) and is closed (fixed members) or open (members minted ad-hoc). A project's effective dimensions = the pack's ⊕ an additive project runtime layer (dimension declare; never shadows pack vocab).
  • Member — one enumerated value of a dimension: {slug, name, description, rank} (empty name renders as slug; rank 0 = unranked, sorts by slug).
  • Cell — one sparse, evidence-asserted point: a canonical coordinate (dim=member;dim=member — pairs sorted by dimension, duplicates rejected, slugs validated) carrying one state from the active pack. An untouched coordinate is not stored; it reads as the pack default with stored=false.
  • State / grade — pack states carry a category (open, in-progress, review, done, excluded, flagged) that drives engine-enforced honesty invariants: only done counts as green; excluded leaves the denominator; review states never count as done; machine-only transitions (e.g. regress) fire only via the sanctioned path (cell reconcile).
  • Gate — authorizes a gated transition. Built-in evaluators: guard-bite (the cell has ≥1 linked evidence — a check that provably bites) and consistency (store predicates recompute clean). cell transition refuses a gated move that fails its gate (FW-WF-GATE-UNSATISFIED) unless --facilitate (records the verdict but allows the move).
  • Evidence — links on an asserted cell (--kind task = validated task ref, --kind url = opaque string). cell reconcile machine-regresses stale-green cells whose cited evidence no longer resolves.
Two readings: proof and roadmap

The same cells serve a backward and a forward reading. Backward, a cell is proof — quality already earned. Forward, each coordinate is a point in the product's quality space and every thin cell is work waiting to happen:

| Grade (coverage pack) | Forward meaning | |---|---| | untested (or unstored) | not yet discovered or decided | | gap | a known deficiency — a decided TODO | | smoke | shallow proof needing deepening | | hardened | done — a committed guard provably bites | | excluded | decided out of scope (leaves the denominator) |

The grade ladder is thus also a work-discovery ladder, and the board is a roadmap: an agent picks its next target from the frontier of weak coverage (cell rollup for the weakest axes/members, board export for the whole frontier), does the work as a task on the work plane, then closes the loop by linking that task as evidence and grading the cell. Work hardens cells; cells reveal work.

Stored cells vs the declared grid (implicit cells)

Storage stays sparse: only coordinates you explicitly assert are written to disk (cell list enumerates exactly those; the pack-default space is never materialised). Left alone, that makes the coverage denominator the count of stored cells — so a scope with one hardened cell and nothing else reads 1/1 = 100%, a vacuous "done". A declared grid fixes that.

A grid is declared per scope as two axes of member slugs — its units (rows, the things being covered) and its applicable dims (cols) — and the scope's honest denominator becomes their cross-product |units| × |dims|. Every un-worked coordinate in that space is an implicit cell: not stored, but counted in the denominator, reading as the pack default (e.g. untested). You record real progress against a fixed grid instead of minting cells one at a time.

lettuce grid scope add-unit s1 validate recover      --project P --author A
lettuce grid scope add-dim  s1 functional resilience --project P --author A
lettuce grid show --project P            # every scope's units/dims/size + project denominator
lettuce cell rollup --by scope --project P   # s1 → untested 0/4 (four implicit cells)
lettuce cell set "scope=s1;unit=validate;dim=functional" --state hardened --project P --author A
lettuce cell rollup --by scope --project P   # s1 → untested 1/4 (one stored, three implicit)

Behaviour to know:

  • Both axes required. A scope with units but no applicable dims (or the reverse) has size 0 and contributes nothing to the denominator — a half-declared grid never reads a vacuous ratio.
  • In-grid only. Once a grid governs a scope, a stored cell counts only if its unit= member is a declared row and its dim= member a declared col; off-grid coordinates never move the applicable / hardened / DoD numbers.
  • Backward-compatible. A project with no grid/ subtree reads declared=false and every consumer (cell rollup, board, dod) falls back to the observed stored-cell denominator — the pre-grid behaviour.
  • One denominator, three surfaces. cell rollup, the board, and the DoD verdict all read the same declared applicable space, so they cannot disagree. (Note board next's frontier is still built from stored cells only — implicit cells shape the denominator, not the row-by-row worklist.)
Freshness and depth — is a green cell's proof still current?

A hardened cell answers "was this proven?" — but proof decays as the code moves on. Two derived, never-stored signals disclose whether a green cell's evidence is still trustworthy, and both feed the Definition of Done:

  • Freshness (FRESH-3) — a categorical recency bucket, fresh | aging | stale, computed per cell at read time. Crucially it is measured in store revisions, NOT wall-clock time: distance = current store revision − the revision the cell's evidence was last asserted at, where the store's revision is its event count (rev@N — the same counter the board masthead uses), and the distance is clamped at 0 (an anchor ahead of the reference reads fresh, never "future-stale"). The default window: fresh within 50 revisions of the assertion (≈ one working wave), aging past 50 but within 2× (≤100 — a re-check is advised), stale beyond 100 (a re-check is due). It is a pure function of that distance — derived on every read, never persisted (a stored value could drift out of sync; a derivation cannot lie).
  • Basis — alongside the bucket each cell discloses whether its freshness is observed (the cell has a real revision anchor — an evidence link carrying an asserted revision) or presumed (no anchor at all → it is anchored at store genesis, so it reads maximally distant). Presumed is the honest "this cell never once bound its currency to a store revision"; a presumed cell counts as unknown against a recency floor, remedied by re-affirming with real evidence.
  • Depth (FRESH-2) — how many distinct store revisions have independently confirmed the grade (via cell verify / cell affirm). Confirming twice at the same revision buys no depth (the anti-farming rule); a verify earns strong depth only when it carries per-cell --evidence (the anti-rubber-stamp rule).

The DoD's optional --recency fresh|aging and --depth N floors gate on these signals (see Milestones & DoD). Recency is this one revision-distance measure — there is nothing to select or configure; the way it is computed is fixed.

The coverage ladder

Every project runs the shipped coverage convention by default; its grade ladder is:

| Grade ladder (default → … → done) | Meaning | |---|---| | untested → planned → in_progress → gap → evidence_linked → smoke → hardened; blocked, regressed (flagged); excluded, waived (excluded) | lettuce's own 88-dimension quality taxonomy; harden is guard-bite-gated (a committed guard that provably bites under fault-injection); waive requires a reason |

* = the default an untouched coordinate reads as (on a fresh project, untested). You do not swap the convention; you tune it per project with the defaults layer.

Coverage: 88 dimensions in 15 families

Inspect any with lettuce dimension list --project P (or dimension show <slug> --project P for one axis).

| Family | Dimensions | |---|---| | correctness | A functional · C spec-impl fidelity · N domain-model · O compat/migration · Q release-compat · U internal consistency | | usability | B UX/DX · S self-documentation · T error-messaging · M docs & examples · AY accessibility · BI i18n/l10n · VD visual & product design · AX agent experience · KB knowledge-base quality · WL white-label · BC browser-compat | | interface | H HTTP/API · J import/export round-trip · BX agent-readiness · CB multichannel parity · AP agent-protocol interop · DP data portability | | security | I attack surface · V privacy · AO rate-limiting · AZ bounded resources · BD auditability · RT red teaming · PT purple teaming · TM threat modeling · RC regulatory compliance | | reliability | BZ temporal · D data integrity · E resilience · F concurrency · FP cross-process concurrency · EL service liveness · AM idempotency · CC cleanup · AN backup/DR · AT determinism · OP ops & incident response | | distributed | G multi-node/sync · CA storage-backend equivalence | | performance | L performance · P observability · SC scalability patterns · DT distributed tracing | | maintainability | K code-quality · AA maintainability · AB testability · R configurability · BL architecture · CS code smells | | delivery | AC licensing · AR supply-chain/SBOM · AS deploy/release · BM CI-CD · BN packaging · BY stack maturity · BP cross-platform portability · LG legal, IP & terms · CN cloud-native/k8s · RG reproducible generation & provenance | | process | TD TDD discipline · GQ quality-gate quality · TK tracking & board discipline · QA QA procedure · RV adversarial/peer review · AL agentic dev-loop quality · PM process maturity & artifacts · RQ research & inquiry quality | | product | PA product analytics & north-star · XP experimentation & A/B testing · PD product discovery & prioritization | | growth | PR pricing & packaging · MN revenue, billing & unit economics | | customer | ON onboarding & activation · SU customer support & service · CX success, retention & churn · FB feedback & voice-of-customer | | market | PO positioning & messaging · DG demand generation & campaigns · SE content, SEO & GEO/AEO discoverability · IR investor & stakeholder communications | | lifecycle | FO cloud cost & FinOps efficiency · SN deprecation, EOL & sunset |

Worked example
lettuce cell set "area=auth;layer=api" --state in_progress --project "$P" --author "$A"
lettuce cell evidence add "area=auth;layer=api" --ref "$P/TASK-1" --kind task --project "$P" --author "$A"
lettuce cell transition "area=auth;layer=api" link-evidence --project "$P" --author "$A"
lettuce cell transition "area=auth;layer=api" harden --project "$P" --author "$A"
lettuce cell rollup --by area --project "$P"    # per-member floor state + hardened ratio, N/A-excluded

Adding evidence does not advance the cell's state: cell evidence add records the link, and cell transition link-evidence is the separate step that moves in_progress to evidence_linked. Skipping it makes harden refuse with FW-WF-TRANSITION-NOT-ALLOWED (harden is declared only from evidence_linked and smoke), which reads like a gate failure but is not one.

harden is gated on evidence that authorises, which is a higher bar than evidence that exists. A linked task authorises only when it is done and carries a custom/grc run-case pin — a task that is merely done still refuses, with FW-WF-GATE-UNSATISFIED. Use --facilitate to record-not-enforce when the pin is genuinely not applicable.

See also

Links to

Dependencies — what depends-on asserts, and which end you start from

↑ top

concepts/concept-dependency

depends-on and blocks are two independent task-reference lists. An edge is stored on the DEPENDENT and names its prerequisite; query graph reads them as a DAG to report cycles, the critical path, and which tasks are ready to start.

Dependencies — what depends-on asserts, and which end you start from

> Not the same "graph" as Graphs — authored process. That page is about > graph-defs and run-cases — authored process enacted on the ledger. This page is about the > task dependency DAG: the plain depends-on / blocks lists on tasks. The two are unrelated > except by name.

What an edge asserts

A depends-on B means B must be complete before A can start. The edge is stored on the dependent and names its prerequisite, so edges run dependent -> prerequisite.

lettuce task create P/A --depends-on P/B          # at create time, repeatable
lettuce task set-list P/A depends-on --value P/B  # afterwards — REPLACES the whole list

task set-list replaces rather than appends: pass every value you want to keep.

What does not belong on it. The edge feeds a schedule computation, so it should carry only real work prerequisites:

  • Not merge ordering. "These two branches touch the same generated file" is a fact about a branch, and it evaporates when either lands. It is not a dependency of the work.
  • Not topical relatedness. "These are both about auth" is what --label and --component are for. A relatedness edge inflates the critical path with a constraint nobody is waiting on.
  • Not "A cannot finish until B". This one is the easiest to get wrong, because it is a real constraint and it feels like a prerequisite. But the edge asserts B gates starting A, and a task already in progress is by definition startable. Writing it would claim the work had not begun and would extend the critical path by a constraint nobody is waiting on to begin.

There is deliberately no relation for finish-to-finish. The edge exists to feed one schedule computation — cycles, the critical path, and which tasks are ready to start — and a finish-to-finish constraint feeds none of the three. Record it where it is true: a comment on the ticket, or the ticket's own status. Leaving it unmodelled keeps the schedule honest; modelling it here would make every reader of critical_path wrong instead.

Which end is ready to start

query graph reports roots and leaves, and the names read backwards from planning intuition:

| | definition | means | when to start it | |---|---|---|---| | leaves | no outgoing edge | depends on nothing | now — these are the ready work | | roots | no incoming edge | nothing depends on them | last — the final deliverables |

Demonstrated on a three-task chain, SHIP depends-on BUILD depends-on DESIGN:

critical_path : ["demo/D-3", "demo/D-2", "demo/D-1"]   length 3
roots         : ["demo/D-3"]    SHIP   — depends on everything, startable LAST
leaves        : ["demo/D-1"]    DESIGN — depends on nothing,    startable NOW

To answer "what should I work on next", read leaves, not roots.

What reads the edges
lettuce query graph --project P [--relation depends-on|blocks|precedence]   # whole project
lettuce task graph P/A --relation depends-on --depth 2                      # one task's neighbourhood
  • query graph builds the DAG over every task in the project and reports cycles, acyclic, the critical_path (the longest chain by node count — the sequence that gates completion), roots and leaves.
  • --relation precedence reads depends-on and blocks together, folding each into a single precedence direction. The two single-relation modes each see only their own list, so a cycle whose closing path alternates between them is invisible to both — the same three tasks, read three ways:
  --relation depends-on   acyclic true    edge_count 1
  --relation blocks       acyclic true    edge_count 2
  --relation precedence   acyclic FALSE   edge_count 3   cycles 1

Reach for it when a project populates both lists. depends-on and blocks remain the right answer for "what does this one relation say".

  • task graph traverses outward from one task. A traversal capped by --depth sets truncated: true and marks each boundary node has_more, so an incomplete closure is never silently returned.
  • Soft-archived tasks are hidden by default in both — as nodes and as edge targets — so they cannot distort roots, leaves, cycles or the critical path. --include-archived opts them back in.
blocks is a second, independent list — not the inverse

Setting depends-on does not populate anything's blocks. The two relations are parallel lists you maintain separately:

D-2  depends-on = demo/D-1     blocks = (empty)
query graph --relation blocks  ->  edge_count 0, every task both a root and a leaf

So a store with a fully populated depends-on graph answers zero for --relation blocks. Pick one relation as the project's convention and populate that one; a half-populated pair is worse than either alone, because both queries look answerable and only one is.

If a project does populate both, read it with --relation precedence. That mode is the only one that sees the two lists as one order — and it does not merge them into each other: blocks and depends-on stay separate lists that point opposite ways, which is exactly why folding them needs a mode of its own rather than an inverse.

Most cycles mean the store was mutated outside the CLI — but not all

Ordinary writes refuse both of the states that would corrupt the analysis:

task set-list P/A depends-on --value P/NOPE   ->  FW-REF-MISSING-TASK   referenced task does not exist
task set-list P/D-1 depends-on --value P/D-3  ->  FW-REF-CYCLE          edge would create a cycle

So a dangling edge, and a cycle within one relation, cannot be authored through task set-list. When query graph reports acyclic: false for a single-relation read, that is an integrity finding, not a planning mistake — the edges arrived by import, direct file edit, or a cross-project path. Treat it as a repair task: see lettuce doctor and lettuce repair plan.

A cycle that alternates between blocks and depends-on is the exception. The write gate checks the two lists separately, so a three-node interleaved cycle is accepted one edge at a time, every write returning ok: true:

task set-list P/T-1 blocks     --value P/T-2   ->  ok: true
task set-list P/T-3 depends-on --value P/T-2   ->  ok: true
task set-list P/T-3 blocks     --value P/T-1   ->  ok: true    closes T-1 -> T-2 -> T-3 -> T-1

That store is reachable through the normal CLI, so acyclic: false under --relation precedence is a planning mistake to fix, not evidence of tampering. validate --strict reports it at rest as FW-REF-CYCLE, "task depends-on/blocks relations form a precedence cycle" — note that the envelope still carries ok: true there while data.valid is false: the command succeeded, the store did not.

When cycles are present the critical path is still well-defined: it is computed over the graph with the cycle back-edges removed.

See also

Links to

Dimensions and members

↑ top

concepts/concept-dimension

A dimension is one quality axis; members are its enumerated values. Dimensions group into families with applicability, and are closed or open. Effective set = pack ⊕ project-declared layer.

Dimensions and members

A dimension is one quality axis along which cells are graded — for example test-coverage, input-validation, or the coverage pack's lettered axes (A functional, I attack-surface, …).

Structure
  • Family — dimensions are grouped into families. The coverage pack's 88 dimensions span 15 families: ten engineering families (correctness, usability, interface, security, reliability, distributed, performance, maintainability, delivery, process) plus a five-family product-lifecycle super-family (product, market, customer, growth, lifecycle).
  • Applicability — each dimension is universal (always applies) or conditional (applies only when relevant to the unit). Which conditional axes a given product-type should require vs treat as N/A is a judgment you record by declaring a scope's applicable grid dims and marking the rest N/A (exclude) deliberately.
  • Closed vs open — a closed dimension has a fixed member enumeration; an open dimension mints members ad-hoc as coordinates use them.
Members

A member is one enumerated value of a dimension, first-class: {slug, name, description, rank}.

  • An empty name renders as the slug.
  • rank 0 = unranked (sorts by slug); otherwise members sort by rank.
  • dimension member add / dimension member update edit only project-declared dimensions — never pack-owned vocabulary.
Methodology — how to apply a dimension

Every dimension carries two distinct texts, and both matter:

  • description says what the dimension *is* — the quality axis itself (e.g. dim D: "Writes are atomic and durable; a crash mid-write leaves a recoverable, consistent store.").
  • methodology says how to apply it to a unit — the procedure an agent follows to grade a cell honestly. In the coverage pack a methodology has up to six facets. Every dimension carries at least Procedure and Hardened; the enriched axes add the middle four:
  • Procedure — the concrete steps to exercise this dimension on a unit.
  • Best practices — what "good" looks like; the do's and don'ts for that dimension's family (correctness / usability / security / …).
  • Tools — named, current tooling that exercises this axis well.
  • Current approaches — the present-day state of the art for the axis.
  • Evaluation — the metric + evidence bar per member; how to score honestly.
  • Hardened — the evidence bar: what a bite-proven guard must do. Across the whole pack, hardened means the same thing — a committed guard that provably bites under fault injection (green → break → RED → green); for non-code axes (process, compliance) the bar is an audit or freshness gate that fails on a missing or stale artifact. Attestation and prose never reach hardened.

> The methodology is a free-form string; the six-facet form above is the > current standard, and every bundled coverage dimension now carries it in full.

Example — coverage dim D (Data integrity / atomicity / persistence):

Procedure: exercise the write path; assert ATOMICITY (write-temp-then-atomic-
  rename or a WAL) and DURABILITY (fsync the file AND its parent dir before ack);
  inject a torn/partial write (crash mid-write, truncated temp, kill -9) and assert
  the store stays consistent + read-back returns the exact bytes. Then name the
  isolation level and prove the anomalies it forbids don't occur.
Best practices: make the ACID story EXPLICIT; writes are write-temp-then-atomic-
  rename never in-place; never ack before durable; "validated but never persisted"
  is a real bug class, so read the canonical file back and assert exact bytes.
Tools: atomic rename(2), fsync/fdatasync + directory fsync, WAL engines (SQLite
  WAL, LMDB, BoltDB); Jepsen elle for isolation; ALICE/CrashMonkey crash injection.
Current approaches: MVCC + snapshot isolation as the default; serializable via SSI;
  elle infers isolation anomalies from histories; deterministic simulation.
Evaluation: atomicity (no torn write survives a crash); durability (an fsync'd
  write survives power loss); isolation (forbidden anomalies never observed);
  multi-object atomicity (a reader never sees a partial commit).
Hardened: a committed torn/partial-write guard bites (green → break → RED → green)
  if atomicity/durability is removed; layer an isolation guard + a fsync-durability
  guard. Distinct lens vs F (F = in-process race-safety; D = the store's contract).

Read a dimension's methodology before grading any of its cells: lettuce dimension show <slug> --project <p> (one axis, full text) or lettuce dimension list --project <p> --format json (the whole effective set) surfaces it. The methodology catalog is the orientation board — the six-facet contract, a family-by-family map of all 88 dimensions, and fully worked exemplars. The methodology guidance is what distinguishes a smoke (exercised) grade from a hardened (bite-proven) one.

> Rule: a dimension without a methodology is incomplete. A quality axis you > cannot tell an agent how to grade is not yet a usable dimension — the > description/methodology pair is mandatory, not decorative.

Effective dimensions = pack ⊕ project layer

A project's effective dimension set is the active pack's dimensions plus an additive project runtime layer declared with dimension declare. The project layer is strictly additive: it can add axes and members but never shadows or overrides pack vocabulary.

Renaming a project dimension

A project-declared dimension's slug can be changed with dimension rename OLD NEW --project P. It is a whole-store structural migration, not a directory move, because the slug is three things at once: a path segment (projects/P/dimensions/<slug>/), the leading component of a qualified reference (P/dimensions/<slug>, the target of every dimension event), and a key inside every cell coordinate. Since a coordinate is the cell's identity, changing the key changes each affected cell's address — so the rename moves each cell directory to its new coordinate hash, carrying the whole cell across (state, note, revision, its own events ledger, and its evidence links with their asserted_at/asserted_rev provenance). The dimension keeps its family, closed-ness, members and its own ledger.

It is applied atomically: on any failure the store is left byte-unchanged, and it refuses rather than shipping a partial rename when a reference cannot be rewritten faithfully — one folded into a content-addressed identity (a graph-run-case advance event, a carrier directory), a stored saved query naming the dimension (the FQL cells source projects scope/unit/dim/group/ kind as fixed columns), or a move off/onto a reserved coordinate axis that the project's declared grid or DoD keys off. A pack-bundled dimension is compiled into the binary and is not renameable.

Coordinates

A cell lives at a coordinatedim=member;dim=member. Pairs are sorted by dimension, duplicates are rejected, and every slug is validated against the effective vocabulary. An untouched coordinate is not stored; it reads as the pack default with stored=false.

See also

Links to

Graphs — authored process, enacted on the ledger

↑ top

concepts/concept-graph

A graph-def is the authored, versioned shape of a repeatable process; a graph-run-case is one event-sourced enactment of it on the real ledger. Definitions are sound by construction and composable; runs carry write-once evidence and a reproducibility pin.

Graphs — authored process, enacted on the ledger

> Not the task dependency graph. depends-on/blocks between tasks — and the > cycles/critical-path analysis query graph runs over them — are > Dependencies. This page is about graph-defs and run-cases: > authored process enacted on the ledger. The two share a name and nothing else.

Most of lettuce tracks what is true: a cell asserts a state, a task moves through workflow, evidence hardens a claim. Graphs track how work is meant to proceed — and then record what actually happened when it did.

Two objects, deliberately separate:

| object | what it is | mutability | |---|---|---| | graph-def | the authored shape of a process — nodes wired by edges, from a start node | versioned data, revised deliberately | | graph-run-case | one enactment of a def on the real ledger | event-sourced; state == f(events) |

Reach for a graph when a process is repeatable, multi-step, and worth auditing — when you want the same shape run many times and each run to leave falsifiable evidence. For a single piece of work, a task is the right unit; for legal states and transitions of that work, see Workflow; for what is true about an area, see Cells.

Definitions are sound by construction

A graph-def is data at projects/<p>/graph-defs/<slug>/. Its spec body is stored append-only-versioned, the same way a task body is.

Creation folds in the soundness gate: a dangling edge, an unreachable node, a missing start, or an uncapped cycle is refused and never stored. So "stored" and "sound" are the same statement — you never have to ask whether a def in the store is coherent. Linting is separate and advisory: it reports design smells as warnings, never fatal.

Composition: a def can use another def

A node may be a subgraph that inlines another def by name and binds its open ports. Compilation resolves the transitive closure, inlines every referenced def, and hashes the whole expansion. Two consequences worth holding onto:

  • editing a shared pattern moves the effective-hash of every parent that uses it;
  • a composition cycle is refused, as is a reference to a def that does not exist.

This is what makes patterns reusable without making them silently divergent.

Enactment: what a run-case records

Opening a run-case positions it at the start node and mints an id. From there it is advanced across edges and finally resolved. Because state is derived from events, the ledger — not a scalar someone wrote — is the authority on where a run got to.

Carriers are the data that moves along edges: content-addressed, write-once, stored at projects/<p>/carriers/. Write-once is the point — a run's evidence cannot be quietly restated after the fact.

Two terminal dispositions, one terminal event. A run that was walked to the end is closed, with an optional --outcome. A run that was opened and never walked to the end is abandoned, and there --reason is required — an abandonment records no work, so the reason is the whole of what the ledger can say. Both write the same case-closed event through the same writer: one terminal, not two. A run that already has a disposition refuses a second one, because two dispositions is a fork in the record. Abandoning is never a delete — the run stays listed and inspectable, and it is excluded from the conformance denominator rather than judged for a walk that never happened.

The disposition is projected onto every read surface, so an abandoned run never has to be mistaken for a completed one:

  • show carries disposition beside state, and the required --reason is readable as outcome — the same field a closed run uses for --outcome.
  • list carries disposition per case, and counts them: total, open, abandoned.
  • viz writes the disposition into the diagram bytes as a %% comment, not just into the envelope. That placement is deliberate: viz > graph.mmd is the normal way the command is used, and an envelope-only field would vanish exactly there. An abandoned walk otherwise draws the same picture as a completed one.

conform remains the other half of the answer — it reports excluded: true for an abandoned case rather than judging a walk that never happened.

The reproducibility pin, and what it does not do. When the named def has a stored effective-hash, opening a run-case copies that hash verbatim onto the open event. Revising the def later moves the def's hash without re-pointing this run's evidence, so a completed run stays falsifiable rather than retroactively re-interpreted.

What the pin does not do is constrain the walk as it happens. The runtime is deliberately graph-def-free: advance reads no spec, so --to and --edge accept any string. A run-case can traverse an edge its def never declared, name a node absent from it, and still close with validate --strict reporting a perfectly clean store. That is by design, not an oversight — but it means the pin names the topology a run claims to have followed rather than proving it followed one.

Conformance replay is what makes the pin binding. It resolves the pinned hash back to the spec version that minted it and replays the recorded walk against that text, reporting an undeclared edge, an unknown node, or a join fired below its declared quorum. Judging against the pinned version rather than the latest is the whole point: revising a def cannot retroactively change the verdict on a run that finished before the revision.

This matters because every other check over a run-case re-derives its verdict from parameters the run itself recorded — the join re-folds the quorum the caller wrote. Each is therefore a fixed point: internally honest, and structurally unable to notice that the recorded number is not the declared one. Conformance is the read-time counterpart that can. It is a report, not a refusal — a non-conforming walk is evidence to read, not corruption to block — and it exits non-zero so a script can gate on it without parsing JSON.

Runtime patterns

Structured parallelism and iteration are authored in the def (and folded into its hash) but enacted in the run-case:

  • fork / join — a fork opens concurrent branches; a K-of-M join fires only once quorum actually arrives, and refuses otherwise;
  • loops — a capped back-edge exits only when its oracle is satisfied (converged, drained, a minimum count, a circuit-breaker), and refuses if not;
  • routers — a router picks its out-edge from the run-case's own recorded evidence (carriers, wave outcomes, produced effects), evaluated through a small deterministic guard grammar. Never from the caller's assertion.

Each of these is guarded by an explicit refusal rather than a best-effort guess. That is the same stance as the rest of lettuce: a gate that cannot be satisfied is reported, not papered over.

Where to go next
  • Graph Authoring — Commands — creating, revising, compiling, linting and visualising defs, and the catalog of shared patterns.
  • Graph Run-Cases — Commands — opening, advancing, closing or abandoning run-cases, replaying conformance, and producing carriers.
  • Cells — what a run-case's effects can harden.
  • Store — how event-sourced state and derived scalars stay coherent.

Links to

Methodology catalog — the orientation board

↑ top

concepts/concept-methodology-catalog

The orientation board for the coverage pack: the 6-facet methodology contract (Procedure · Best practices · Tools · Current approaches · Evaluation · Hardened evidence bar), a family-by-family map of all 88 dimensions, and worked exemplars — what you could/should do for a dimension to be properly considered, and the evidence-quality bar a hardened grade demands.

Methodology catalog — the orientation board

This is the orientation board for the coverage pack. Before you grade any cell on a dimension, read that dimension's methodology: it tells you everything you could and should do to consider the dimension properly, and the evidence-quality bar a hardened grade demands.

The coverage pack ships 88 dimensions across 15 families, each carrying a methodology. This page teaches the methodology contract, maps every dimension to its family, and shows three fully-worked exemplars. It deliberately does not reproduce all 88 methodologies — that content lives in one always-current place:

lettuce dimension list --project P --format json          # all 88 dims + full methodology
lettuce dimension list --project P --format json \
  | jq '.data.dimensions[] | select(.slug=="AL")'         # one dimension, full text

> The binary is authoritative. coverage.yaml is embedded in the binary, so the > command above always reflects the exact methodology the current release grades > against — the exemplars below are a readable snapshot, not the source of truth.

The methodology contract — how to read a dimension

Every dimension carries two distinct texts, and both matter:

  • description — what the axis is (the quality property itself).
  • methodology — how to apply it: the procedure an agent follows to grade a cell honestly, and the bar each grade must clear.

A methodology has up to six facets. Every dimension carries at least Procedure and the Hardened evidence bar; the enriched axes add the middle four:

| Facet | What it answers | |---|---| | Procedure | The concrete steps to exercise this dimension on a unit. | | Best practices | What "good" looks like — the do's and don'ts for the family. | | Tools | Named, current tooling that does this well. | | Current approaches | The 2025–26 state of the art for this axis. | | Evaluation | The metric + evidence bar per member; how to score honestly. | | Hardened | The evidence bar for hardened — a committed guard that provably bites under fault injection (green → break → RED → green), or, for non-code axes, an audit/freshness gate that fails on a missing or stale artifact. Attestation and prose never reach hardened. |

> Every dimension now carries the full six-facet form (Procedure · Best practices · > Tools · Current approaches · Evaluation · Hardened). Either way, a dimension without > a methodology is incomplete — you cannot grade what you cannot be told how to > grade.

The evidence bar, stated plainly. hardened is never earned by "we looked at it and it seemed fine." For a code axis it demands a committed guard that bites — remove the safeguard and the guard goes RED. For a non-code axis (process, compliance, agentic-loop) it demands an audit or freshness gate that fails on a missing, unsigned, or expired artifact. The Hardened facet of each dimension spells out exactly what its bar is.

The grading ladder (coverage's state machine): untested → gap | smoke → hardened, via the exercise, flag-gap, exercise-gap, and harden transitions. harden is gated by guard-bite — at least one linked evidence proving a check that bites — the only path to hardened. exclude marks a dimension structurally N/A (it leaves the denominator). See Cells — the coverage model for the full grade/state model.

Families — the navigation map

All 88 dimensions across 15 families. Read a dimension's full methodology with the jq snippet above (slugs are upper-case, e.g. AL).

| Family | Dimensions | |---|---| | correctness (6) | A functional correctness · C spec-impl fidelity · N domain-model completeness · O compat/versioning/migration · Q release-compat contract · U internal consistency | | usability (11) | B UX/DX · S self-documentation · T error-handling & messaging · M docs & examples · AY accessibility (a11y) · BI i18n/l10n · VD visual & product design · AX agent experience · KB knowledge-base & self-doc quality · WL white-label & theming · BC browser/client compatibility | | interface (6) | H HTTP/API surface · J import/export round-trip · BX agent-readiness · CB multichannel parity · AP agent-protocol interoperability · DP data portability & anti-lock-in | | security (9) | I attack surface · V privacy · AO rate-limiting/abuse · AZ bounded resources · BD auditability · RT red teaming · PT purple teaming · TM threat modeling · RC regulatory compliance & enforcement | | reliability (11) | BZ temporal-correctness · D data integrity/atomicity · E resilience/recovery · F concurrency/race-safety · FP cross-process concurrency & lock-safety · EL service liveness & crash-isolation · AM idempotency · CC resource-cleanup · AN backup/DR · AT determinism · OP operations & incident response | | distributed (2) | G multi-node/sync · CA storage-backend equivalence | | performance (4) | L performance/efficiency · P observability · SC scalability patterns · DT distributed tracing & trace ownership | | maintainability (6) | K code-quality · AA maintainability · AB testability · R configurability · BL architecture · CS code smells & anti-patterns | | delivery (10) | AC licensing · AR supply-chain/SBOM · AS deploy/release · BM CI-CD health · BN packaging · BY stack maturity · BP cross-platform portability · LG legal, IP & terms · CN cloud-native / kubernetes deployment · RG reproducible generation & asset provenance | | process (8) | TD TDD discipline · GQ quality-gate quality · TK tracking & board discipline · QA QA procedure (full) · RV adversarial/peer review · AL agentic development-loop quality · PM engineering-process maturity & artifacts · RQ research & inquiry quality | | product (3) | PA product analytics & north-star instrumentation · XP experimentation & A/B testing · PD product discovery & prioritization · _(product-lifecycle super-family — growing)_ | | growth (2) | PR pricing & packaging · MN revenue, billing & unit economics | | customer (4) | ON onboarding & activation · SU customer support & service · CX success, retention & churn · FB feedback & voice-of-customer | | market (4) | PO positioning & messaging · DG demand generation & campaigns · SE content, SEO & GEO/AEO discoverability · IR investor & stakeholder communications | | lifecycle (2) | FO cloud cost & FinOps efficiency · SN deprecation, EOL & sunset |

Worked exemplars

Three dimensions rendered in full — one from reliability (a code axis whose bar is a biting guard), one from security (a mixed code-and-artifact axis), and one from process (an axis whose bar is deliberately mixed-gateability). This is the pattern every dimension follows; pull any other with the jq snippet above. In the Phase-2 generated reference/coverage-catalog.md, every dimension renders like these.

---

D — Data integrity / atomicity / persistence

Family: reliability · Applicability: universal

What it is. Writes are atomic and durable (a crash mid-write leaves a recoverable, consistent store) AND the store's transaction/isolation contract is explicit and honest — the ACID story is named and proven, not assumed.

Procedure. Exercise the write path; assert ATOMICITY (all-or-nothing — write-temp-then-atomic-rename, or a WAL/journal) and DURABILITY (fsync the file AND its parent directory before ack — an un-fsync'd rename can vanish on power loss); inject a torn/partial write (crash mid-write, truncated temp, kill -9 between write and rename) and assert the store stays consistent + read-back returns the exact bytes. Then the TRANSACTION depth: name the isolation level the store offers (read-committed / snapshot / serializable) and prove the anomalies it forbids do not occur — dirty read, non-repeatable read, phantom, and write-skew (snapshot isolation still permits write-skew; only serializable forbids it); if multi-object/multi-file atomicity is claimed, prove a concurrent reader never observes a half-applied multi-key commit (it sees pre- or post-state, never mid).

Best practices. Make the ACID story EXPLICIT — Atomicity (temp+rename/WAL, single commit point), Consistency (invariants hold across the commit), Isolation (name the level; document that snapshot permits write-skew), Durability (fsync file

  • parent dir; group-commit for throughput); writes are

write-temp-then-atomic-rename never in-place; never ack before durable; "validated but never persisted" is a real bug class, so read the canonical file back and assert exact bytes (no more, no less — a single-version test misses append-only latest-version bugs); never expose a partially-applied multi-key mutation; treat isolation level as a documented contract. Don't: fsync the file but not its dir, rely on OS buffering for durability, or claim serializable while shipping snapshot.

Tools. atomic rename(2) (same filesystem), fsync/fdatasync + directory fsync, WAL/journal engines (SQLite WAL, LMDB, BoltDB single-writer MVCC); isolation reasoning ANSI SQL levels, snapshot-isolation/MVCC, Jepsen elle (cycle-detection isolation checker over observed histories); crash injection ALICE/CrashMonkey-style FS fault injection, kill -9 harnesses, power-cut simulation, deterministic simulation (FoundationDB/TigerBeetle VOPR).

Current approaches. MVCC + snapshot isolation is the default store concurrency model; serializable via SSI (PostgreSQL) or lock-based (CockroachDB/TiDB/YugabyteDB proved true serializability via Jepsen); elle infers isolation anomalies from histories — the modern way to PROVE an isolation claim rather than assert it; deterministic simulation crash-tests the durability path exhaustively; group-commit + fsync batching for durable throughput.

Evaluation. atomicity (no torn write survives a mid-write crash); durability (an fsync'd write survives power loss — verified with a crash/barrier harness); isolation (the claimed level's forbidden anomalies never observed via an elle-style history check); multi-object atomicity (a reader never sees a partial commit). Evidence = a crash-injection log + an isolation-history check.

Hardened (evidence bar). KEEP the committed torn/partial-write guard — it bites (green → break → RED → green) if atomicity/durability is removed and the store is left inconsistent. LAYER: an isolation guard that bites when a concurrent reader observes a half-applied multi-key commit (interleave a multi-file mutation with a read; assert the read sees pre- or post-state, never mid), and a durability guard asserting the write is fsync-durable (remove the dir-fsync → a crash harness loses the rename → red). Distinct lens vs F (F = in-process race-safety of the mechanism; D = the atomicity/durability/isolation CONTRACT of the store).

---

RC — Regulatory compliance & enforcement

Family: security · Applicability: conditional

What it is. The product is graded against a regulatory or platform-policy REGIME (the member = hipaa/gdpr/soc2/pci-dss/iso27001/app-store-review/play-store-policy/…) control-by-control with linked evidence, and enforcement = a committed control-check that BITES when a required safeguard is absent, misconfigured, or removed.

Procedure. Pick the regime (member: hipaa/gdpr/soc2/pci-dss/iso27001/nist-800-53/fedramp/ccpa, OR a PLATFORM-POLICY gatekeeper regime — apple-app-store-review / google-play-policy, whose "controls" are the store guidelines + content-rating + data-safety/privacy-nutrition-label declarations and whose "audit" is the store's pre-publish review that can reject the artifact) and scope the compliance boundary (in-scope systems/data — PCI Cardholder Data Environment, HIPAA ePHI systems, GDPR personal-data systems) as a versioned artifact (data-flow diagram, asset inventory, network map); enumerate the regime's applicable controls (PCI's 12 requirements, ISO 27001:2022 Annex A's 93 controls, HIPAA Security Rule 164.308/.310/.312 safeguards, SOC 2 Trust Services Criteria, NIST 800-53 families) marking each applicable or N/A with WRITTEN justification; map each control → implemented safeguard + dated evidence (the control-to-evidence traceability matrix); record every gap (owner, severity, remediation date) in a gap register; remediate; wire an automated control-check that FAILS when a technical safeguard is absent/drifts, and an artifact-freshness check that fails when a signed process-control artifact is missing or past its review-by date; run continuously in CI + scheduled scans (audit-ready always, not point-in-time).

Best practices. compliance-as-code (controls as executable policy in git, not GRC-spreadsheet prose — a control's truth is its passing check, reviewable in a PR); control-to-evidence traceability (dated reproducible evidence, not "the policy says X"); never check the box without proof; continuous over point-in-time; scope discipline (tokenize/segment/pseudonymize out of scope — the cheapest control is the one you removed from scope); cross-framework mapping (one safeguard e.g. encryption-at-rest satisfies HIPAA 164.312, PCI Req 3, ISO A.8.24, SOC 2 CC6.1, GDPR Art 32 — evidence once, reuse everywhere); separation of duty on evidence (the implementer is not the sole signer); least-privilege + immutability on the audit/evidence store itself (a mutable audit trail defeats the control).

Tools. control catalog OSCAL (NIST machine-readable catalog/profile/SSP/POA&M) + IBM Trestle; policy-as-code OPA/Rego + Conftest, Checkov (1000+ IaC policies mapped to CIS/NIST/PCI/SOC2/HIPAA), Cloud Custodian (CNCF, auto-remediation), Prowler (multi-cloud, built-in HIPAA/PCI/SOC2/GDPR/FedRAMP frameworks), Trivy/Kubescape/Terrascan/kube-bench; continuous-compliance platforms Vanta/Drata/Secureframe/Sprinto (+ Scytale/Anecdotes); cloud-native AWS Config conformance packs + Security Hub, Azure Policy + Defender for Cloud, GCP Security Command Center; evidence pipeline SIEM/CloudTrail, Vault, IdP logs (Okta/Entra) for access + MFA evidence.

Current approaches. continuous compliance / compliance-as-code is dominant (controls are code, evidence auto-collected on a schedule, drift alerts near-real-time — "audit-ready always" replaces the annual scramble); cross-framework control mapping (implement+evidence a safeguard once, inherit across SOC2/ISO/HIPAA/PCI/GDPR — so "add HIPAA" onto an existing SOC 2 program is incremental, not a restart); machine-readable regulation (FedRAMP 20x + RFC-0024, Jan 2026, mandates OSCAL packages + Key Security Indicators with continuous validation — tooling lag is real but the direction is set); automated evidence collection (read-only integrations snapshot cloud config/IdP-MFA/vuln results on a cadence); shift-left compliance (IaC scanners gate the PR so a non-compliant resource never reaches production).

Evaluation. control coverage (% of the regime's APPLICABLE controls with an implemented + fresh-evidenced safeguard; HIPAA/PCI demand ~100% of applicable, ISO/SOC 2 tolerate documented risk-accepted exceptions justified in the Statement of Applicability / management assertion); evidence freshness (each artifact timestamped + max-age — technical-check evidence within the scan window ~24h, process artifacts within their review cycle: BAA current, DPIA annual, pentest ≤12mo, access review ≤quarterly; stale evidence = uncovered); gap-register health (open gaps + severity + owner + date; open criticals block hardened); scope correctness (boundary documented, asset inventory matches reality, N/A justifications hold). Evidence QUALITY auditors expect: reproducible, independent (not self-attestation), complete (whole population not a hand-picked sample), timestamped + attributable, tamper-evident. SOC 2 Type I (design at a point in time) vs Type II (operating effectiveness over a 3–12mo window) — Type II needs evidence the control operated CONTINUOUSLY, exactly what a biting automated check produces.

Hardened (evidence bar). A regime cell is hardened only when EVERY applicable control is enforced by either a biting automated check OR a fresh signed artifact, the two classes are paired, and the gap register is empty. Technical controls = a committed check that fails when the safeguard is absent/drifted: encryption at rest/in transit fails on any in-scope datastore storing PHI/PAN/personal-data with encryption off (flip a test bucket insecure → red); MFA on all privileged/in-scope access; audit logging enabled + retained + immutable; config drift from baseline; the data-subject-rights erasure/portability/access path ACTUALLY EXECUTES (a technical control weak programs wrongly attest — make it bite); vuln/patch SLA. Process/attestation controls = a signed, dated, non-expired artifact graded by a freshness check: BAA per PHI-touching vendor; DPIA/RoPA; ISO Statement of Applicability + certificate; SOC 2 Type II report; PCI ROC/SAQ + pentest; FedRAMP SSP/POA&M/3PAO. Enforcement principle: wherever a control CAN be technically verified it MUST be a biting check — attestation is not acceptable for what a machine can prove ("we encrypt PHI" must be a failing test on unencrypted PHI, never a signed sentence); pair a signed report with the biting check of its underlying technical control, either alone is insufficient.

---

AL — Agentic development-loop quality

Family: process · Applicability: conditional

What it is. When an AI agent (or fleet) is doing the development, the build→verify→improve→reflect LOOP itself is a graded engineered system — autonomous, resilient, observable, convergent, cost-bounded — proven by instrumented evidence, not agent vibes. Member = a loop property (autonomy / resilience / provenance / observability / stability / scalability / effectiveness / speed-quality / overhead / self-reflection / self-tuning).

Procedure. Name the loop under test (agent/scaffold — Claude Code, OpenHands, SWE-agent, Cursor, a custom harness; repo/scope; the gates it drives) and its unit of progress (a landed PR, closed ticket, hardened cell, passed task); INSTRUMENT before judging (OpenTelemetry GenAI / OpenInference spans for every model call, tool call, reasoning step, token+cost — you cannot grade a loop you cannot see); then exercise each loop PROPERTY with a deliberate probe not a happy-path watch: autonomy (measure human-interventions-per-unit over a real unattended window → SAE-style L0–L5), resilience (INJECT a mid-loop failure — kill a step, corrupt a tool result — and observe self-recovery without human rescue), stability (run N≥5 iterations, watch for green→red oscillation vs monotone convergence), scalability (1 then k parallel agents on isolated worktrees, measure throughput + collisions), effectiveness (resolve rate on SWE-bench Verified/-Live/Terminal-Bench or an internal set), speed-quality (iterations/wall-clock against a FIXED quality floor), overhead (cost-per-completed-task = attempt-cost / solve-rate), provenance (sample decisions from the trace, each must link a rationale+evidence), self-reflection + self-tuning (the loop critiques its own runs and adjusts from a scored record, not folklore); score each member on evidence quality; aggregate + name the weakest property + its next probe.

Best practices. instrument first, judge second (an un-traced loop is capped at 'covered' — 'we watched it, it seemed fine' is the vibe score this dim kills); autonomy is a dial not a switch (state the OBSERVED SAE level + intervention rate; most 2025-26 production loops are L2-L3, ceiling L3 conditional; never claim 'fully autonomous' without an unattended trace); converge not churn (every iteration reduces distance-to-done and never regresses an already-green gate — green→red→green oscillation is a first-class loop defect); every decision carries its receipt (rationale + the failing test/file/prior result that drove it); recover without a human (retry-safe/idempotent steps + checkpoints; distinguish transient infra faults — retry/circuit-break — from semantic faults — Specification Drift/Reasoning/Tool-Call — which blind retry just burns tokens on); parallelize with isolation, merge with judgment (worktrees give filesystem isolation only; decomposition/semantic-conflict/ merge-selection are still yours; adding agents must add LANDED output); govern speed-quality explicitly (a velocity floor the gate suite may not breach); budget on cost-per-completed-task not raw tokens; benchmark against a contamination-resistant set (SWE-bench-Live ~19% vs Verified 60%+ exposes overfitting).

Tools. eval/effectiveness SWE-bench + SWE-bench Verified (500-task human-validated), SWE-bench-Live (anti-contamination), Terminal-Bench + Long-Horizon-Terminal-Bench, Holistic Agent Leaderboard (HAL)/Live-SWE-agent (cost-annotated); scaffolds SWE-agent, AutoCodeRover, OpenHands, Devin, Claude Code (--worktree), Cursor 2.0 (multi-agent), Aider, ccswarm; observability/AgentOps LangSmith, Langfuse (OSS), AgentOps, Arize Phoenix (OpenInference), W&B Weave, Traceloop/OpenLLMetry over the OpenTelemetry GenAI semantic conventions (the portable substrate); resilience/durable-execution Restate, Temporal (checkpoint+resume, exactly-once), circuit-breaker/retry libs, MAPE-K loops; parallelism git worktrees + lock-safety (ties to FP); cost provider token/usage APIs + cost-per-resolved-task.

Current approaches. the instrumented agentic SDLC (every run traced with OTel GenAI/OpenInference; the decision graph — not a re-run — is the primary debugging artifact; observability consolidated on LangSmith/Langfuse/AgentOps/Phoenix/Weave); autonomy as a measured SAE-style dial (L2-L3 consensus, L3 ceiling); self-healing loops (failure-classified repair — circuit-break transient, corrective-feedback/rollback semantic — over durable-execution state so a recovered agent CONTINUES not restarts); contamination-aware effectiveness (Live/fresh sets, cost reported alongside score); parallel-agent fleets on worktrees (Cursor up to 8 concurrent) with the honest caveat that worktrees solve low-level isolation only; governed speed-with-a-floor as the loop-level 'keep-green'.

Evaluation. each member has a distinct metric + evidence bar — evidence must be reproducible (re-run yields the same class of outcome), instrumented (from the trace/harness, not a screenshot/prose), windowed (over a real run of N iterations or a benchmark subset, not one cherry-picked pass), and where gate-able biting (fails when the property is broken). autonomy = interventions/unit threshold audited off an unattended trace; resilience = self-recovery rate from injected failures; observability = span-coverage %; stability = green→red regressions across N runs + convergence trend; scalability = output(k)/(k*output(1)) + collision count; effectiveness = resolve rate vs a floor; speed-quality = iterations/wall-clock with the full floor still green; overhead = cost-per-completed-task budget; provenance = decision-linkage coverage; self-reflection/self-tuning = a scored eval record showing runs are critiqued + params evolve from measured winners. A single successful demo run is 'covered', never 'hardened'.

Hardened (evidence bar). deliberately mixed-gateability — its honesty is being explicit about which members bite via a committed check, which are metric-threshold-gated, and which are audit-graded. GATE-ABLE (a committed check that BITES): resilience (fault-injection test — SIGKILL a step / corrupt a tool response — asserts self-recovery; red when the loop wedges or restarts from scratch), stability (green-stays-green repeated-run harness over N≥5; red on any previously-green gate regressing), effectiveness (benchmark-score-floor CI gate; red when a loop change drops resolve rate below floor), overhead (cost-per-completed-task budget gate — the least-fakeable member, straight off the token meter), speed-quality ('faster AND floor-still-green'; red when speed came from skipping a gate), scalability (scaling-efficiency threshold + zero-cross-agent-collision assertion; red when adding agents adds no landed output or collides). METRIC-THRESHOLD-GATED (a number vs a bar, trace-audited): autonomy (interventions/unit ≤ bar for the claimed SAE level), observability (required span kinds present; red if instrumentation is dropped). AUDIT-GRADED (a review that fails on a missing artifact): provenance + self-reflection/self-tuning (fails when a sampled decision lacks a linked rationale+evidence, or a prompt/param change ships with no eval record). Cross-cutting rule: no member exceeds 'covered' from a demo or prose claim — every claim about the loop is a check that bites, a number against a bar, or an audit that fails on a missing receipt. That is precisely how this dim avoids collapsing into an 'agent vibe' score.

---

See also

Links to

Milestones and Definition of Done

↑ top

concepts/concept-milestone-dod

Milestones are a staged hypothesis ladder; a Definition of Done declares the grade floor a project must reach. Together they give board next its verdict line.

Milestones and Definition of Done

Milestones

A milestone groups work toward an outcome and advances through stages — a hypothesis ladder you progress as evidence accrues.

lettuce milestone create <slug> --project P --author A --title "..."
lettuce milestone list --project P
lettuce milestone show <slug> --project P
lettuce milestone set-stage <slug> --stage <s> --project P --author A   # advance the ladder
lettuce milestone close <slug> --project P --author A

Milestones live on the Work plane alongside tasks; they organize why work is being done, while tasks are the what.

Definition of Done (DoD)

A Definition of Done declares the grade floor a project (or scope) must reach on the coverage plane — the objective bar that separates "in progress" from "done".

lettuce dod set   --project P --author A ...   # declare the grade floor
lettuce dod show  --project P                  # inspect the current DoD
lettuce dod clear --project P --author A       # remove it

Once a DoD is declared, board next prints a leading DoD: … verdict line — the honest, computed answer to "are we done yet?" A DoD turns "done" from an assertion into a measurement: the floor is met only when the cells actually grade at or above it (with excluded cells leaving the denominator).

What the floor is made of

dod set writes up to three coverage floors, checked as a strict per-scope AND-gate over the applicable (non-excluded) cells — a scope is met only when every such cell clears every declared floor, reported as a k/n count, never a blended percentage:

  • --grade STATE (required on first declaration) — the minimum pack state a cell must reach to count (e.g. hardened).
  • --depth N (optional) — the minimum confirmation depth (FRESH-2): how many distinct store revisions independently confirmed the grade.
  • --recency fresh|aging (optional) — the minimum freshness bucket (FRESH-3): fresh (must be fresh) or aging (fresh-or-aging, never stale). A cell whose freshness is presumed (no revision anchor) counts as unknown — unmet until re-affirmed. See freshness and depth for how both are computed.

--scope S sets a per-scope override of any floor (an unset field inherits the project default). Setting a floor never moves the hardened ratio: a scope can read 100% hardened yet DoD-unmet because its proof is stale or shallow.

Beyond the coverage floors, the overall verdict layers two auto-derived outer gates you never set by hand — every committed milestone reached and zero non-terminal tickets — so a project can clear every coverage floor and still read not done. Inspect all of them via dod show / board export.

Organizing a project

A typical project shape:

1. Declare the working model — every project runs the shipped coverage convention by default; optionally add project dimensions (dimension declare) or tune the ladder with the defaults layer. 2. Declare the bardod set a grade floor (per project and/or per scope). 3. Frame the outcomes — create milestones with stages. 4. Do the worktasks claimed with leases, evidenced by runs/artifacts, closing cells. 5. Steer by the boardboard next weakest-first until the DoD verdict is met.

See also

Links to

The shipped convention — coverage as data

↑ top

concepts/concept-pack

Coverage is the one convention lettuce ships: its states, transitions, gates, dimensions, and families are data, not code. Every project runs it by default; you inspect it and tune it per project — you do not swap it.

The shipped convention — coverage as data

lettuce ships one working convention, and it is expressed as data, not code: the set of states, transitions, gates, dimensions, and families a project grades against. That convention is coverage, and every project runs it by default — a fresh project is already on coverage with nothing to enable.

This is the mechanism-vs-convention split at the heart of lettuce: the engine is pure mechanism (it owns the containers for meaning and method), and the convention supplies the meaning (which states exist, which transitions are legal, which gates authorize them, which quality axes to grade). The convention lives as data in the binary, so the engine and the on-disk store format never have to know what any particular state or dimension means.

You do not swap the convention at the user surface. You inspect it (read what coverage declares for your project) and tune it per project with an additive defaults layer. The internal envelope still names the active convention on some read surfaces — e.g. dimension list and cell show carry a pack: coverage field — which is the convention's internal identifier, not a command you run.

The default: coverage

Coverage is a 88-dimension / 15-family quality taxonomy (the families run from correctness and security through market and lifecycle). Every coordinate you have not yet worked reads as the sparse default untested; you record real progress by transitioning cells along coverage's ladder.

The ladder (each state carries a one-letter board glyph):

| State | Glyph | Meaning | |---|---|---| | untested | U | the default — never worked | | planned | N | scheduled, not started | | in_progress | I | actively being worked | | gap | G | worked and found deficient (needs a reason) | | evidence_linked | E | progress backed by linked evidence | | smoke | S | exercised end-to-end | | hardened | H | done* — reached only through a gate that provably bites | | blocked | B | flagged: work stalled (needs a reason) | | regressed | R | flagged: a hardened cell that broke | | excluded | X | N/A for this scope (needs a reason) | | waived | W | deliberately not pursued (needs a reason) |

* = the default a fresh coordinate reads as. hardened is the only done state and the only one behind a gate: the guard-bite gate requires a committed check that provably goes green → break → RED → green under fault injection — strictly stronger than "the tests pass". The transition actions that move a cell are plan, start, exercise, flag-gap, exercise-gap, link-evidence, harden, block, unblock, waive, exclude, regress, and reopen; an action with no legal transition from a cell's current state is refused.

Inspecting the convention

Coverage is read-only data you can query per project (every read needs a store root — an explicit --root, else the nearest .lettuce directory found by walking up from the working directory, else the command refuses — and --project):

lettuce defaults show    --project P            # the effective LADDER — states/transitions/gates, each source-tagged + hidden states
lettuce dimension list   --project P            # the project's effective dimensions (source-tagged)
lettuce dimension show A --project P            # one dimension by slug, with its full methodology
lettuce dod show         --project P            # the Definition-of-Done floor + current verdict
lettuce grid show        --project P            # the declared coverage grid + denominator
lettuce board render     --project P            # the whole board as a self-contained HTML page

Each read answers a different question: defaults show = the ladder (which states, transitions, and gates the project grades against); dimension list = the axes; dod show = the Definition-of-Done floor. defaults show resolves a project's effective ladder — the bundled convention ⊕ the project's tweak layer — and tags every element with a source of default or project, so it is the read complement to the defaults tweak commands: it shows exactly what a tweak changed, base states the project has hidden (dropped from the effective view, listed under a hidden section), and where the grading-at-entry default landed. A fresh project (no tweak) resolves byte-identically to the shipped convention — every element reads source=default; after a tweak, authored states/transitions/gates read source=project and any hidden base state drops out of the ladder and appears under hidden.

dimension list reports the effective dimensions — coverage's declared axes plus any additive per-project runtime dimensions — each tagged with its source. A dimension's slug is its coverage letter (A, B, H, …); dimension show prints that axis's full procedure, best-practices, tooling, and evidence bar.

Tuning the convention (per project)

When one project needs coverage with a small adjustment, you do not author a new convention — you record an additive per-project tweak layer over the ladder / gates / DoD. A project that authors no tweak resolves byte-identically to the shipped convention; a tweak is stored under projects/<p>/… and merged at resolve time, so it never edits the bundled convention.

The defaults command family authors that layer (every subcommand is a mutation — pass --project and --author):

# additive working state (done/excluded are structural and refused)
lettuce defaults state declare triaging --category in-progress --letter T --rank 15 --project P --author A
lettuce defaults state set-default triaging --project P --author A   # move the grading-at-entry default
lettuce defaults state hide blocked        --project P --author A    # subtractive: hide a base state + its edges

# additive workflow edge (--from/--to must resolve; --gate optional, must resolve —
# but REQUIRED when --to is the done state: only a gate promotes to done)
lettuce defaults transition declare expedite --from untested --to gap --project P --author A
lettuce defaults transition declare fast-harden --from smoke --to hardened --gate guard-bite --project P --author A

# additive guard (--check-kind must be a shipped evaluator, e.g. guard-bite, consistency)
lettuce defaults gate declare peer-review --check-kind consistency --description 'two approvals' --project P --author A

# clear the tweak layer back to the shipped convention (per-scope: ladder | dod | dimensions)
lettuce defaults reset --only ladder --project P --author A

Two safety rules keep the layer honest:

1. Additive-only + validate-on-write. A tweak that would break the ladder's honesty invariants — a transition to an undeclared state, a gate naming an unknown check-kind, a set-default that would leave the ladder without exactly one default, or a state declare whose slug shadows an existing state (including a base state this project has hidden — re-declaring it would create an invisible phantom) — is refused with nothing written (exit 1, FW-CMD-USAGE). Every refusal happens before any write. There is no unhide command; to bring a hidden base state back, clear the overlay with defaults reset --only ladder. 2. A reset can't strand work. Per-scope orphan guards refuse a reset that would leave cells holding a state or dimension it removes (reassign or clear those cells first); a clean no-op reset still succeeds. 3. Only a gate promotes to done. A transition whose --to is the done-category state (hardened) must carry a --gate; an ungated one is refused, citing spec §5 invariant 5. requires: [evidence] is not a substitute — recording a citation is the agent's act, promotion is the gate's. This is what makes the direct-set gate un-opt-out-able: cell set --state hardened is refused only while every declared entry into hardened is gated, so before this rule one ungated transition declare switched that refusal off for the whole project. Transitions out of done (regress, reopen) and into excluded/waived are unaffected — they are not promotion.

The done-state slug is hardened — use it (not done) in any transition example, because --to done names no state and hits the honesty gate.

To see the result of any tweak, read the effective ladder with defaults show (above) — it renders the resolved states/transitions/gates with each element tagged source=default|project plus the hidden base states, so you can confirm exactly what a tweak moved. The defaults subcommands are documented in full under Definition of Done — Commands.

See also

Links to

The plain format — what --format plain emits, and when it emits the whole object

↑ top

concepts/concept-plain-format

plain is the scriptable surface: one primary reference per line. Two rules decide what a command emits — an EXPLICIT projection renders the requested columns instead (LET-909), and an object with no primary reference has nothing to collapse to. Both are keyed on the command and its flags, never on the data.

The plain format — what --format plain emits, and when it emits the whole object

--format plain is the surface you pipe. The spec defines it in one line:

> plain — newline-separated primary references

That sentence is the whole contract for the common case, and it is what makes ... --format plain | xargs lettuce task show work. Everything below exists because two situations are not covered by it, and both were previously settled only inside code comments — which is why five different readers re-derived the rule locally and reached different answers.

The default: one primary reference per line

With no projection flag, a read collapses to bare references, one per line, with no header, no numbering and no columns:

$ lettuce query run 'from tasks' --format plain
lettuce/LET-1433
lettuce/LET-1432
lettuce/LET-1430

That is the scriptable contract. A collection collapses to a reference per line; a single minimal read yields its own reference and nothing else.

Rule 1 — an explicit projection renders the columns you asked for

If the caller states which fields they want, plain renders those fields rather than collapsing to the reference:

$ lettuce query run 'from tasks select task,title' --format plain
demo/DEMO-1	t

The key is explicitness, not whether a reference column happens to be present. The default projection already contains task, so keying on reference-presence would make plain-without-select start emitting extra columns and break every existing pipeline.

If you want bare references while naming fields, use --refs-only. It cannot co-occur with an explicit projection, which is what keeps the two intentions distinguishable.

This rule is deliberate and load-bearing, but note that it is wider than the spec sentence: a row of tab-separated columns is not "newline-separated primary references". See Where the spec and the code disagree below.

Rule 2 — an object with no primary reference renders in full

plain finds an object's primary reference by looking for a reference, ref or task field. Some object kinds do not have one:

| object | its canonical identity | has a reference field | |---|---|---| | task, lease | a task/lease reference | yes | | cell | a coordinate (dim=…;scope=…;unit=…) | no | | graph definition | a slug | no | | dimension | a slug | no |

When there is no primary reference, there is nothing to collapse to, and plain renders the full object rather than emitting nothing. This is intentional, and it is the rule to reach for when a new object kind appears: an object whose identity is not spelled reference renders in full until its identity is declared to the plain projection.

The same applies when collapsing would drop what you asked for. A read enriched by an inclusion flag (--full, --with-body, --with-logs) or carrying a baked-in rollup renders in full, because collapsing it to a bare reference would silently discard the content the flag requested.

What plain will never do
  • Never change shape because of the data. The projection is a function of the command and its flags. A task with no labels and the same task one --label later produce the same plain shape; a script's parse shape does not change the first time somebody labels a ticket.
  • Never emit nothing for an object that exists. If a command produces a payload, plain produces output. Zero bytes from a successful read is a defect, not a projection.
Where the spec and the code disagree

Stating this plainly because it is the one open question the rule above does not settle.

§20.6 says plain is "newline-separated primary references", flat. Rule 1 renders tab-separated columns when a projection is explicit. Those are not the same claim, and the difference is not a rounding error: a caller reading only the spec would call select task,title --format plain a violation, and a caller reading only the code would call it correct.

The behaviour is right and the spec sentence is what should move. A caller who names columns has stated exactly what they want, and rendering something else would be the surprising choice — the spec line predates the projection flags and describes the default branch only. Until the spec is amended, treat §20.6 as describing the default projection, and this page as describing both branches.

Judging a command against this contract

A show command has no projection flag, so it is always in the default branch — rule 1 can never apply to it. That makes each one answerable:

| command | branch | verdict | |---|---|---| | query run (no select) | default | conforms — bare references per line | | query run … select … | explicit | conforms under rule 1 | | task list, lease list, milestone list | default | conform — reference per line | | graph-def list, dimension list | default | conform under rule 2 — rows carry a slug, not a reference | | cell list, cell show | default | conform under rule 2 — a cell's identity is its coordinate | | project show | default | does not conform — it is listed as rendering full, but its identity is a reference | | grid show | default | does not conform — emits zero bytes for a grid that exists |

The last two are the live cases, and they fail differently.

grid show collapses to an empty sub-array and emits nothing, which the second clause of What plain will never do forbids outright: a successful read of an object that exists produced no output.

project show renders its fields because it is named in an internal list of commands that render the full object — not because either rule above reaches it. A project's identity is a reference, so rule 2 does not apply, and a show has no projection, so rule 1 cannot. Under this contract it should collapse to its reference. If the fields it prints are genuinely the requested content — a project's path and its sub-entity counts — then the honest fix is to say so in the contract, not to keep a list that overrides it silently.

See also
  • Queries — projections, select, and --refs-only
  • Cells — the coordinate that identifies a cell

Links to

Querying with FQL

↑ top

concepts/concept-query

FQL reads the store: from SOURCE where EXPR select fields order/limit. Sources include tasks, events, cells; the cells source exposes DoD-derived axes (freshness, depth, dod).

Querying with FQL

FQL (the lettuce query language) reads the store deterministically. Shape:

from SOURCE [where EXPR] [select f1,f2] [order by f [desc]] [limit N] [offset N]
  • Sources: tasks, events, registry, authors, projects, dimensions (the active pack's declared dimensions), cells (stored cell assertions — sparse defaults are not rows).
  • Strings use double quotes (single quotes are rejected). contains matches case-insensitively unless --case-sensitive.
  • Task-reference fieldsparent, depends-on, blocks — are stored project-qualified (proj/TASK-1), and the comparison operand is canonicalised against --project before matching. Both spellings therefore find the same rows: where parent = "TASK-1" is equivalent to where parent = "proj/TASK-1". Before v0.15.0-3312 only the qualified spelling matched: the bare one returned an empty result at exit 0 rather than an error, so if an older build reports no rows for a relation you can see on disk, that is why.
  • --group-by FIELD (tasks source only) buckets by assignee, component, milestone, severity, status, type, or workflow.
  • Soft-archived tasks are hidden from every query/list surface by default; pass --include-archived.
lettuce query run "from tasks where status = active select task,title" --root "$ROOT" --format json
lettuce task show "$P/TASK-1" --with-body --format json     # or --full
lettuce task audit "$P/TASK-1" --format json                # event history
lettuce query timeline ...                                  # chronological events
Querying coverage with the cells source

The cells source interrogates the coverage plane the same way you query tasks. Stored fields: coordinate, state, hash (plus cell/project/pack identity). It also carries DoD-derived axes:

| Axis | Values | Meaning | |---|---|---| | freshness | fresh | aging | stale | how current the cell's evidence is | | depth | int | distinct-revision confirmation count | | dod | blocking | met | is this cell blocking the Definition of Done | | dod-reason | grade | depth | recency | unknown | why a blocking cell blocks |

These turn "what is not yet done?" into a query:

lettuce query run "from cells where dod = blocking select coordinate,state" --project "$P" --format json
lettuce query run "from cells where freshness = stale select coordinate" --project "$P" --format json
lettuce query run "from cells where depth >= 2 select coordinate" --project "$P" --format json
lettuce query run "from cells where dod-reason = grade select coordinate" --project "$P" --format json
Slicing by scope / member

FQL has no dedicated scope/unit/dimension filter operator today — slice by a coordinate member instead: where coordinate contains "layer=api" or where coordinate contains "scope=login". See scopes.

Saved queries
lettuce query saved create <slug> --title "<title>" --fql "<fql>" --project P --author A
lettuce query saved run <name> --project P
lettuce query saved list --project P
See also

Scopes — the DoD/board partition

↑ top

concepts/concept-scope

scope is a reserved dimension that partitions the coverage board and Definition of Done. Cells without a scope fall into the synthetic unscoped bucket, never silently outside the DoD frame.

Scopes — the DoD/board partition

A scope is the reserved partition by which the Definition of Done and the board evaluate coverage. It is a modeled dimension, but a special one: scope is how a project carves its quality space into evaluable regions (e.g. scope=auth, scope=login, scope=storage).

How to shape scopes

Scopes are declared implicitly by the cells that use them — you assert cells at coordinates that include a scope= member, and those scope values become the partitions the board and DoD report on. Which units and dimensions belong to a scope is a modeling choice: a scope groups the coordinates whose scope= member matches, across whatever other dimensions those coordinates declare.

lettuce cell set "scope=auth;layer=api"  --state in_progress --project P --author A
lettuce cell set "scope=auth;layer=db"   --state planned    --project P --author A
lettuce board next --project P --scope auth     # steer within one scope
lettuce cell rollup --by scope --project P       # per-scope floor + hardened ratio
The unscoped bucket (honesty invariant)

A cell that declares no scope= is bucketed under the synthetic scope unscoped at evaluation time — so it is never silently outside the DoD frame. You cannot assert scope=unscoped on a cell; the name is reserved for that bucket. This guarantees every asserted cell is accounted for by exactly one scope when the DoD verdict is computed.

Board & DoD interplay
  • board next --scope <name> steers within one scope; naming an undeclared scope returns an honest error listing available scopes (never a silent empty report).
  • dod set can declare a grade floor per project and/or per scope; the board's leading DoD: … line is the computed verdict against that floor.
  • grid scope add-unit / add-dim declare a scope's coverage grid — its units × applicable dims — which sets the scope's honest denominator (every un-worked coordinate counts as an implicit-untested cell), independent of how many cells are actually stored.
See also

Links to

The store and the two data planes

↑ top

concepts/concept-store

The store is a path-jailed root of ordinary validated files. Objects fall into two planes: Work (projects/tasks/leases/runs/artifacts) and Coverage (packs/dimensions/cells).

The store and the two data planes

Canonical state lives in a store — a path-jailed root of ordinary files. Files are the source of truth: you can inspect, diff, and validate the store with normal tools. lettuce validate --strict and lettuce doctor tell you if it is healthy and how to repair it.

Foundational invariants
  • Files are the source of truth. No hidden database; every object is a file.
  • Mutations are explicit and attributed. Always pass --project and --author; lettuce never infers them from the OS, Git config, or store contents. Every mutation is recorded as an event (task audit, query timeline).
  • Concurrency is coordinated by leases and revisions. Claim work with a lease before touching it; pass --expect-revision N when retrying or racing another agent. Writes are serialized by a single-writer generation lock.
  • Output is a stable envelope. With --format json|yaml, every result is { ok, data, warnings, meta }; errors are { ok:false, error:{ code, message, diagnostics:[...] } } with machine-readable diagnostic codes.
The two data planes

| Plane | Objects | Question it answers | |---|---|---| | Work | projects, tasks, workflow, leases, runs, artifacts, comments | what is being done, by whom, with what evidence | | Coverage | packs, dimensions, members, cells, gates, boards | how proven each part of the product is |

The two planes meet at evidence: a task on the Work plane is linked as the evidence that hardens a cell on the Coverage plane.

Store modes
  • filesystem (default, offline) — canonical state under the store root.
  • dedicated-git — a strongly-consistent shared store that fetches upstream before every mutation (requires connectivity by design).
  • client — set a server URL to drive a running lettuce serve over HTTP instead of mounting the store.
See also

Links to

Tasks and the work plane

↑ top

concepts/concept-task

A task is the unit of work: created under a project, moved along validated workflow transitions, claimed with leases, and evidenced by runs and artifacts.

Tasks and the work plane

A task is the unit of work on the Work plane. Tasks live under a project, carry a stable reference (project/TASK-ID), and move through a workflow of states via validated transitions.

Lifecycle
lettuce task create LET-1 --project P --author A --title "..." --body "..."
lettuce task show P/LET-1 --with-body
lettuce task transition P/LET-1 <transition> --project P --author A   # only legal moves
lettuce task list --project P
  • Workflow is supplied by the active pack: which states exist and which transitions are legal. An illegal transition is refused, not recorded (lettuce workflow list / workflow show).
  • Stable referencesproject/TASK-ID is durable across renames; prefer it when project context is ambiguous.
  • Attribution & audit — every mutation records an event; inspect with task audit and query timeline.
Coordination for agents
  • Leases — claim a task before working it: lettuce lease acquire (atomic, expiring, audited). Renew with lease renew; steal only expired leases. This is the honest alternative to a "who's working on it" naming convention.
  • Revisions — pass --expect-revision N on event-bearing mutations when retrying or racing another agent; a stale revision is rejected.
Recording execution (evidence)
  • Runsrun start / run finish, with run log add and run summary add — the record of an execution attempt.
  • Artifactsartifact add / replace attach outputs to a task.
  • Commentscomment add for human/agent narrative.

A finished task becomes evidence: link it to a cell (cell evidence add --kind task) to harden coverage. Work hardens cells; cells reveal work.

Task-local objects

Comments, leases, runs, and artifacts are task-local — 35 subcommands in the Task-Local-Objects group.

See also

Links to

Workflow — states, transitions, and gates

↑ top

concepts/concept-workflow

Workflow is the pack-supplied model of legal states and transitions for tasks and cells. Transitions are validated; gated transitions require a satisfied gate or explicit --facilitate.

Workflow — states, transitions, and gates

Workflow is the model of legal states and the transitions between them. It is supplied by the active pack as data — not hard-coded — and it governs both tasks (the work plane) and cells (the coverage plane).

lettuce workflow list --project P              # available workflows
lettuce workflow show <name> --project P       # its states + transitions
lettuce workflow transition list --project P   # the legal moves
Validated transitions

A transition moves an object from one state to another only along a declared, legal edge. An illegal move is refused, not recorded:

lettuce task transition "$P/TASK-1" start-work --project P --author A
# positional: lettuce task transition REF ACTION [--reason TEXT] [--expect-revision N]
  • Some transitions are requirement-gated — e.g. start-work needs an active lease; without it, the move fails with FW-WF-REQUIREMENT-UNSATISFIED.
  • --expect-revision N guards against racing another agent (a stale revision is rejected).
Gates (coverage plane)

On cells, a gate authorizes a gated transition. Built-in evaluators:

  • guard-bite — the cell has ≥1 linked evidence (a check that provably bites).
  • consistency — store predicates recompute clean.

cell transition refuses a gated move that fails its gate (FW-WF-GATE-UNSATISFIED) unless --facilitate records the verdict but allows the move.

> Never --facilitate past a failed gate to "make progress." One unproven > green poisons every future orientation. See agentic cycles.

See also

Links to

Getting started

↑ top

getting-started

Create your first lettuce store and task in fewer than five commands, then learn where to go next.

Getting started

The first successful path is fewer than five commands.

lettuce init --author jota --bootstrap-author --bootstrap-project default
lettuce task create LET-1 --project default --author jota --title "Try lettuce" --body "First task."
lettuce task list --project default
lettuce task show default/LET-1 --with-body

default is just an ordinary project name — there is no hidden default-project pointer and no project inference from store contents. Pass --project and --author explicitly for mutations; lettuce never infers them from the OS, Git config, or store contents.

Naming guidance
  • Task IDs: a short uppercase prefix related to the project, e.g. API-42, LAT-7. v0.15 does not enforce prefix/project coupling (that would make rename and import workflows harder).
  • Agent authors: stable, non-secret identifiers such as codex-local-01, ci-agent, planner-agent.
The core agent loop

Once a store exists, an agent typically:

1. Discovers work — lettuce task list / lettuce query run (FQL). 2. Claims it — lettuce lease acquire (atomic, expiring). 3. Transitions status — lettuce task transition (validated). 4. Records execution — lettuce run start / run finish, artifact add. 5. Validateslettuce validate --strict and lettuce doctor --format json.

Modes
  • filesystem (default) — offline, canonical state under the store root.
  • dedicated-git — a strongly-consistent shared store that fetches upstream before every mutation (requires connectivity by design; not an offline mode).
  • client — set a server URL (and bearer token) to drive a running lettuce serve over HTTP instead of mounting the store.
Next

Running lettuce in autonomous agentic cycles

↑ top

guides/guide-agentic-cycles

Use the store as your loop — read forward it is the plan, written backward it is the proof. The orient→act→reflect→file cycle via board next, and the invariant that keeps it honest.

Running lettuce in autonomous agentic cycles

lettuce is not primarily an autonomy tool — every command works one at a time, human or agent. But one powerful way to use it: if you are an agent with standing goals and a store, run lettuce as your loop. The store read forward is the plan; the store written backward is the proof — no external planner needed.

The core loop (one task at a time)
ROOT=.lettuce; P=myproject; A=my-agent
# 1. Once: seed a store (idempotent).
lettuce init --root "$ROOT" --author "$A" --bootstrap-project "$P" --bootstrap-author --idempotent --format json
# 2. Discover — concrete items AND the coverage frontier.
lettuce task list --project "$P" --root "$ROOT" --format json
lettuce board next --project "$P" --root "$ROOT" --format json
# 3. Create work.  4. Claim (lease) then start.  5. Record runs/artifacts.  6. Complete + release lease.
lettuce lease acquire "$P/TASK-1" --expires-at 2026-01-01T00:00:00Z --project "$P" --author "$A" --format json
lettuce task transition "$P/TASK-1" start-work --project "$P" --author "$A" --format json
# ... work, narrate with `run log add` / `comment add`, attach `artifact add` ...
lettuce task transition "$P/TASK-1" complete --reason "Done + verified" --project "$P" --author "$A"
lettuce lease release "$P/TASK-1" --project "$P" --author "$A"

> Lease-gated transitions (start-work) fail with FW-WF-REQUIREMENT-UNSATISFIED > unless you hold the lease. Acquire first. Transition syntax is positional: > lettuce task transition REF ACTION [--reason TEXT] [--expect-revision N].

The autonomous cycle — orient → act → reflect → file
# ORIENT — ask the store what matters most right now.
lettuce board next --project "$P" --root "$ROOT" --format json
#   → every scope's meter weakest-first, shape-aware suggestions, concrete
#     gap/untested coordinates, each with the exact drill command (--depth 0|1|2).
#     Pick ONE target: gap (known defect) before untested (undiscovered),
#     weakest scope first. Act on the coordinate it printed — don't hand-compose one.

# ACT — make the work claimed, attributed, and visible.
lettuce task create TASK-N --title "Harden <coord>" ...
lettuce lease acquire "$P/TASK-N" ...; lettuce task transition "$P/TASK-N" start-work ...

# REFLECT — record what happened WITH evidence, then close the cell.
lettuce artifact add "$P/TASK-N" --type test-report ...          # the proof itself
lettuce task transition "$P/TASK-N" complete --reason "guard bites" ...
lettuce cell evidence add "<coord>" --ref "$P/TASK-N" --kind task ...
lettuce cell transition "<coord>" harden ...                    # guard-bite gate must pass

# FILE — organize everything you discovered before looping.
lettuce task create ...                             # one ticket per unfixed finding
lettuce cell set "<coord>" --state gap --reason "<defect>" ...  # defects get addresses
lettuce dimension member add <dim> <member> ...     # new surface → new map row
lettuce milestone set-stage <slug> --stage <s> ...  # progress the hypothesis ladder
lettuce cell reconcile ...                          # regress stale greens
lettuce validate --strict ...

Then run board next again — the frontier has changed, partly because you hardened a cell and partly because you filed what you found. Work hardens cells; cells reveal work. FILE is not bookkeeping — it is how the map stays truthful enough to steer the next iteration.

What board next needs to be useful
  • A store and a valid --project (a missing/unknown project is refused — no default, no cross-project scan).
  • At least one stored cell — the frontier is built from asserted cells only; sparse pack-defaults are never rows. An empty board is not an error (every scope meter reads n/a).
  • A declared DoD to get the leading DoD: … verdict line (dod set).
  • --depth accepts only 0, 1, 2; --scope <name> naming an undeclared scope returns an honest error listing available scopes, never a silent empty.
The invariant that keeps the loop honest

A gap/untested cell spawns a task (the cell is the work's address); the finished task, linked as evidence, authorizes hardening (cell transition is guard-bite gated); and if the cited evidence later unresolves, cell reconcile machine-regresses the cell. Neither direction can lie to the next iteration — which is why you never --facilitate past a failed gate to "make progress": one unproven green poisons every future ORIENT.

Sharing the board: export and render

board next steers your loop; two sibling read-only projections publish the same board for a human or a dashboard, from the identical BoardExport:

  • board export emits a stable, versioned JSON data contract on stdout (schema_version, the pack's dimension/state legend, the stored cells with evidence, per-axis coverage rollups, the blended headline ratio, milestones, tickets, and the activity histogram). It is data ⟂ visual: the document carries no styling, so a separate renderer owns the presentation.
  • board render turns that same export into a self-contained HTML page natively in Go (no Python, no JSON round-trip) — you pipe stdout to a file. Every byte is inline: no src=, no external references, and no network call of any kind. The page is pure-CSS with one authorized exception — a project carrying graph-run-cases also emits the grc replay simulator as exactly one inline <script> plus one inert <script type="application/json"> data island per grc; a project without graph-run-cases emits no <script> at all. --theme selects only the CSS frame (today the sole built-in is default; an unknown name is refused with the available list). Both default their provenance from the store (data revision + latest-event instant), never the wall clock, so a render is reproducible; --source-rev stamps an explicit revision into the masthead.

Both require --project and read only that project — no cross-project scan.

The activity/velocity band is store operations, not git commits. The board's histogram is derived purely from stored event timestamps (a per-calendar-day count of store mutations), bucketed into ISO weeks. It is deliberately the self-containable substitute for git-commit velocity — the board never reads a git repo, which is what keeps the HTML fully offline and portable. Read it as "how much work landed in the store over time", not as a commit log.

See also

Links to

Agentic loop demo — one development cycle, step by step

↑ top

guides/guide-agentic-loop-demo

A single realistic dev loop worked end to end: at each orient→act→reflect→file step, exactly what the agent GETS from lettuce and what it DOES, with real commands and output.

Agentic loop demo — one development cycle, step by step

The Agentic cycles guide gives you the theory of the orient→act→reflect→file loop and the invariant that keeps it honest. This guide walks one concrete loop, showing at every step what lettuce hands you (GET) and what you do with it (DO). The commands are real; the output blocks below are illustrative — they depict a hypothetical webapp store, not a captured session.

The scenario. A webapp project on the shipped coverage convention (the default — every project runs it with nothing to enable). To keep the board compact, this walkthrough grades a deliberately small slice: two coverage axes, a (Functional correctness) and i (Security), across an auth scope (fully hardened) and a checkout scope (weak). Our job this cycle: harden one cell. We do not choose it — the board does.

> New to a project? Start with First contact. Standing > a project up from nothing? Use the Project setup > playbook.

Step 1 — ORIENT · GET the frontier and the DoD verdict

DO: ask the store what matters most, and read the verdict first.

ROOT=.lettuce; P=webapp; A=codex-01
lettuce board next --root "$ROOT" --project "$P" --depth 1 --format plain

GET:

board next · project webapp · DoD: NOT DONE (1/2 scopes met) · 2 open cell(s)
  DoD bar: hardened
  DoD-blocked (close these to reach done):
    [✕] checkout checkout — 0/2 met (2 below bar)
        ↳ re-verify: lettuce board next --project webapp --scope checkout --depth 2
start here: checkout / dim=a;scope=checkout;unit=cart  [In_progress · Functional correctness]
  ↳ detail: lettuce cell show "dim=a;scope=checkout;unit=cart" --project webapp

[AUTH] auth — 100.0% · 0 open
  • A  Functional correctness                       100.0%  1H
  • I  Security                                     100.0%  1H

[CHECKOUT] checkout — 0.0% · 2 open
  • A  Functional correctness                         0.0%  1U
  • I  Security                                       0.0%  1U

What the store just told you, for free:

  • The DoD verdict (NOT DONE (1/2 scopes met)) — the honest answer to "are we there yet?" — leads the report. auth is met; checkout blocks done.
  • The single targetstart here: names one coordinate, dim=a;scope=checkout;unit=cart, currently In_progress. Take this coordinate verbatim; do not hand-compose one. Weakest scope, weakest cell, chosen deterministically.
  • The drill commands — every line prints the exact lettuce … to descend.
Step 2 — ORIENT · GET the cell's own history

DO: before touching code, read what the target cell already knows.

lettuce cell show "dim=a;scope=checkout;unit=cart" \
  --root "$ROOT" --project "$P" --format plain

GET — its current state, canonical coordinate (note the axes are sorted dim;scope;unit), pack, and any first-class note:

project    : webapp
state      : in_progress
coordinate : dim=a;scope=checkout;unit=cart
hash       : ...
pack       : coverage
stored     : true

Now you know: this cell is a genuine open item on the coverage frontier, and your job is to move it to hardened — which the convention's harden gate will not let you do without proof.

Step 3 — ACT · claim the work, attributed and visible

DO: create a ticket for the change (if none exists), claim its lease, and start it. Leases make the claim atomic and prevent two agents fighting over the same work.

lettuce task create LET-2 --title "Test cart rejects tampered price" \
  --body "Add guard test." --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce lease acquire webapp/LET-2 --expires-at 2099-12-31T00:00:00Z \
  --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce task transition webapp/LET-2 start-work \
  --root "$ROOT" --project "$P" --author "$A" --format plain

GET:

task create ok
lease acquire ok
task transition ok

> start-work is lease-gated: without the lease it fails > FW-WF-REQUIREMENT-UNSATISFIED. Acquire first. --expires-at is a required > RFC-3339 timestamp — the lease auto-expires so a crashed agent never wedges the > board.

...now do the actual engineering — write the failing test, make it pass, rebuild, and verify the guard bites (green → break the code → RED → fix → green). Narrate durable notes on the task as you go:

lettuce comment add webapp/LET-2 \
  --body "Guard added; verified it bites when price is tampered." \
  --root "$ROOT" --project "$P" --author "$A" --format plain
Step 4 — REFLECT · GET the honesty gate, DO record proof

DO: the cell is in_progress; walk it up the coverage ladder and attach the proving task as evidence. The harden transition is guard-bite gated — it refuses unless the cell carries at least one linked evidence.

C="dim=a;scope=checkout;unit=cart"
lettuce cell transition "$C" link-evidence --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce cell evidence add "$C" --ref webapp/LET-2 --kind task \
  --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce cell transition "$C" harden --root "$ROOT" --project "$P" --author "$A" --format plain

GET:

cell transition ok
cell evidence add ok
cell transition ok

That last ok is meaningful: the guard-bite gate passed because real evidence is linked. Try harden with no evidence and the store refuses:

lettuce: error [FW-WF-GATE-UNSATISFIED]: transition is blocked by its gate

> Discipline, not shortcut. cell set --state hardened would assert the > state directly, bypassing the gate — an unproven green. Flip cells through > cell transition (gated), and reserve cell set for declaring planned / > blocked / waived / seeding. One unproven green poisons every future ORIENT.

Close out the ticket and release the lease:

lettuce task transition webapp/LET-2 complete --reason "guard bites on tampered price" \
  --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce lease release webapp/LET-2 --root "$ROOT" --project "$P" --author "$A" --format plain
Step 5 — FILE · DO organize what you discovered, GET the moved frontier

Found a second defect while working? File it as its own cell/ticket now, so the next ORIENT sees it. Then re-run the loop's first command — the frontier has moved, partly because you hardened a cell and partly because you filed what you found:

lettuce board next --root "$ROOT" --project "$P" --format plain

GET:

board next · project webapp · DoD: NOT DONE (1/2 scopes met) · 1 open cell(s)
  DoD bar: hardened
  DoD-blocked (close these to reach done):
    [✕] checkout checkout — 1/2 met (1 below bar)
        ↳ re-verify: lettuce board next --project webapp --scope checkout --depth 2
start here: checkout / dim=i;scope=checkout;unit=cart  [Planned · Security]

[CHECKOUT] checkout — 50.0% · 1 open

Checkout climbed 0.0% → 50.0%, the open count dropped from 2 to 1, and start here now points at the next weakest cell. That is the whole method: work hardens cells; cells reveal work.

Adapt this to your own cycle
  • One cell per loop. Take the start here target, prove it, harden it, re-orient. Small, honest increments beat batch grading.
  • Evidence is the currency. A cell reaches hardened only through the gated cell transition, with a real proving task linked. Never --facilitate past a failed gate to "make progress".
  • Read the DoD first, every loop. board next leads with the verdict; when it reads DONE, you are actually done — measured, not asserted.
  • The full ladder. This walkthrough graded a compact slice of the shipped coverage convention; its full ladder is untested → planned → in_progress → gap → evidence_linked → smoke → hardened, via plan / start / flag-gap / exercise / exercise-gap / link-evidence / harden (plus block / unblock / exclude / waive / regress / reopen) — the loop is identical across every axis. See the Project setup playbook.
See also

Links to

Configuring lettuce for useful leverage

↑ top

guides/guide-config-for-leverage

Wire lettuce into a real project so an agent gets maximum leverage: root/project/author resolution, the config precedence chain, pack selection, mode choice, author identity, saved queries, and DoD floors.

Configuring lettuce for useful leverage

lettuce ships with working defaults, but leverage comes from wiring it into a real project deliberately: a store an agent can find, a pack that models the work, a Definition of Done floor that makes "done" a measurement, and saved reads that survive restarts. This guide covers every configuration surface and how to compose them.

The configuration precedence chain

Every resolvable setting follows one order, everywhere:

explicit flag  →  environment variable  →  --config JSON file  →  built-in default

| Setting | Flag | Env var | Default | |---|---|---|---| | Store root | --root PATH | LETTUCE_ROOT | nearest .lettuce walking up from the working directory, else refused (filesystem); cwd (dedicated-git) | | Project | --project NAME | LETTUCE_PROJECT | none — explicit where required | | Author | --author NAME | LETTUCE_AUTHOR | none — required for every mutation, never inferred | | Mode | --mode | LETTUCE_MODE | filesystem (other: dedicated-git) | | Output | --format | — | table (also plain, json, yaml; markdown only for doctor/usage/skill) | | Server URL | --server-url URL | LETTUCE_SERVER_URL (_FILE) | none; setting it switches the CLI to HTTP-client mode (fallback http://127.0.0.1:8727) | | Bearer / actor | --bearer | LETTUCE_BEARER (_FILE), LETTUCE_ACTOR (_FILE) | none | | Listen | serve --listen | LETTUCE_LISTEN | 127.0.0.1:8727 | | Config file | --config PATH | LETTUCE_CONFIG | none |

--config PATH is a JSON file for client context (server URL, bearer, actor) — useful when a machine drives a remote served store and you do not want tokens on the command line.

> --author is never inferred. lettuce refuses to guess the acting author > from the OS, Git config, or store contents. This is the honesty invariant that > makes every mutation attributable — set LETTUCE_AUTHOR once per agent so you > never forget it, but the tool will still never fill it in for you.

init — seeding a store idempotently
lettuce init --root .lettuce --author agent-1 \
  --bootstrap-project myproject --bootstrap-author --idempotent --format json

init requires a root but neither a project nor an author of its own; the flags bootstrap them in one call. It advertises idempotency_key=true and accepts the external-input keys bootstrap_project, bootstrap_author, idempotent, so --idempotent makes re-running it on an already-initialized store a success, not an error — safe to run on every agent wake as a cron-guarded seed step.

Each new project ships with the default workflow (open → ready → active → review → done, plus blocked/needs-human and terminals), the standard severities (low/medium/high/critical), task types (epic, story, task, bug, research, …), and artifact types — inspect them with lettuce workflow show default and lettuce registry list.

Root and project resolution
  • --root is the path-jailed store root. Name it explicitly per project (.lettuce in the repo). There is no home-directory default: when no root is stated and none is discoverable by walking up from the working directory, the command refuses instead of guessing. That refusal is deliberate — two stores can each hold a project of the same name, so a wrong-store write succeeds silently and is discovered late.
  • --project is a trusted context for shorthand references and project-scoped commands. There is no default-project pointer and no inference from store contents — a missing or unknown --project on a project-scoped command is refused (FW-NAME-PROJECT), never a silent cross-project scan. Use fully qualified references (myproject/TASK-1) when context is ambiguous.
Choosing a mode

| Mode | Activation | When to use | |---|---|---| | filesystem (default) | --mode filesystem / LETTUCE_MODE | Offline, single-worktree, canonical state under --root. The everyday choice. | | dedicated-git | --mode dedicated-git | A strongly-consistent shared store: every mutation is a Git commit and fetches upstream first. Requires connectivity by design — not an offline mode; needs a clean, synced worktree. sync status/push/pull manage it. | | HTTP client | --server-url / LETTUCE_SERVER_URL | The identical CLI dispatches over HTTP to a running lettuce serve instead of mounting the store. |

Pick filesystem for a local agent loop; dedicated-git when several writers share one authoritative store; client when the store lives behind a server. See serving lettuce safely for the client-mode auth posture.

Inspecting and tuning the convention

The shipped convention is the working model — states, transitions, gates, dimensions. lettuce ships exactly one, coverage, and every project runs it by default with nothing to enable. You inspect it and tune it per project rather than swapping it (every read needs a store root and --project):

lettuce dimension list  --project P            # the project's effective dimensions
lettuce dimension show A --project P            # one dimension by slug, full methodology
lettuce dod show        --project P            # the Definition-of-Done floor + verdict
lettuce grid show       --project P            # the declared coverage grid + denominator
lettuce board render    --project P            # the whole board as a self-contained HTML page

coverage is lettuce's 88-dimension / 15-family quality taxonomy. For that same convention with one project-specific adjustment, use the defaults layer — an additive per-project tweak over the ladder / gates / DoD — rather than authoring a whole new convention.

Author identity

Authors are stable, non-secret identifiers (codex-local-01, ci-agent, planner-agent) — one per acting agent.

lettuce author add planner-agent --author agent-1        # register an author
lettuce project author add myproject agent-2 --author agent-1 --bootstrap-author

--bootstrap-author on init/project create/project author add creates and links the author in the same call.

Saved queries — freezing the reads that matter

Reads an agent runs every cycle should be stored once, not retyped:

lettuce query saved create ready-tasks --project P --author A \
  --title 'Ready Tasks' --fql 'from tasks where status = ready select task,title'
lettuce query saved run ready-tasks --project P --format json
lettuce query saved update ready-tasks --fql '<new fql>' --expect-revision 1 --project P --author A
lettuce query saved list --project P

Saved queries are project-scoped, versioned (guard updates with --expect-revision), and archivable. Pair them with the reading surfaces so orientation is one command.

DoD floors — make "done" a measurement

A Definition of Done turns "are we there yet?" from an assertion into a computed verdict. Declare the floor once:

lettuce dod set --grade hardened --depth 2 --recency aging --project P --author A
lettuce dod set --scope s3 --depth 3 --project P --author A     # per-scope override
lettuce dod show --project P --format json                      # policy + verdict
  • --grade (required for a first declaration) is the minimum pack state a cell must reach to count as done (validated against the active pack).
  • --depth is an optional minimum distinct-revision confirmation depth (FRESH-2).
  • --recency is an optional minimum freshness bucket (FRESH-3: fresh or aging, never stale).
  • Without --scope you set project defaults; with --scope you override one scope's floors (unset fields inherit the default).

The verdict is a strict per-scope AND-gate — a scope is met only when every applicable cell clears the bar, never a blended percentage — and it layers two auto-derived outer gates you never set here: every committed milestone reached and zero non-terminal tickets. dod clear removes a floor or the whole policy.

Wiring lettuce in for maximum agentic leverage

The store is only leverage if an agent can rediscover it after a restart. Anchor the coordinates where they survive compaction — your CLAUDE.md (or equivalent always-injected instruction file), not memory:

1. Export the coordinatesLETTUCE_ROOT, LETTUCE_PROJECT, LETTUCE_AUTHOR so every command inherits them. 2. Cron-guard the seed — run idempotent init on each wake; it is a no-op on an existing store. 3. Model the work — declare project scopes/units on the default coverage convention (tune it with defaults if needed), assert the first cells. 4. Declare the bardod set a grade floor so board next leads with a verdict line. 5. Freeze the reads — saved queries for the frontier you check every cycle. 6. Run the loop — then board next both answers "are we done?" and hands you the next target.

Work that lives only in your context dies with your context; work reflected into the store is durable memory. That reflection is the whole point of configuring lettuce well.

See also

Links to

First contact — what a fresh agent sees, reads, and does

↑ top

guides/guide-first-contact

From zero prior context to productively driving lettuce: the exact first moves (skill, docs, usage, status, board), what each returns, and how the shipped default is the 88-dimension coverage taxonomy (with the smaller huru ladder available on request).

First contact — what a fresh agent sees, reads, and does

You have just been handed a lettuce binary and a repository. You have no prior context. This guide is the fastest honest path from "just arrived" to "productively driving lettuce", written from your point of view. Every command below is real — run it.

> This is the entry point of the Agent Playbook. Once oriented, go to > Project setup playbook to prepare a > project, Agentic loop demo to watch one dev loop > end to end, and Agentic cycles for the loop theory.

Move 0 — read the model, not the whole reference

The binary documents itself. Two commands, no store required:

lettuce skill      # the embedded agent guide (SKILL.md) — read this ONCE, top to bottom
lettuce docs       # the embedded wiki (HTML explorer); `docs show <page>` streams one page

lettuce skill prints the model-first guide — its opening frame:

# Using lettuce

`lettuce` is a filesystem-native work tracker **and coverage/quality store**.
Canonical state (projects, tasks, comments, runs, artifacts, cells) lives as
ordinary files inside a path-jailed store root; every mutation is validated and
recorded as an event. ...

lettuce docs show <page> streams one wiki page as markdown (concepts and guides by slug), e.g. lettuce docs show concept-cell or lettuce docs show guide-first-contact. When prose and the binary disagree, the binary wins — so treat usage (below) as ground truth.

Move 1 — get the exhaustive contract on demand

You never guess a flag. For any command, ask the binary:

lettuce usage                      # every command, every flag, examples
lettuce usage cell set             # just one command's contract
lettuce usage cell set --format json   # machine metadata: kind, requires_root/project/author, flags, examples

The top of usage carries the Agent Guidance you should internalize before your first mutation:

## Agent Guidance

- Prefer --format json for automation. JSON and YAML outputs use stable machine
  envelopes with ok, data, warnings, and meta.
- Pass --project and --author explicitly for mutations. Do not infer project or
  author from the operating system, Git config, or store contents.
- Use fully qualified task references such as project/TASK-1 when project context
  might be ambiguous.
...

Two rules that will save you an hour: mutations need explicit --project and --author (lettuce never infers them), and task IDs need a 1–9 char uppercase prefix (LET-1, not t-1).

Move 2 — find out where you are
lettuce status --root .lettuce --format plain
root=/repo/.lettuce mode=filesystem project= author= initialized=true diagnostics=0

initialized=true diagnostics=0 means a healthy store already exists at .lettuce. initialized=false means there is no store yet — jump to the Project setup playbook to stand one up. If diagnostics is non-zero, run lettuce doctor --format json for the diagnosis and repair suggestions before touching anything.

The store root resolves through --root, then LETTUCE_ROOT, then config; in a repo the convention is a git-tracked .lettuce/.

Move 3 — see the shipped convention (the default is 88 dimensions)

Coverage grading runs on the one convention-as-data lettuce ships — bundled in the binary and active on every project by default, with nothing to enable. Read a project's effective dimensions (this needs a store root and --project):

lettuce dimension list --root .lettuce --project <P> --format plain # this project's EFFECTIVE dimensions
project    : <P>
pack       : coverage
dimensions:
  ID           SLUG  NAME                     FAMILY        …
  coverage-a   A     Functional correctness   correctness   …
  coverage-b   B     UX / DX (usability)      usability     …
  coverage-h   H     HTTP / API surface       interface     …
  …
count      : 88

The shipped default is coverage — lettuce's own 88-dimension quality taxonomy across 15 families, each dimension carrying a full methodology (Procedure / Best practices / Tools / Current approaches / Evaluation / Hardened). The pack: coverage line is the convention's internal identifier surfacing in the envelope — not a command you run. A dimension's slug is its coverage letter (A, B, H, …); read one axis in full with:

lettuce dimension show A --root .lettuce --project <P> --format json  # one axis + its methodology

Its state ladder is untested → planned → in_progress → gap → evidence_linked → smoke → hardened (plus blocked/regressed flagged and excluded/waived out-of-denominator); hardened is reached only through the guard-bite gate — a committed check that provably bites under fault-injection.

Add your own axis. On top of the shipped convention you can declare a project-specific dimension (strictly additive — it can never shadow the convention's vocabulary):

  • lettuce dimension declare <slug> --family <F> --applicability universal|conditional --project <P> --author <A> adds a project axis. See Dimensions.
  • To tune the ladder / gates / DoD for one project without authoring a new convention, use the defaults layer (covered in the setup playbook).
Move 4 — ask the store what to do next

If cells have been asserted, one command orients you and hands you a target:

lettuce board next --root .lettuce --project <P> --format plain

On an empty store this is honest, not an error:

board next · project <P> · 0 open cell(s)
  no open frontier — every cell is hardened or excluded.

Once there is coverage, board next ranks every scope weakest-first, prints a single start here pointer, and — if a Definition of Done is declared — leads with the DoD verdict line:

board next · project webapp · DoD: NOT DONE (0/2 scopes met) · 1 open cell(s)
  DoD bar: hardened
  ...
start here: auth / dim=test-coverage;scope=auth;unit=login  [Planned · Test coverage]
  ↳ detail: lettuce cell show "dim=test-coverage;scope=auth;unit=login" --project webapp

Every summarized line prints the exact lettuce … command to descend, so you are never stuck. --depth 0|1|2 deepens the report; --scope <name> restricts it to one scope.

You are now oriented — what to do with it

1. Read the DoD verdict first (lettuce dod show --project <P>), then take the single target board next hands you — don't hand-compose a coordinate. 2. Discover concrete work with lettuce task list --project <P> and lettuce query run … (FQL). 3. Drive the loop: claim a lease, transition status, do the work, record evidence, grade the cell. The full worked example is the Agentic loop demo.

See also

Links to

How to read lettuce — orienting in an existing store

↑ top

guides/guide-how-to-read

Before acting, an agent orients: board next for the frontier, FQL over tasks/cells/events, task show/audit, rollups and timelines, and the leading DoD verdict line — read machine-first with --format json.

How to read lettuce — orienting in an existing store

The first thing an agent does with an unfamiliar store is not act — it reads. lettuce is built so the store read forward is a plan and read backward is proof, and every reading surface is a pure, deterministic projection that never mutates. This guide is the orientation pass: what to read, in what order, and how to interpret the verdict.

The one-command orient: board next

Start here. board next distills the whole coverage board into an agent-facing orientation report — "what should I harden next?" — without exporting and re-parsing anything:

lettuce board next --project P --format json          # meters + start-here
lettuce board next --project P --depth 2 --format json # + weakest units + concrete coords
  • It is a pure read over the same BoardExport that board export/render produce: a project context is required — resolved from --project, else LETTUCE_PROJECT, else project: in config (an empty value counts as MISSING, not malformed — the resolver skips it, so an empty --project and no flag at all reach the same refusal) — and a MISSING context is refused FW-CMD-MISSING-PROJECT-CONTEXT while an INVALID name is refused FW-NAME-PROJECT (LET-264 split them). It reads only that project's board, never a cross-project scan.
  • Output is weakest-first: every scope's meter ranked, plus a single "start here" pointer (the globally weakest open cell).
  • --depth deepens detail: 0 (default) meters + start-here; 1 adds each scope's shape-aware subcounts; 2 adds the weakest units and the concrete gap/untested coordinates — each capped with an honest +N-more drill string, never a silent truncation.
  • --scope <slug> restricts the report; a slug that names no scope on the board is refused with the available list.

The frontier is the not-done, not-excluded, not-smoke cells (gap + untested). An empty board is not an error — every scope meter reads n/a. The report is self-guiding: each summarized node prints the exact lettuce … command to descend, so you are never stuck.

Reading the DoD verdict line

If the project has declared a Definition of Done, board next leads with it — the first line is the verdict:

DoD: NOT DONE (0/1 scopes met)

Read this first, before picking any target. The verdict is a strict per-scope AND-gate over applicable (non-excluded) cells — a scope is done only when every cell clears the bar, reported as a k/n count, never a blended percentage. Two consequences to internalize:

  • 100% hardened can still be NOT DONE. Setting a DoD never moves the hardened ratio; a scope may read fully hardened yet be unmet because its evidence is stale or too shallow (depth/recency floors).
  • Outer gates apply. Beyond per-scope coverage, overall DONE also requires every committed milestone reached and zero non-terminal tickets — visible via lettuce dod show as milestone_gate and ticket_gate.

A project that declared no floor reports declared=false and the board renders unchanged (DoD is opt-in).

The three freshness/depth/dod axes

The cells query source carries the DoD-derived axes that explain why a cell is or isn't done — the vocabulary the verdict is computed from:

| Axis | Values | Meaning | |---|---|---| | freshness | fresh | aging | stale | how current the cell's evidence is | | depth | int | distinct-revision confirmation count (FRESH-2) | | dod | blocking | met | is this cell blocking the Definition of Done | | dod-reason | grade | depth | recency | unknown | why a blocking cell blocks |

Reading these turns "what is not yet done?" into a precise query rather than a guess.

Querying with FQL over tasks, cells, and events

FQL reads the store deterministically: from SOURCE [where EXPR] [select f1,f2] [order by f [desc]] [limit N]. Strings use double quotes (single quotes are rejected).

# Work plane — what is in flight.
lettuce query run 'from tasks where status = active select task,title' --project P --format json
lettuce query tasks --group-by status --project P --format json        # bucketed counts

# Coverage plane — what remains, by axis.
lettuce query run 'from cells where dod = blocking select coordinate,state' --project P --format json
lettuce query run 'from cells where freshness = stale select coordinate'  --project P --format json
lettuce query run 'from cells where depth >= 2 select coordinate'         --project P --format json
lettuce query run 'from cells where dod-reason = grade select coordinate' --project P --format json

FQL has no dedicated scope/unit filter operator — slice by a coordinate member instead: where coordinate contains "scope=login". See scopes. Sources include tasks, events, cells, registry, authors, projects, dimensions; the cells source lists stored assertions only — sparse pack-defaults are never rows. Soft-archived tasks are hidden everywhere by default (--include-archived opts in).

Reading one object: task show and task audit
lettuce task show P/TASK-1 --with-body --format json   # or --full
lettuce task audit P/TASK-1 --format json              # full event history

Every mutation is an event, so task audit is the object's complete provenance — who did what, when, with which reason. Bodies are versioned, never edited in place, so the history is faithful.

Rollups and timelines — the aggregate reads
lettuce cell rollup --by test-coverage --project P --format json   # per-member floor + hardened ratio
lettuce query timeline --project P --kind object-created --format json
lettuce query timeline --project P --task P/TASK-1 --format json
  • cell rollup --by DIM pools a project's stored cells by one dimension: the floor (least-progressed) state, hardened count, non-excluded denominator, and ratio per observed member — N/A-excluded, never blended. This is where you see which axis is weakest before drilling with board next.
  • query timeline merges events chronologically, filterable by --task, --author, --kind, --since, --until — the history of the whole project or one object.
How an agent orients before acting

A disciplined orientation pass, in order:

1. Verdictboard next (reads the DoD: … line first): are we done, and what's blocking? 2. Frontier — the same report's weakest scope + start-here coordinate: where is the next target. 3. In-flight workquery tasks --status active and your held leases (lease list --holder <you>): what is already claimed, so you don't collide. 4. Provenance, if neededtask audit / query timeline on the target: why the cell is in its current state.

Only then act. The store, not your context, is your memory — read it first every cycle. See running lettuce in autonomous agentic cycles for the full orient → act → reflect → file loop.

Read machine-first: --format json

For any automated reader, pass --format json (or yaml). Every result is the stable envelope { ok, data, warnings, meta }; errors are { ok:false, error:{ code, message, diagnostics:[...] } } with machine-readable codes. Branch on the code, not the message text — diagnostics carry expected/actual, repairability, and suggested_actions, so the error tells you the fix. Exit codes are distinct too: 1 invalid input, 2 not found, 3 expected-revision mismatch, 6 interrupted operation requires recovery, 0 success.

See also

Links to

Retrying a mutation safely: --idempotency-key

↑ top

guides/guide-idempotent-mutations

Make a retried mutation land at most once with --idempotency-key: which commands accept it, how a replay identifies itself, what a reused key with a different payload does, and why the record is runtime-only.

Retrying a mutation safely: --idempotency-key

A retry is only safe if the second attempt can tell it is a second attempt. An agent whose network call times out does not know whether the mutation landed, and re-running it blind is how one intended task becomes two.

--idempotency-key closes that gap: the first call performs the mutation and remembers its response; a repeat of the same call with the same key returns that stored response instead of mutating again.

lettuce task create DEMO-1 --project demo --author agent-1 \
  --title "Wire the importer" --idempotency-key run-42-create-demo-1
A replay says so, in meta

This is the part worth wiring into a caller. The replay returns the original response — including the same operation_id — and marks itself:

first call    ok=true   operation_id=op-20260827-171309-067f48d57b6ddb4
replay        ok=true   operation_id=op-20260827-171309-067f48d57b6ddb4
                        meta.idempotency_replayed = true

So a caller distinguishes "my retry worked" from "my retry was a no-op because the first attempt had already succeeded" by reading meta.idempotency_replayed, not by comparing timestamps or diffing the store.

Reusing a key for a different mutation is refused

A key identifies one specific mutation, not a session or a batch. Reuse it with a different payload and lettuce refuses rather than guessing which one you meant:

FW-CMD-IDEMPOTENCY-CONFLICT: idempotency key was already used with a different mutation scope

There is a second, benign form of the same code: idempotency key is already in progress, raised when a concurrent call holds the same key. That one is worth retrying shortly; the mismatched-scope form is a bug in the caller and retrying will never help. Read the message, not just the code — they share it.

Only mutation commands accept it

The flag is refused, rather than silently ignored, on commands that do not support it:

lettuce doctor --idempotency-key k9
FW-CMD-USAGE: idempotency key is not supported for this command yet

Supported today: init; author add; project create, project author add; task create/set/unset/set-list/transition/body; version add; comment add/edit/status; lease acquire/renew/steal/release; run start/finish/log/summary; artifact add/replace; registry create/update; custom set/clear; and the milestone wrappers over registry. The command reference marks each command with idempotency key: true, which is the authoritative list — the enumeration above is a convenience and can age.

The record is runtime-only, and expires

The stored response lives under .runtime/idempotency/<key-hash>/ in the store directory — alongside a scope-hash (what the key was used for) and an expires-at. Two consequences worth knowing:

  • It does not travel with the store. .runtime/ is git-ignored and carries no tracked files, so a clone, an export or a fresh checkout starts with no idempotency history. A key that replayed on one machine will perform the mutation on another.
  • It expires after 24 hours. Past that, the same key is a fresh key and the mutation runs again. Idempotency here protects a retry loop, not a permanent record of "this was already done" — the store's own state is that record.
Choosing keys

Derive the key from the work, not from the clock: something like <run-id>-<step>-<target> is stable across a retry of the same step, which is exactly when you need it to match. A key containing a timestamp defeats the mechanism, because the retry generates a different one.

See also

Links to

Project setup playbook — prepare a project to leverage lettuce

↑ top

guides/guide-project-setup-playbook

Do-this-now setup: init and bootstrap, a decision procedure for designing YOUR scopes, choosing and ideating dimensions (with methodology), an evaluable Definition of Done via milestones and tickets, and a per-cycle hygiene checklist.

Project setup playbook — prepare a project to leverage lettuce

This is the do-this-now guide for turning a repository into a project lettuce can steer. By the end you have a store, a coverage model that fits your project, an evaluable Definition of Done, and the discipline to keep it honest.

Everything here is real — run each command. It builds on the concepts (Scopes, Dimensions, Cells, Milestones & DoD) for the what; this page supplies the how. New to lettuce? Read First contact first.

1. Init & bootstrap (store, project, author)

One idempotent command creates the store skeleton, a project, and your author:

ROOT=.lettuce; P=webapp; A=codex-01
lettuce init --root "$ROOT" --author "$A" \
  --bootstrap-project "$P" --bootstrap-author --idempotent --format plain
initialized /repo/.lettuce

Confirm health before anything else:

lettuce status --root "$ROOT" --format plain
# root=/repo/.lettuce mode=filesystem project= author= initialized=true diagnostics=0

Attribution discipline from command one: lettuce never infers --project or --author from the OS, Git, or store contents — pass both explicitly on every mutation. Pick a stable, non-secret author id (codex-01, ci-agent). Track .lettuce/ in git so the store travels with the repo (only .lettuce/.runtime/ is ignored). For tuning the client context (default root, mode, format), see Configuring lettuce for leverage.

2. The working model (the coverage convention)

Coverage grading runs on the one convention-as-data lettuce ships. The shipped default is coverage (lettuce's 88-dimension quality taxonomy across 15 families), and every project runs it by default — nothing to enable or choose.

The coverage convention ships 88 dimensions across 15 families, each carrying a full methodology (Procedure / Best practices / Tools / Current approaches / Evaluation / Hardened). Inspect it per project (needs a store root and --project):

lettuce dimension list  --root "$ROOT" --project "$P" --format json   # every dim + its methodology
lettuce dimension show A --root "$ROOT" --project "$P" --format json  # one axis in full

Its ladder is untested → planned → in_progress → gap → evidence_linked → smoke → hardened (plan, start, flag-gap, exercise/exercise-gap, link-evidence, harden [guard-bite gated], exclude/waive, block, regress).

> For the same convention with one project-specific adjustment (an extra > working state, an added edge or guard) you don't need another pack — record a > per-project tweak with the defaults layer.

3. Design YOUR scopes (a decision procedure, not a template)

A scope is a partition of the board scored separately and never blended — blending hides gaps. lettuce ships four scope archetypes as reference examples, not a mandatory template:

| Archetype | Shape | Row axis | Good for | |---|---|---|---| | s1 Feature | grid | a feature/command (unit=) | user-facing features × quality dims | | s2 Component | grid | a subsystem (unit=) | internal modules × quality dims | | s3 Product | scalars | none (rows are the dims) | one grade per whole-product axis | | s4 Ecosystem | ladder | a milestone | staged bets that mature over time |

The slugs s1s4 are magic: they carry those built-in shapes. Any other scope name (scope=auth, scope=checkout) is legal and gets a default heatmap shape. Do not force your project into s1s4. Instead:

The decision procedure. 1. Enumerate the real surfaces of work that need independent coverage — the things you would not want averaged together (e.g. auth, checkout, api, data-migration). Each becomes one scope. 2. Pick a shape per surface. A grid of units × dimensions? Reuse the s1/s2 archetype. One grade per axis for the whole product? s3. A staged hypothesis that matures (sellable, GA)? s4 + milestones. A flat set of items? use a named scope (heatmap). 3. Define "done" per scope — the grade floor each must reach (§5). 4. Keep scopes few and orthogonal. If two scopes always move together, they are one scope.

A named-scope board needs nothing but cells that carry a scope= member:

lettuce cell set "scope=auth;unit=login;dim=input-validation" --state in_progress \
  --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce cell set "scope=checkout;unit=cart;dim=test-coverage" --state planned \
  --root "$ROOT" --project "$P" --author "$A" --format plain

To get the richer archetype shapes (grid/scalars/ladder) and real row names, declare scope/unit as dimensions and use the magic slugs — see the worked recipe in lettuce skill ("Standing up a coverage board from scratch"):

lettuce dimension declare scope --family interface --applicability universal \
  --name "Scope" --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce dimension member add scope s2 --name "Component" \
  --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce dimension declare unit --family interface --applicability universal \
  --name "Command / unit" --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce dimension member add unit store --name "store" \
  --root "$ROOT" --project "$P" --author "$A" --format plain
# an S2 component-grid cell (has a unit row):
lettuce cell set "dim=am;scope=s2;unit=store" --state gap --reason "durability not yet proven" \
  --root "$ROOT" --project "$P" --author "$A" --format plain

> A cell that declares no scope= is bucketed under the reserved unscoped > scope at evaluation — never silently outside the DoD frame. scope=unscoped > is refused (FW-NAME-RESERVED).

4. Units & dimensions per scope
4a. Pick from the shipped palette

Each cell grades a unit (a row: a command, a subsystem) along a dimension (a quality axis). Start from the active pack's dimensions as a palette:

lettuce dimension list --root "$ROOT" --project "$P" --format plain   # this project's EFFECTIVE set
lettuce dimension show A --root "$ROOT" --project "$P" --format plain  # one axis in full

Read a dimension's methodology before grading any of its cells — it is what separates a shallow smoke grade from a hardened one. For coverage dim D (Data integrity):

Procedure: exercise the write path; assert ATOMICITY (write-temp-then-atomic-
  rename or a WAL) and DURABILITY (fsync the file AND its parent dir before ack);
  inject a torn/partial write (crash mid-write, truncated temp, kill -9) and assert
  the store stays consistent + read-back returns the exact bytes. Then name the
  isolation level and prove the anomalies it forbids don't occur.
Best practices: make the ACID story EXPLICIT; writes are write-temp-then-atomic-
  rename never in-place; never ack before durable; "validated but never persisted"
  is a real bug class, so read the canonical file back and assert exact bytes.
Tools: atomic rename(2), fsync/fdatasync + directory fsync, WAL engines (SQLite
  WAL, LMDB, BoltDB); Jepsen elle for isolation; ALICE/CrashMonkey crash injection.
Current approaches: MVCC + snapshot isolation as the default; serializable via SSI;
  elle infers isolation anomalies from histories; deterministic simulation.
Evaluation: atomicity (no torn write survives a crash); durability (an fsync'd
  write survives power loss); isolation (forbidden anomalies never observed);
  multi-object atomicity (a reader never sees a partial commit).
Hardened: a committed torn/partial-write guard bites (green → break → RED → green)
  if atomicity/durability is removed; layer an isolation guard + a fsync-durability
  guard. Distinct lens vs F (F = in-process race-safety; D = the store's contract).
4b. Ideate a custom dimension (with its methodology)

When your project's nature needs an axis no pack ships, declare one. It is strictly additive — it can add axes and members but never shadow pack vocabulary. Ideate it in four parts:

1. Name the risk — the failure this axis guards against (e.g. "a schema migration corrupts or loses data under partial failure"). 2. Pass criterion — what "covered" means (migrations reversible + loss-free under injected partial failure). 3. Methodology — the procedure an agent follows to grade a unit on it (Procedure / Best practices / Tools / Current approaches / Evaluation / Hardened), so the axis is gradeable, not decorative. 4. Hardened-evidence bar — what a bite-proven guard must do.

Declare it (--family must be one of the active pack's families):

lettuce dimension declare data-migration --family reliability --applicability conditional \
  --name "Data migration safety" \
  --description "Schema/data migrations are reversible and loss-free under partial failure." \
  --root "$ROOT" --project "$P" --author "$A" --format plain
# dimension declare ok
lettuce dimension show data-migration --root "$ROOT" --project "$P" --format plain

Add first-class members if the axis enumerates values:

lettuce dimension member add data-migration forward --name "Forward migration" --rank 10 \
  --root "$ROOT" --project "$P" --author "$A" --format plain
# dimension member add ok

> Honest limitation (current build): dimension declare persists a one-line > description but has no methodology field — only shipped pack > dimensions carry the structured six-facet (Procedure / Best practices / Tools / > Current approaches / Evaluation / Hardened) text. So write your > custom dimension's full methodology somewhere durable anyway (a project doc, > a pinned cell note, or the proving task's body), because a dimension without > a methodology is incomplete. For a methodology that travels with the binary, > prefer a coverage-pack dimension or contribute your axis + methodology to a > pack. Do not assert grades on an axis whose methodology you have not written > down.

5. A Definition of Done that's actually evaluable

Turn "done" from an assertion into a measurement. Represent the plan as milestones + tickets, then declare the grade floor so board next can compute a verdict.

# Frame outcomes as milestones (the hypothesis ladder / S4 rungs).
lettuce milestone create v1-launch --title "v1 launch" \
  --root "$ROOT" --project "$P" --author "$A" --format plain
lettuce milestone list --root "$ROOT" --project "$P" --format plain
# webapp/milestone/v1-launch

# Declare the bar: the minimum grade every cell must reach to count as done.
lettuce dod set --grade hardened --root "$ROOT" --project "$P" --author "$A" --format plain
# dod set ok  (add --depth N / --recency for confirmation-depth + freshness floors,
#              or --scope S to override one scope's floor)

Now the DoD is a live verdict — a strict per-scope AND-gate plus outer milestone and ticket gates:

lettuce dod show --root "$ROOT" --project "$P" --format plain
project  : webapp
declared : true
grade    : hardened
verdict:
  coverage_met   : false
  met_scopes     : 0
  milestone_gate:
    met     : false
    reached : 0
    total   : 1
  scopes:
    APPLICABLE  BLOCKED_GRADE  MET  SCOPE     VERDICT
    2           1              1    auth      unmet
    1           1              0    checkout  unmet
  ticket_gate:
    met   : false
    open  : 1
    total : 1
  total_scopes   : 2
  verdict        : unmet

How tickets map to units. A cell is the address of work; a task is the work. The disciplined loop is: board next names a weak cell → you create a ticket to fix it → link that finished ticket as the cell's evidence → the guard-bite gate then authorizes harden. DoD's ticket_gate refuses "done" while any ticket is still open, and milestone_gate refuses it until every committed milestone is reached — so the verdict reflects both proven coverage and closed work. The full closing loop is the Agentic loop demo.

6. Hygiene & discipline — the per-cycle checklist

The map only steers if it stays truthful. Every cycle:

  • [ ] Orient from board next, take its target. Don't hand-pick coordinates; act on the one the store surfaces (weakest scope, weakest cell first).
  • [ ] Read the dimension's methodology before grading any cell on it.
  • [ ] Flip cells with cell transition (gated), never cell set --state hardened. cell set asserts a state directly and bypasses the guard-bite gate — an unproven green. Use cell set only for planned / blocked / waived / seeding. Reach hardened through the gated transition with a real proving task linked as evidence.
  • [ ] One ticket per finding. Discover a defect mid-work? File it as its own cell (cell set --state gap/planned) + ticket so the next ORIENT sees it.
  • [ ] Never --facilitate past a failed gate to "make progress" — one unproven green poisons every future orientation.
  • [ ] Keep the board and tickets current — close tickets, harden cells, and let cell reconcile machine-regress stale greens whose evidence unresolved.
  • [ ] Validate after structural worklettuce validate --strict and lettuce doctor --format json after import/repair/conflict resolution.
  • [ ] Re-orient. Run board next again; confirm the frontier moved for a real reason (a hardened cell, a filed finding), not drift.
See also

Links to

Serving lettuce safely (HTTP)

↑ top

guides/guide-server-security

lettuce serve is fail-closed by design (ADR-0008): a non-loopback listener with no shared secret refuses to start. Covers the serve surface, bearer auth, per-actor identity, rate gates, IP allowlists, and what is safe to expose.

Serving lettuce safely (HTTP)

The same binary that is a CLI is also an HTTP server: lettuce serve exposes the store over HTTP so the identical CLI, pointed at it in client mode, can drive it remotely. Exposing a store to the network is a security decision, and lettuce is built fail-closed so the unsafe path is the one you have to opt into explicitly.

The fail-closed model (ADR-0008)
lettuce serve --root . --listen 127.0.0.1:8727      # safe default: loopback only

The default listen address is 127.0.0.1:8727loopback only, reachable solely from the same host. The invariant:

> A non-loopback --listen with no shared secret refuses to start.

A secret can come from any of --secret, --secret-file, LETTUCE_API_SECRET, or LETTUCE_API_SECRET_FILE. If none is present and you bind to a non-loopback address, startup refuses unless you pass --allow-unauthenticated-nonloopback — and even then startup warns. You cannot accidentally serve an unauthenticated store to the network; you have to state the override in words.

The serve surface

serve is kind: server — it requires a root but neither a project nor an author (those arrive per-request). Its flags:

| Flag | Env | Purpose | |---|---|---| | --listen ADDR | LETTUCE_LISTEN | Listen address (default 127.0.0.1:8727; non-loopback requires a secret) | | --secret SECRET / --secret-file PATH | LETTUCE_API_SECRET (_FILE) | The bearer token secret | | --allow-ip IP-OR-CIDR | LETTUCE_ALLOWED_IPS | Allowed client IP/CIDR (repeatable) | | --trusted-proxy-cidr IP-OR-CIDR | — | Trusted proxy source range (repeatable) | | --rate-ip-rpm RPM | LETTUCE_RATE_IP_RPM | Per-IP requests/minute (ADR default 600) | | --rate-actor-mutation-rpm RPM | LETTUCE_RATE_ACTOR_MUTATION_RPM | Per-actor mutating requests/minute (default 300) | | --rate-global-mutation-rpm RPM | LETTUCE_RATE_GLOBAL_MUTATION_RPM | Global mutations/minute across all actors (default 60) | | --rate-burst N | LETTUCE_RATE_BURST | Per-IP burst: max requests in a 1s window (default 60) | | --rate-limit RPM | LETTUCE_RATE_LIMIT | Legacy per-IP limit (seeds --rate-ip-rpm) | | --authz-policy PATH | LETTUCE_AUTHZ_POLICY_FILE | Authorization policy JSON file | | --auth-subject SUBJECT | — | Authenticated subject name | | --auto-provision-actors | LETTUCE_AUTO_PROVISION_ACTORS | Create missing X-Lettuce-Actor authors for authorized mutations | | --allow-unauthenticated-nonloopback | — | Explicitly permit a non-loopback listener WITHOUT a secret (warns) | | --recover-on-start | LETTUCE_RECOVER_ON_START | Self-heal a crashed prior writer (dedicated-git) — discards uncommitted torn state | | --push-interval DURATION | LETTUCE_PUSH_INTERVAL | Auto-push to git remote at interval (dedicated-git only) |

Endpoints

GET / and GET /SKILL.md serve the embedded agent guide unauthenticated — this is intentional: the guide is public documentation, not store data. The store API lives under /v1/… (for example, DELETE /v1/projects/{project}/dod clears a Definition of Done) and is what the shared secret protects.

Auth and identity posture

lettuce serve does have an auth mechanism — it is a shared-secret bearer model plus a per-actor identity header:

  • Bearer secret (authentication). The --secret is a shared bearer token. Clients present it as --bearer / LETTUCE_BEARER (_FILE). Requests to /v1/… without a valid bearer are rejected. This is a shared secret, not per-user credentials.
  • Actor identity (attribution). A client also sends its acting author via the X-Lettuce-Actor header (LETTUCE_ACTOR in client mode). Because mutations must be attributed, an unknown actor is refused unless --auto-provision-actors is set (which creates the missing author for authorized mutations).
  • Authorization policy (optional). --authz-policy PATH points at an authorization policy JSON file, with --auth-subject naming the authenticated subject. The sources describe the flags but not the schema/contents of that policy file — treat the policy format as a binary detail to read from lettuce usage serve and the shipped spec, not something to guess at here.

> Honest gap: the gold sources describe the transport as plain HTTP and > document no built-in TLS termination. For any remote exposure, terminate TLS at a > trusted fronting proxy — the --trusted-proxy-cidr flag exists precisely to name > that proxy's source range so client-IP allowlisting still works behind it. Do not > assume the served port encrypts traffic on its own; the sources do not claim it.

Rate limiting (ADR-0003)

Four independent gates bound abuse, each with an ADR default: per-IP requests (--rate-ip-rpm, 600), per-actor mutations (--rate-actor-mutation-rpm, 300), global mutations (--rate-global-mutation-rpm, 60), and per-IP burst (--rate-burst, 60 in a 1s window). The legacy --rate-limit seeds the per-IP gate. Tighten these below the defaults for a public-facing instance.

Local vs remote exposure

| Exposure | How | Posture | |---|---|---| | Loopback (default) | --listen 127.0.0.1:8727 | Same-host only. No secret required; safe for a local agent driving its own store over HTTP. | | Trusted LAN | non-loopback --listen + secret + --allow-ip CIDR | Secret mandatory (fail-closed). Restrict clients with IP allowlists. | | Public / remote | non-loopback + secret + allowlist + TLS-terminating proxy + tight rate gates | Every guard on. Front with a proxy for TLS (see honest gap above); name it with --trusted-proxy-cidr. |

Never reach for --allow-unauthenticated-nonloopback on anything beyond a fully trusted, isolated network — it is the deliberate override of the whole fail-closed model, and startup warns for a reason.

Driving a served instance (client mode)

Point the identical CLI at the server instead of mounting the store:

export LETTUCE_SERVER_URL=https://lettuce.example:8727   # or --server-url
export LETTUCE_BEARER_FILE=/run/secrets/lettuce-bearer   # or --bearer
export LETTUCE_ACTOR=agent-1                             # X-Lettuce-Actor identity
lettuce task list --project P --format json              # dispatched over HTTP

Almost every command works over the HTTP client — the authoritative per-command answer is the kind field of lettuce usage <cmd> --format json. The narrow exceptions are refused in client mode: serve itself, sync status/push/pull, and github init-repo (they act on a local process or the local working copy + Git remote), plus the bulk/confirmation cell ops (cell set-where, clear-where, verify, affirm, local import) which are local / dedicated-git only.

What is and isn't safe to expose
  • Safe by default: loopback serve for a co-located agent; the / and /SKILL.md guide endpoints (public docs by design).
  • Safe with the guards on: non-loopback serve with a secret, an IP allowlist, tuned rate gates, and TLS terminated at a trusted proxy.
  • Not safe: any non-loopback listener without a secret. lettuce refuses it unless you explicitly override — take the refusal as the correct answer rather than reaching for the override.
See also

Links to

Driving lettuce from a file: structured external input

↑ top

guides/guide-structured-external-input

Supply command fields from a JSON or YAML envelope with --from-json / --from-yaml: the wrapper, what the envelope may not set, how it merges with CLI flags, how YAML scalars are converted, and the refusals you will actually hit.

Driving lettuce from a file: structured external input

Most commands take their fields as flags. When the values come from another program — a generator, a form, an agent assembling a task body — putting them on a command line means quoting prose into a shell, and that is where multi-line bodies and apostrophes go wrong.

--from-json and --from-yaml take those fields from a file instead. The command is still named on the command line; only its field values move into the envelope.

The wrapper is required

Both flags accept the same envelope. The wrapper is not optional and not inferred — a bare object of fields is refused.

schema_version: v0.16
kind: lettuce-command-input
data:
  task_id: DEMO-1
  title: Wire the importer
  body: |
    Multi-line prose, apostrophes, "quotes" — none of it touches a shell.
{"schema_version":"v0.16","kind":"lettuce-command-input",
 "data":{"task_id":"DEMO-1","title":"Wire the importer","body":"..."}}
lettuce task create --project demo --author agent-1 --from-yaml ./new-task.yml

A wrong schema_version is refused FW-CMD-USAGE (unsupported external input schema_version), and only schema_version, kind and data are accepted at the top level.

Not every command accepts an envelope

The support check runs before the file is parsed, so a command that does not accept external input tells you that plainly instead of complaining about your file:

lettuce doctor --from-yaml ./anything.yml
FW-CMD-USAGE: --from-yaml is not supported for this command

That ordering matters when you are debugging: a message about the file means the command was accepted and the payload is the problem.

The envelope cannot set your execution context

data may carry a command's own fields. It may not carry the trusted context or anything credential-shaped — root, project, author, config, format, mode, bearer, token, PATs, listen addresses and proxy/rate settings are all refused:

FW-CMD-CONTEXT-IN-EXTERNAL-INPUT: external input cannot set trusted execution context

This is deliberate. A file you received decides what to record; it never decides which store it lands in, who it is attributed to, or what credentials are used. Those stay on the command line, where the operator sets them. The scan is recursive, so a denied key nested deep in the payload is caught too.

CLI flags win; the envelope fills the gaps

The two sources compose rather than conflict, and the rule is one-directional:

> A value supplied on the command line always wins. The envelope only fills > fields the command line did not supply.

envelope: title: from-envelope
command:  --title from-flag
stored:   from-flag

The same holds for positionals, by index: a CLI positional keeps its own slot and the envelope supplies only the slots you left empty. So you can keep one envelope as a template and override a single field per invocation without editing it.

How YAML scalars are converted

YAML resolves unquoted scalars to types, and lettuce converts them back to the text the command would have received as a flag. For a string field, every one of these round-trips to its literal bytes:

| You write | Stored in a string field | Why | |---|---|---| | 007 | 007 | integer literal preserved, not renumbered | | 0x10 | 0x10 | not converted to 16 | | True | True | casing preserved (see below) | | 2026-01-02T03:04:05Z | 2026-01-02T03:04:05Z | timestamp kept as text | | << | << | merge token kept as text | | yes | yes | not a boolean in YAML 1.2 |

The reason is a single principle: the downstream validator is the one source of truth about a value. If the YAML layer silently reshaped values, the same input would mean different things through --from-yaml than through --from-json or a plain flag.

True/TRUE/False/FALSE are the case worth calling out, because YAML does resolve them to booleans. A string field keeps your literal casing; a genuine boolean field (--force, --idempotent, --bootstrap-author, --dry-run) still resolves normally, so force: True and force: true both work.

A null carries no value at all — supplying a required field as null fails exactly as if you had omitted it.

Rejected outright, so an envelope cannot mean two things: anchors, aliases, explicit tags, duplicate object keys, and non-string object keys.

Limits and refusals worth knowing

| Condition | Result | |---|---| | File larger than 64 MiB | refused before any write | | Container nesting deeper than 128 | external input nesting is too deep | | Duplicate key at any level | refused (both JSON and YAML) | | A file path escaping the store root | FW-PATH-ESCAPES-ROOT |

The size and nesting checks run before any mutation, so a rejected envelope never leaves a half-written store.

A note on where the file lives

Keep envelopes outside the store root. The store validates its own top-level paths, so a stray .yml inside --root is refused FW-PATH-UNKNOWN: unknown top-level store path — a confusing error to hit while debugging an unrelated payload.

See also

Links to

index

↑ top

index reserved

No description.

Lettuce Wiki

The source-of-truth knowledge bundle for lettuce, maintained in the lettuce repository itself. It has two layers:

  • Curated — concepts, guides, and orientation, authored by humans/agents and gated by okf check.
  • Generated — the Command Reference, emitted from the binary by lettuce usage --format okf and regenerated by make docs. Never hand-edit anything under reference/.
Orientation
Concepts
Guides

Agent Playbook — do-this-now guides for driving lettuce at full power:

Reference guides:

Reference (generated)
  • Command Reference — the exhaustive CLI surface, regenerated from the binary by make docs.

Links to

+12 more

What is lettuce

↑ top

overview

lettuce is a local-first, filesystem-native work tracker and coverage/quality store for humans, agents, and small teams — canonical state as ordinary validated files.

What is lettuce

lettuce is a local-first, filesystem-native work tracker and coverage/quality store for humans, agents, and small technical teams that need inspectable work state. Canonical state — projects, tasks, comments, runs, artifacts, cells — lives as ordinary files inside a path-jailed store root. Every mutation is validated and recorded as an event. The same binary is a CLI and an HTTP server, and the same CLI becomes an HTTP client when a server URL is set.

Thesis

Most work trackers optimize for hosted workflows and opaque databases. lettuce optimizes for the opposite:

  • plain files that can be inspected and reviewed
  • deterministic validation before and after mutations
  • stable task references for agents and automation
  • Git-friendly history for dedicated stores
  • structured diagnostics that explain repair paths
  • CLI-first workflows before server or UI complexity
  • HTTP-client mode for agents that should not mount the canonical store
Why filesystem-native

The filesystem is the product boundary. Because canonical state is ordinary files, users and agents can review exact changed paths, validate state without a running server, recover interrupted local work, attach Git history to each mutation (in dedicated-git mode), and debug with normal shell tools. This is a deliberate tradeoff: lettuce is not a high-volume database, a real-time collaboration server, or a dashboard-first planning suite in v0.15.

Who it's for
  • Solo engineers — create a local store, track tasks, query current work, optionally review changes through Git.
  • Agents — discover work, claim it with leases, record execution runs, attach artifacts, and act on structured diagnostics without editing canonical files directly.
  • Small teams — project-local work state with explicit author attribution, optional HTTP authorization, and reviewable mutations.
  • Tool integrators — stable JSON envelopes, diagnostic codes, and filesystem fixtures over a hosted UI.
Next

Links to

Authors And Projects — Commands

↑ top

reference/cmd-authors-and-projects

lettuce Authors And Projects commands — 15 entries — author add, author list, project create, project set-name, project rename, project merge, project list, project show, project archive, project unarchive, project delete, project id-block grant, project id-block list, project author add, project au

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Authors And Projects — Commands

lettuce command group Authors And Projects — 15 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • author add
  • author list
  • project create
  • project set-name
  • project rename
  • project merge
  • project list
  • project show
  • project archive
  • project unarchive
  • project delete
  • project id-block grant
  • project id-block list
  • project author add
  • project author list

---

Manage root authors, projects, and project author membership.

author add

Usage: lettuce author add AUTHOR [--idempotent]

Create a root author.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): name
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --idempotent - Treat an existing author as success.

Examples:

lettuce author add agent-1 --idempotent --format json
lettuce author add agent-1 --idempotent --format plain
author list

Usage: lettuce author list

List root authors.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce author list --format json
lettuce author list --format plain
project create

Usage: lettuce project create PROJECT [--name NAME] [--description TEXT] [--bootstrap-author] [--idempotent] [--yes] [--force]

Create a project skeleton and bootstrap registry objects. Optionally sets a human display name/description (persisted at projects/<slug>/name, /description). Creating an ADDITIONAL project into a store that already holds one requires --yes.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): name, bootstrap_author
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --name text - Optional human display name (defaults to the slug on the board title when unset).
  • --description text - Optional human description of the project.
  • --bootstrap-author - Create/link the acting author as project author.
  • --idempotent - Treat an existing valid project as success.
  • --yes - Confirm creating an ADDITIONAL project in a store that already holds one (also accepts --force).
  • --force - Alias of --yes: confirm an additional project.

Examples:

lettuce project create lettuce --name Lettuce --author agent-1 --bootstrap-author --format json
lettuce project create lettuce --author agent-1 --bootstrap-author --idempotent --format plain
lettuce project create sandbox --author agent-1 --bootstrap-author --yes --format json

Notes:

  • A store normally holds exactly ONE project: the board, cell coverage, run-cases and most queries are project-scoped, so a store split across several projects has no single view able to relate its tickets, cells and run-cases. Creating a SECOND project is therefore refused with FW-PROJECT-ADDITIONAL-UNCONFIRMED (naming the projects already present) unless --yes (or --force) is passed. This is a confirmation, not a ban — multi-project stores stay fully supported. The FIRST project of an empty store is never gated, and re-running create for a project that already exists (with or without --idempotent) is unaffected because it adds no project. Over HTTP the same guard applies and the acceptance is "confirm": true in the POST /v1/projects body.
project set-name

Usage: lettuce project set-name PROJECT --name NAME [--description TEXT]

Set or update an existing project's human display name (and optional description). The board title renders this name in place of the slug. Emits a project-updated lifecycle event.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --name text - Human display name to set (required; empty OR whitespace-only clears back to the slug default). Required.
  • --description text - Optional human description to set (empty or whitespace-only clears it).

Examples:

lettuce project set-name dashboard --name Lettuce --author agent-1 --format json

Notes:

  • Names an EXISTING project; use lettuce project create --name to name a project at creation time. The board title (board render) prefers this name over the project slug.
project rename

Usage: lettuce project rename OLD NEW

Rename a project's slug: move projects/OLD to projects/NEW AND rewrite every stored OLD-qualified reference (event targets, cross-object depends-on/blocks refs, object refs) so the renamed store stays strict-valid. A whole-store structural migration, applied atomically under the mutation lock. Preserves the display name and all data.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce project rename dashboard lettuce --author agent-1 --format json

Notes:

  • OLD and NEW are POSITIONAL slug arguments (not --project). Refuses if OLD does not exist (FW-PATH-NOT-FOUND), NEW already exists (a collision), or NEW is an invalid slug (FW-NAME-SLUG). REFUSES (FW-PROJECT-REF-REWRITE-UNSAFE, writing nothing) when a reference to OLD is folded into a CONTENT-ADDRESSED identity — a graph-run-case advance event or a carrier directory is named by the hash of its own payload, so rewriting such a ref would leave the object no longer addressing its own content. On any failure the store is left byte-unchanged (atomic). Verify after with lettuce validate --strict.
project merge

Usage: lettuce project merge SRC DST

Fold project SRC into project DST and remove the emptied SRC: every task, cell, artifact, comment, run, saved query, graph-def and run-case MOVES into DST, shared registry vocabulary is reconciled, and every stored SRC-qualified reference is rewritten to DST so the merged store stays valid. Rename's sibling whole-store structural migration, applied atomically under the mutation lock. Nothing is ever overwritten, auto-renamed, or silently dropped.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce project merge merge-healing lettuce --author agent-1 --format json

Notes:

  • SRC and DST are POSITIONAL slug arguments (not --project); BOTH must already exist. REFUSES the whole merge, writing nothing, when an object id or cell coordinate exists in BOTH projects (FW-PROJECT-MERGE-CONFLICT naming every collision) or when a registry slug both projects share differs SEMANTICALLY (the differing field is named; created/updated/revision provenance is ignored). A shared slug that matches keeps DST's copy; SRC-only objects and vocabulary move in; SRC's own display name/description are dropped with the dissolved project and echoed in dropped_source_meta. Also refuses (FW-PROJECT-REF-REWRITE-UNSAFE) when a reference to SRC is folded into a CONTENT-ADDRESSED identity (a graph-run-case advance event or a carrier directory is named by the hash of its own payload, which includes recorded effect/enrichment refs). On any failure the store is left byte-unchanged (atomic). Verify after with lettuce validate --strict.
project list

Usage: lettuce project list [--include-archived]

List project names. Archived projects are hidden unless --include-archived is passed; when they are included, the result marks which of the returned rows are archived.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --include-archived - Include archived projects in the results (hidden by default).

Examples:

lettuce project list --format json
lettuce project list --include-archived --format plain

Notes:

  • With --include-archived the JSON result carries an archived array naming which entries of projects are archived (LET-359). Before that, the inclusive listing returned archived and live projects in ONE flat list with nothing to tell them apart, so a caller who asked to SEE archived rows could not IDENTIFY them. Without the flag the key is omitted entirely and the output is byte-identical to the default listing.
project show

Usage: lettuce project show PROJECT

Show project metadata, authors, registry summary counts, and archived_at when archived. A successful read reflects THIS project's own consistency only (LET-1434 scoped gate): corruption in an unrelated part of the store is surfaced by doctor / validate --strict, not refused here.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce project show lettuce --format json
lettuce project show lettuce --format plain
project archive

Usage: lettuce project archive PROJECT [--reason TEXT]

Soft-archive a project: hide it from default project list and refuse new task create, without deleting history. Reversible with lettuce project unarchive.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Optional reason recorded on the archive event.

Examples:

lettuce project archive lettuce --author agent-1 --reason 'Retired.' --format json

Notes:

  • Archived projects are hidden from project list unless --include-archived is passed, and refuse new task create until restored. This is reversible and preserves history.
project unarchive

Usage: lettuce project unarchive PROJECT [--reason TEXT]

Restore a previously archived project back to normal visibility and re-permit new task create.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Optional reason recorded on the unarchive event.

Examples:

lettuce project unarchive lettuce --author agent-1 --format json

Notes:

  • Only an archived project can be unarchived; the inverse of lettuce project archive.
project delete

Usage: lettuce project delete PROJECT --yes [--cascade] [--force]

Permanently delete a project and all its history. Irreversible (unlike project archive, there is no undo). A non-empty project is refused unless --cascade is passed. Requires --yes to confirm.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --yes - Confirm the irreversible delete (also accepts --force).
  • --force - Alias of --yes: confirm the irreversible delete.
  • --cascade - Also delete the project's tasks when it is non-empty.

Examples:

lettuce project delete lettuce --author agent-1 --yes --format json
lettuce project delete lettuce --author agent-1 --yes --cascade --format plain

Notes:

  • Irreversible: prefer project archive when you may need the project or its history again. An empty project deletes with just --yes; a non-empty one needs --cascade.
project id-block grant

Usage: lettuce project id-block grant PROJECT AUTHOR --prefix PREFIX --start N --size N

Reserve a disjoint range of task ids to one author so task create --next cannot mint an id another clone already used. Refused if the range overlaps an existing grant.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --prefix PREFIX - Id prefix the block applies to (LET, BUG). Blocks under different prefixes never conflict. Required.
  • --start n - First id in the block, inclusive. Required.
  • --size n - How many ids the block holds. Required.

Examples:

lettuce project id-block grant lettuce speedman --prefix LET --start 2000 --size 100 --author jota --format json

Notes:

  • The guarantee is DISJOINTNESS: an id inside a granted block cannot have been minted by another author, including in a clone this machine has never seen. That is why an overlapping grant is refused rather than merged.
  • An author holding no block is unaffected and still allocates from the highest id in the local tree, with the FW-CMD-ID-ALLOCATED-FROM-LOCAL-TREE warning that says so.
  • Run 'lettuce project id-block list PROJECT' first to see which ranges are already held.
project id-block list

Usage: lettuce project id-block list PROJECT

List every id block granted in a project, with each range's first and last id.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce project id-block list lettuce --format json

Notes:

  • Read this before granting: a grant that overlaps an existing block is refused, and this is the only way to see which ranges are taken.
project author add

Usage: lettuce project author add PROJECT AUTHOR [--bootstrap-author] [--idempotent]

Link an author into a project.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): project_name, target_author, bootstrap_author
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --bootstrap-author - Create the root author if missing.
  • --idempotent - Treat an existing link as success.

Examples:

lettuce project author add lettuce agent-2 --author agent-1 --bootstrap-author --format json
lettuce project author add lettuce agent-2 --author agent-1 --idempotent --format plain
project author list

Usage: lettuce project author list PROJECT

List authors linked to a project.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce project author list lettuce --format json
lettuce project author list lettuce --format plain

Links to

Cells — Commands

↑ top

reference/cmd-cells

lettuce Cells commands — 28 entries — cell list, cell rollup, cell evidence list, cell evidence add, cell evidence remove, cell gate check, cell show, cell set, cell clear, cell set-where, cell clear-where, cell note, cell import, cell transition, cell verify, cell affirm, board export, board next

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Cells — Commands

lettuce command group Cells — 28 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • cell list
  • cell rollup
  • cell evidence list
  • cell evidence add
  • cell evidence remove
  • cell gate check
  • cell show
  • cell set
  • cell clear
  • cell set-where
  • cell clear-where
  • cell note
  • cell import
  • cell transition
  • cell verify
  • cell affirm
  • board export
  • board next
  • board render
  • cell reconcile
  • dimension list
  • dimension show
  • dimension member list
  • dimension member add
  • dimension member update
  • dimension declare
  • dimension rename
  • dimension close

---

Assert and inspect per-project coverage cells — the coordinate/state grid governed by the project's effective dimensions, states, and gates.

cell list

Usage: lettuce cell list --project PROJECT

List a project's STORED cells — the explicitly-asserted coordinates and their states; the sparse pack-default space is not enumerated.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce cell list --project lettuce --format json
lettuce cell list --project lettuce --format plain
cell rollup

Usage: lettuce cell rollup --by DIMENSION --project PROJECT

Roll a project's stored cells up by one dimension: the pooled floor (least-progressed) state, hardened count, non-excluded denominator, and ratio per OBSERVED member (N/A-excluded, never blended).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --by dimension - Dimension to roll the project's stored cells up by (pooled floor, hardened count, non-excluded denominator, and ratio per observed member). Required.

Examples:

lettuce cell rollup --by A --project lettuce --format json
lettuce cell rollup --by A --project lettuce --format plain
cell evidence list

Usage: lettuce cell evidence list COORDINATE --project PROJECT

List the evidence links on a cell (index, kind, ref).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce cell evidence list area=auth;layer=api --project lettuce --format json
lettuce cell evidence list area=auth;layer=api --project lettuce --format plain
cell evidence add

Usage: lettuce cell evidence add COORDINATE --ref REF --kind KIND --project PROJECT

Link evidence to an asserted cell (kind task=an existing task ref, validated; url=an opaque external reference); records a cell-evidence event.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --ref ref - Evidence reference: an existing task ref (with --kind task, validated to exist) or an opaque external reference (with --kind url). Required.
  • --kind kind - Evidence kind: task (ref validated to exist) or url (any non-empty opaque string). Required.

Examples:

lettuce cell evidence add area=auth;layer=api --ref lettuce/LET-1 --kind task --project lettuce --author agent-1 --format json

Notes:

  • The cell must already be asserted (cell set/transition). A task ref is validated to exist; url is any non-empty string.
cell evidence remove

Usage: lettuce cell evidence remove COORDINATE --index N --project PROJECT

Remove one evidence link (addressed by its numeric index — see cell evidence list) from an asserted cell; records a cell-evidence-remove event. The inverse of cell evidence add — unblocks zero-based re-validation (drop stale evidence so a guard-bite gate must be re-proven on fresh evidence).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --index n - Numeric index of the evidence link to remove (as shown by cell evidence list); a missing index or one with no entry is refused FW-PATH-NOT-FOUND. Required.

Examples:

lettuce cell evidence remove area=auth;layer=api --index 2 --project lettuce --author agent-1 --format json

Notes:

  • The cell must be asserted and carry an evidence entry at the given index. Surviving links keep their indices (no renumber).
cell gate check

Usage: lettuce cell gate check COORDINATE --gate SLUG --project PROJECT

Evaluate one gate declared by the active pack against a cell, returning {gate, coordinate, passed, reason}. Built-in evaluators: consistency (a STORE-WIDE predicate: the whole store root validates clean. It IGNORES the COORDINATE, so every cell in the store gets the same verdict, and it is not project-scoped either — a fault in another project sharing the root fails this check) and guard-bite (the cell carries >=1 AUTHORISING evidence link — a task link that still RESOLVES to a DONE task carrying custom/grc, so a link citing a DELETED task is a phantom and fails; a url link is stored and counted as evidence but ANNOTATES ONLY and cannot open a gated state, so a cell whose only evidence is a url still fails). Read-only; an unknown gate is refused FW-GATE-UNKNOWN.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --gate slug - Gate slug to evaluate (built-in evaluators: consistency, guard-bite); an unknown gate is refused FW-GATE-UNKNOWN. Required.

Examples:

lettuce cell gate check area=auth;layer=api --gate guard-bite --project lettuce --format json
lettuce cell gate check area=auth;layer=api --gate consistency --project lettuce --format plain
cell show

Usage: lettuce cell show COORDINATE [--with-references] [--with-audit] --project PROJECT

Show the asserted state of a cell at a coordinate; an untouched coordinate reports the active pack's sparse DEFAULT state (stored=false) computed, not stored. --with-references adds a referenced_by projection — the graph-run-cases whose effects reference this cell (INT-15b provenance surfaced inline; the reverse of graph-run-case refs-to).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-references - Include the referenced_by back-reference projection: the graph-run-cases whose recorded produced-effects reference THIS cell (which run-case decisions hardened/touched it). Opt-in (default off keeps the cheap bare read). Surfaced in the machine formats (json/yaml) and the human table — always present there when set, an empty [] when nothing references the cell. Under --format plain (the pipeable/scriptable format) the flag is a no-op and the bare cell renders. Deterministic order (grc id, then event order). Same reverse index as graph-run-case refs-to, surfaced at the cell.
  • --with-audit - Include the LET-418 evidentiary projection: the cell's derived depth/depth_verify/depth_affirm and freshness/freshness_basis, plus the evidence and confirmation LEDGERS those figures are derived from. Before this flag cell show returned state/stored/note only and the confirmation ledger had NO read surface at all, so the signals that reveal DoD gaming — is this hardened cell evidence-backed, how deep, how stale, who attested it — were readable only via board export and FQL. Composed from the SAME readers the board and the DoD verdict use, so the audit can never disagree with the gate. OPT-IN because it costs whole-project event walks (the freshness reference revisions); a bare cell show stays a cheap point read. Local store only: refused in client mode rather than silently answering without the projection.

Examples:

lettuce cell show area=auth;layer=api --project lettuce --format json
lettuce cell show area=auth;layer=api --with-references --project lettuce --format json
lettuce cell show area=auth;layer=api --project lettuce --format plain
cell set

Usage: lettuce cell set COORDINATE --state STATE [--facilitate] [--note TEXT] [--reason REASON] --project PROJECT

Assert a cell's state at a coordinate (canonicalized dim=member;dim=member), recording a cell-set event; the state must be in the project's active pack vocabulary. --note persists a first-class rationale scalar on the cell (queryable via cell show, projected as cells[].reason in board export).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --state state - State to assert at the coordinate; must be in the active pack's state vocabulary. Required.
  • --reason reason - Optional justification for the assertion, recorded on the cell-set EVENT (most meaningful when asserting a waived/excluded state — captures WHY the cell is out of scope).
  • --note text - Optional FIRST-CLASS rationale (GAP-2) persisted as a scalar ON the cell — read back by cell show and projected as cells[].reason in board export. Distinct from --reason (event-only). Omitting --note preserves any existing note; clear a note with cell note COORD "".
  • --facilitate - Record-not-enforce a direct set into a GATE-ENTRY-ONLY state: assert it even though no gate guarding entry passed, recording the failed gate verdict on the cell-set event (the same annotation cell transition --facilitate writes).

Examples:

lettuce cell set area=auth;layer=api --state in_progress --project lettuce --author agent-1 --format json
lettuce cell set area=auth;layer=api --state waived --reason 'platform not in scope for v1' --project lettuce --author agent-1 --format json
lettuce cell set area=auth;layer=api --state hardened --note 'covered by TestAuthApiHardened (bite-verified)' --project lettuce --author agent-1 --format json
lettuce cell set area=auth;layer=api --state hardened --facilitate --reason 'onboarding a hand-graded corpus' --project lettuce --author agent-1 --format json

Notes:

  • The coordinate is canonicalized (dimensions sorted, deduplicated) and the state validated against the active pack's states; a malformed coordinate or unknown state is refused. An optional --reason justification is durably recorded on the cell-set event (the same rationale mechanism cell transition uses); an optional --note persists a first-class rationale scalar on the cell itself (GAP-2), read back by cell show and projected as cells[].reason in board export. The reserved scope= member partitions the DoD/board: a coordinate with a scope= lands in that scope, one WITHOUT a scope= is bucketed under the synthetic scope unscoped at evaluation time (so it always counts — never vacuously done); asserting an explicit scope=unscoped is refused (FW-NAME-RESERVED) since that name is reserved for the bucket. PROMOTION INTEGRITY: a state the active pack lets you enter ONLY through gated transitions (e.g. hardened, entered only by harden behind the guard-bite gate) is GATE-ENTRY-ONLY — a direct set into it must satisfy at least one of those gates or it is refused FW-WF-GATE-UNSATISFIED; --facilitate applies it anyway and records the failed verdict on the event. A state with ANY ungated way in (or none at all, like the pack default) is unaffected.
cell clear

Usage: lettuce cell clear COORDINATE --project PROJECT

Remove a stored cell so its coordinate reverts to the active pack's sparse default (stored=false); a coordinate that was never asserted is refused.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce cell clear area=auth;layer=api --project lettuce --author agent-1 --format json

Notes:

  • Hard-removes the cell's stored assertion; clearing an un-asserted coordinate is refused.
cell set-where

Usage: lettuce cell set-where --where '<fql>' --state GRADE [--reason TEXT] [--confirm] [--dry-run] [--facilitate] --project PROJECT

Bulk-assert one state (grade) on EVERY stored cell matching an FQL predicate over the cells source (the same engine query run / cell list back — reuse the scope/unit/dim/group/kind/grade columns to slice a dimension). Requires --confirm to mutate more than one cell; --dry-run lists the matched cells without writing. The whole batch is applied under ONE store mutation lock (byte-identical to N individual cell set calls), so no concurrent writer interleaves.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --where fql - FQL predicate over the cells source selecting the cells to mutate (same syntax as query run 'from cells where ...'). Required.
  • --state grade - Grade to assert on every matched cell; must be in the active pack's state vocabulary. Required.
  • --reason text - Optional justification recorded on each cell-set event (most meaningful when asserting a waived/excluded grade).
  • --facilitate - Record-not-enforce a bulk assert into a GATE-ENTRY-ONLY grade: apply it to matched cells whose entry gates fail, recording the failed verdict on each cell-set event. Without it those cells are skipped and reported.
  • --confirm - Confirm applying the change to all matched cells (required for more than one match).
  • --dry-run - List the matched cells and intended change without writing.

Examples:

lettuce cell set-where --where 'scope = s1 and grade = evidence_linked' --state hardened --confirm --project lettuce --author agent-1 --format json
lettuce cell set-where --where 'unit = cell-set' --state hardened --dry-run --project lettuce --author agent-1 --format json

Notes:

  • The predicate matches only explicitly-asserted cells (the sparse pack-default space is never a row), so a bulk set never invents a cell. The grade is validated once against the active pack; a coordinate whose member is not enumerated in a CLOSED pack dimension is skipped and reported, never aborting the batch. A cell whose target grade is GATE-ENTRY-ONLY (reachable only through gated transitions, e.g. hardened) and whose entry gates all fail is likewise skipped and reported unless --facilitate records-not-enforces it. Local and dedicated-git modes only in this release.
cell clear-where

Usage: lettuce cell clear-where --where '<fql>' [--confirm] [--dry-run] --project PROJECT

Bulk-remove EVERY stored cell matching an FQL predicate so each coordinate reverts to the active pack's sparse default (the bulk inverse of cell clear). Requires --confirm to clear more than one cell; --dry-run lists the matched cells without writing. Applied under ONE store mutation lock.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --where fql - FQL predicate over the cells source selecting the cells to clear (same syntax as query run 'from cells where ...'). Required.
  • --confirm - Confirm clearing all matched cells (required for more than one match).
  • --dry-run - List the matched cells without writing.

Examples:

lettuce cell clear-where --where 'grade = untested' --confirm --project lettuce --author agent-1 --format json

Notes:

  • The predicate matches only explicitly-asserted cells; a coordinate with no stored cell is skipped and reported (a bulk clear of nothing is a no-op, not an error). Local and dedicated-git modes only in this release.
cell note

Usage: lettuce cell note COORDINATE [TEXT] --project PROJECT

Set (or, with no/empty TEXT, CLEAR) a cell's first-class NOTE — the operator rationale scalar (GAP-2), orthogonal to the cell's state, so you can annotate WHY a cell holds its grade without re-asserting the grade. Read back by cell show and projected as cells[].reason in board export. The cell must already be asserted (a note needs a cell).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce cell note area=auth;layer=api 'grade held by TestAuthApiHardened; last audited 2026-07' --project lettuce --author agent-1 --format json
lettuce cell note area=auth;layer=api --project lettuce --author agent-1 --format json

Notes:

  • Records a cell-note event and persists (or removes) the cell's note scalar under one lock with a read-back verify. Annotating an un-asserted coordinate is refused (assert it with cell set first). Omitting TEXT (or passing "") clears the note. Same rationale reachable at assert time via cell set --note, and over HTTP through the cell set PUT body; the dedicated cell note command is local and dedicated-git modes only.
cell import

Usage: lettuce cell import --file PATH [--confirm] [--dry-run] [--facilitate] --project PROJECT

Bulk-ASSERT many cells to their OWN explicit states from a FILE in one locked batch (GAP-8) — the bulk assert cell verify --coords-file (bulk confirm) and cell set-where (bulk set by predicate) left. Each file line is coordinate<TAB>state[<TAB>note]; blank lines and #-comments are ignored. Requires --confirm to assert more than one cell; --dry-run previews the parsed assertions without writing. The whole batch applies under ONE store mutation lock (byte-identical to N cell set calls).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --file path - Path to the import file: one assertion per line, coordinate<TAB>state[<TAB>note]. Blank lines and #-comments ignored; a malformed line (missing TAB-separated state, empty coordinate/state), an invalid coordinate, or an unknown state is skipped and reported, never aborting the batch. Required.
  • --facilitate - Record-not-enforce rows asserting a GATE-ENTRY-ONLY state: apply them even though no entry gate passed, recording the failed verdict on each cell-set event. Without it those rows are skipped and reported — this is the flag for onboarding an externally-graded corpus.
  • --confirm - Confirm applying every parsed assertion (required for more than one assertion).
  • --dry-run - List the parsed assertions and skipped lines without writing.

Examples:

lettuce cell import --file ./cells.tsv --confirm --project lettuce --author agent-1 --format json
lettuce cell import --file ./cells.tsv --dry-run --project lettuce --author agent-1 --format json

Notes:

  • Each line asserts one coordinate to its own state (optionally with a first-class note); the state is validated against the active pack per line and a bad/unknown/malformed line is skipped and reported (the bulk gap-tolerance), never aborting the batch. A row asserting a GATE-ENTRY-ONLY state (one reachable only through gated transitions, e.g. hardened) whose entry gates all fail is skipped and reported unless --facilitate records-not-enforces it. The whole batch is applied under ONE project-scoped mutation lock. Local and dedicated-git modes only in this release.
cell transition

Usage: lettuce cell transition COORDINATE ACTION [--reason TEXT] [--facilitate] --project PROJECT

Move a cell to a new state through the active pack's workflow (an action with no legal transition from the cell's current state is refused); records a cell-transition event. A transition that declares a gate must PASS it (FW-WF-GATE-UNSATISFIED otherwise); --facilitate records the gate verdict on the event but allows the move (record-not-enforce). A transition whose pack entry declares requires: [reason] is refused (FW-CMD-MISSING-ARGUMENT) without --reason.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Why this move was made — REQUIRED by any transition whose pack entry declares requires: [reason]. In the shipped coverage pack that is flag-gap, block, waive and exclude: each records a judgement someone must later be able to question (this is a gap / this is blocked / this is out of scope), so the reason is the durable half of the assertion. Recorded on the cell-transition event. Run lettuce defaults show and read the REQUIRES column for the transitions in force on YOUR project.
  • --facilitate - Record the gate verdict on the event but allow a gated transition to proceed even if its gate fails (record-not-enforce).

Examples:

lettuce cell transition area=auth;layer=api plan --project lettuce --author agent-1 --format json
lettuce cell transition area=auth;layer=api flag-gap --reason 'the cited spec is not in this repo' --project lettuce --author agent-1 --format json
lettuce cell transition area=auth;layer=api harden --facilitate --project lettuce --author agent-1 --format json

Notes:

  • The action must name a transition legal from the cell's current state in the active pack (see lettuce defaults show); an untouched coordinate starts at the pack default. A gated transition (e.g. harden requires the guard-bite gate) is refused unless the gate passes or --facilitate is given.
  • lettuce defaults show is the authority on which actions your project requires a --reason for: its REQUIRES column is resolved from the base convention PLUS the project's own tweak layer, so a project that declares an extra reason-requiring transition is reflected there and cannot be read off this page.
cell verify

Usage: lettuce cell verify COORDINATE [--evidence REF] [--reason TEXT] --project PROJECT | lettuce cell verify --coords-file PATH [--evidence REF] [--reason TEXT] --project PROJECT

Append a VERIFY confirmation to a cell's FRESH-2 confirmation ledger — an INDEPENDENT re-check that the cell's current grade still holds (the stronger durability signal), recorded with the store revision at confirmation time so the cell's distinct-rev hardening DEPTH deepens. Never changes the grade or the hardened ratio; depth is derived (never a settable counter). The STRONG depth (depth_verify — the one the DoD depth floor keys off) counts a verify ONLY when it carries --evidence (a per-cell re-exercise reference); an evidence-less verify records but is demoted to affirm-tier depth, so a bulk stamp with no per-cell proof earns NO verify-depth (the un-fakeable anti-rubber-stamp rule). A given --evidence ref earns verify-depth ONCE PER CELL: the first verify citing it deepens depth_verify, and a later verify on the SAME cell citing the SAME ref is demoted to affirm-tier EVEN AT A NEW STORE REVISION, because one unit of proof is not N independent re-exercises (LET-414-B distinct-EVIDENCE, which is stricter than the distinct-rev rule below). The de-duplication is per-cell, so one ref shared across DIFFERENT cells — the --coords-file pattern — still deepens each of them. Confirming twice at the same store revision buys no depth (the distinct-rev anti-farming rule); a grade change resets depth to the new grade's confirmations only. --coords-file confirms MANY cells in one call (bulk), computing the store subject revision ONCE for the whole batch — the O(n^2)->O(n) fix for a large hardening pass, byte-identical to N individual verifies.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --evidence ref - Per-cell re-exercise reference (guard-test name, run id, or URL) proving this verify independently re-checked the cell. REQUIRED for the verify to strengthen depth_verify (the DoD depth floor keys off it); an evidence-less verify still records but only as affirm-tier depth. Re-using the SAME ref on the SAME cell deepens depth_verify only the FIRST time — later repeats record as affirm-tier even at a new revision. With --coords-file the one ref is applied to EVERY coordinate in the batch.
  • --reason text - Optional justification recorded on the cell-confirm event (auditable; a rubber-stamp confirmation stays attributable).
  • --coords-file path - Bulk mode: confirm every newline-separated coordinate in this file in ONE call (blank lines and #-comments ignored). Computes the subject revision ONCE for the whole batch (O(n^2)->O(n)); each cell's confirmation is byte-identical to an individual cell verify. Mutually exclusive with the COORDINATE positional; a coordinate with no asserted cell (or a malformed line) is skipped and reported, never aborting the batch.

Examples:

lettuce cell verify area=auth;layer=api --evidence 'go test ./... -run TestAuthAPI' --project lettuce --author agent-1 --format json
lettuce cell verify --coords-file ./coords.txt --evidence CI#1234 --project lettuce --author agent-1 --format json

Notes:

  • The cell must already be asserted (cell set/transition). Depth = count of DISTINCT confirmation revisions of the current grade (verify + affirm reported separately, never blended); an unconfirmed cell reads depth 0. depth_verify counts ONLY evidence-backed verifies (--evidence) whose ref is DISTINCT for that cell — the DoD depth floor is satisfied by proven re-exercise, never a bare stamp and never one proof cited N times. Both mutations still return ok:true when a repeat is demoted, so read depth_verify back (query from cells select depth_verify, or board export) rather than inferring it from the call succeeding. --coords-file bulk-confirms a coordinate list (skipping unasserted/malformed lines) with one shared --evidence; the batch is semantically identical to N individual verifies but O(n) not O(n^2). Local and dedicated-git modes only in this release.
cell affirm

Usage: lettuce cell affirm COORDINATE [--reason TEXT] --project PROJECT | lettuce cell affirm --coords-file PATH [--reason TEXT] --project PROJECT

Append an AFFIRM confirmation to a cell's FRESH-2 confirmation ledger — a RESTATEMENT that the cell's current grade still holds (an agentic re-examination, the weaker signal vs verify), recorded with the store revision at confirmation time so the cell's distinct-rev hardening DEPTH deepens. Never changes the grade or the hardened ratio; depth is derived (never a settable counter). Confirming twice at the same store revision buys no depth (the distinct-rev anti-farming rule); a grade change resets depth to the new grade's confirmations only. --coords-file confirms MANY cells in one call (bulk), computing the store subject revision ONCE for the whole batch — the O(n^2)->O(n) fix for a large hardening pass, byte-identical to N individual affirms.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Optional justification recorded on the cell-confirm event (auditable; a rubber-stamp confirmation stays attributable).
  • --coords-file path - Bulk mode: confirm every newline-separated coordinate in this file in ONE call (blank lines and #-comments ignored). Computes the subject revision ONCE for the whole batch (O(n^2)->O(n)); each cell's confirmation is byte-identical to an individual cell affirm. Mutually exclusive with the COORDINATE positional; a coordinate with no asserted cell (or a malformed line) is skipped and reported, never aborting the batch.

Examples:

lettuce cell affirm area=auth;layer=api --reason 're-reviewed against head' --project lettuce --author agent-1 --format json
lettuce cell affirm --coords-file ./coords.txt --project lettuce --author agent-1 --format json

Notes:

  • The cell must already be asserted (cell set/transition). Depth = count of DISTINCT confirmation revisions of the current grade (verify + affirm reported separately, never blended); an unconfirmed cell reads depth 0. --coords-file bulk-confirms a coordinate list (skipping unasserted/malformed lines); the batch is semantically identical to N individual affirms but O(n) not O(n^2). Local and dedicated-git modes only in this release.
board export

Usage: lettuce board export --project PROJECT [--source-rev REV]

Project a project's coverage board into a stable, versioned BoardExport v0.1 JSON DATA CONTRACT (schema_version, generated_at, source_rev, pack dimensions + state legend, stored cells with evidence, per-axis coverage rollups, blended headline ratio, milestones, and tickets) for a dashboard renderer. Read-only projection: emits the document as the machine envelope data on stdout (pipe it or read .data), never writes a file or mutates the store; visuals live outside the contract (data separate from visual). Distinct from export (a whole-store backup bundle).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --source-rev rev - Optional provenance revision (repo commit short-SHA or store revision) stamped into source_rev. generated_at is NOT a wall-clock stamp: with none supplied it defaults from the STORE — the instant of the latest event — so repeated exports of an unchanged store are byte-identical and it advances only when the store does. The whole projection, provenance included, is reproducible.

Examples:

lettuce board export --project lettuce --format json
lettuce board export --project lettuce --source-rev a1b2c3d --format json

Notes:

  • BoardExport is a lossy presentation-oriented projection of the coverage board only (cells + rollups + milestones + tickets), NOT the store-bundle export (lettuce export --bundle), which is a faithful full backup. The two do not share a schema. See docs/specs/board-export-v0.1.md.
  • Per-axis rollups are keyed by the real coordinate axis name (e.g. by_axis.dim, by_axis.command); the blended headline is Sigma-hardened / Sigma-non-excluded over every stored cell. cells[].reason is reserved but empty in this release (GAP-2: cells carry no first-class reason field). REST parity is deferred (CLI-first).
board next

Usage: lettuce board next --project PROJECT [--depth 0|1|2] [--scope SLUG]

Agent-facing coverage ORIENTATION report — "what should I harden next?" — distilled from the same board board export produces, so an agent picks its next target WITHOUT exporting and re-parsing the whole board. Read-only: every scope's meter ranked WEAKEST-FIRST plus a single "start here" pointer (the globally weakest open cell). --depth deepens the detail (the operator's global-to-increasing-detail): 0 (default) meters + start-here; 1 adds every scope's shape-aware suggestions (a heatmap scope → its dimensions with H/G/U subcounts, a scalars scope → its scalar grades, a ladder scope → its milestones) weakest-first; 2 adds the weakest units + the concrete open (gap/untested) cell coordinates, capped with an honest +N-more pointer. --scope restricts the report to one scope. The default output is a SELF-GUIDING plain-text report: every summarised node prints the exact lettuce ... command to descend, so the agent is never stuck; --format json emits the same data structured (scopes[] each with meter + suggestions[] + coordinates[] + a more drill string), depth-trimmed to match.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --depth 0|1|2 - How much detail to surface: 0 (default) per-scope meters + start-here; 1 adds every scope's dimension/milestone subcounts weakest-first; 2 adds the weakest units + concrete open coordinates. Never hides a whole scope — only how deep each goes.
  • --scope slug - Restrict the report to one scope member (e.g. s1); a slug that names no scope on the board is refused with the available list.

Examples:

lettuce board next --project lettuce --format json
lettuce board next --project lettuce --depth 2 --format json

Notes:

  • A pure READ over the same BoardExport as board export/board render: it never mutates the store and honours the identical project-scoping contract — a PROJECT CONTEXT is REQUIRED — resolved from --project, else LETTUCE_PROJECT, else config project: — and a MISSING context is refused FW-CMD-MISSING-PROJECT-CONTEXT while an INVALID name is refused FW-NAME-PROJECT (LET-264 split them; an EMPTY value counts as missing, not malformed). The diagnostic names CONTEXT, not the flag, for exactly this reason and it reads ONLY the named project's board, never a default or a cross-project scan. Frontier = the not-done, not-excluded, not-smoke cells (gap + untested), derived from the pack's state vocabulary, never a hardcoded slug. Same honesty invariants as the board: never invents a cell, never blends across scopes, an empty denominator reads n/a, and a capped list always announces its full count + the drill command (no silent truncation). REST parity is deferred (CLI-first), mirroring board export/render.
board render

Usage: lettuce board render --project PROJECT [--theme SLUG] [--source-rev REV]

Render a project's coverage board as a SELF-CONTAINED, zero-JS HTML page NATIVELY in Go from the same BoardExport board export produces — no external python, no JSON round-trip. Read-only projection: the raw HTML is written to stdout so a publisher pipes it to a file; a machine --format (json/yaml) wraps it in the envelope's data as a {theme, format, content} object. DATA ⟂ PRESENTATION: the data/structure is theme-independent and a --theme selects only the presentation (an unknown theme is refused with the available list). Reproducible: with no --source-rev the provenance defaults from the store (data revision + latest-event instant), never the wall clock. REST parity is deferred (CLI-first), mirroring board export/next.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --theme slug - Presentation theme selecting only the CSS/frame (data is theme-independent); defaults to the built-in default theme. An unknown theme is refused with the available list.
  • --source-rev rev - Optional provenance revision (repo commit short-SHA or store revision) stamped into the masthead; with none it defaults from the store (data revision + latest-event instant) for a wall-clock-free, reproducible render.

Examples:

lettuce board render --project lettuce
lettuce board render --project lettuce --theme default
lettuce board render --project lettuce --format json

Notes:

  • A pure READ over the same BoardExport as board export/board next: it never mutates the store and honours the identical project-scoping contract — a PROJECT CONTEXT is REQUIRED — resolved from --project, else LETTUCE_PROJECT, else config project: — and a MISSING context is refused FW-CMD-MISSING-PROJECT-CONTEXT while an INVALID name is refused FW-NAME-PROJECT (LET-264 split them; an EMPTY value counts as missing, not malformed). The diagnostic names CONTEXT, not the flag, for exactly this reason and it reads ONLY the named project's board. The HTML is strictly self-contained: every byte is inline — no src=, no external http(s) reference the browser resolves (the only http(s) strings are the SVG xmlns and inert provenance URLs inside title= tooltips), and no network call of any kind (no cdn/fetch/XHR/WebSocket/dynamic import). It is pure-CSS with ONE authorized exception (operator 20974/21127): a project carrying graph-run-cases also emits the grc replay simulator as exactly one INLINE <script> (an IIFE) plus one inert <script type="application/json"> data island per grc. A project with no graph-run-cases emits no <script> at all. Only the html output format is supported for the raw body (an unsupported --format is refused); a global machine --format wraps the HTML in the envelope. TO PUBLISH: the raw HTML goes to STDOUT, so redirect it to a file — lettuce board render --project P > board.html — and open that file. A machine --format (json/yaml) does NOT write a viewable page: it returns the HTML escaped inside the envelope as data.content, for a programmatic consumer that will unwrap it. Use board next to decide what to harden, board export for the data contract, and board render only when you want the page.
cell reconcile

Usage: lettuce cell reconcile [--dry-run] --project PROJECT

Reconcile STALE-GREEN cells: scan the project's stored cells and, for each in a guard-bite-gated done state (e.g. hardened) whose gate NO LONGER passes because its cited evidence broke (the cited task was deleted), machine-fire the active pack's regress transition so the stored state stops silently reading green (conformance §106: a gate-fail must regress, no silent stay-green). Detects a phantom with the exact evidence resolution the honest rollup uses, so reconcile and rollup agree; a cell whose gate still passes is untouched, making a second run a no-op. --dry-run reports what WOULD regress and writes nothing.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --dry-run - Report which stale-green cells WOULD regress and write nothing.

Examples:

lettuce cell reconcile --project lettuce --author agent-1 --format json
lettuce cell reconcile --dry-run --project lettuce --format json

Notes:

  • The SANCTIONED path to fire the machine-only regress edge that a manual cell transition <coord> regress refuses (BUG-70 PART 1). Regresses ONLY a cell that HAS evidence of which none still resolves (a direct-set done state with no evidence is left alone, exactly as the honest rollup counts it); each regress is an independent atomic cell-transition mutation. Run by an operator or CI to reconcile after evidence is deleted — reads stay pure (no surprise mutation on a read path). Local and dedicated-git modes only in this release.
dimension list

Usage: lettuce dimension list --project PROJECT

List a project's EFFECTIVE dimensions — the active convention pack's declared dimensions plus the project's additive runtime dimension layer (cells-v0.16 §4) — each tagged with its source (pack vs project). Read-only; the additive project layer never overrides pack vocabulary (decision A6).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce dimension list --project lettuce --format json
lettuce dimension list --project lettuce --format plain

Notes:

  • The effective dimension space is the active pack's dimensions (source=pack) plus any dimensions the project declared at runtime (source=project). Until a project declares runtime dimensions, every dimension is source=pack. REST parity: GET /v1/projects/{project}/dimensions.
dimension show

Usage: lettuce dimension show SLUG --project PROJECT

Show ONE of a project's EFFECTIVE dimensions by slug — the resolved dimension (active convention pack ⊕ the project's additive runtime layer, cells-v0.16 §4/§8) with all its declared fields and its source (pack vs project). Read-only; an unknown slug is refused FW-CMD-USAGE.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce dimension show A --project lettuce --format json
lettuce dimension show A --project lettuce --format plain

Notes:

  • Resolves against the same effective space dimension list enumerates: the active pack's dimensions (source=pack) first, then the project's runtime layer (source=project). A slug present in neither is refused FW-CMD-USAGE. REST parity: GET /v1/projects/{project}/dimensions/{slug}.
dimension member list

Usage: lettuce dimension member list DIMENSION --project PROJECT

List the members of ONE effective dimension — the base pack's enumerated members (source=pack, in declared order) plus any members the project's runtime layer added (source=project). Read-only; an open dimension that enumerates no members yields an empty list, and an unknown dimension is refused FW-CMD-USAGE.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce dimension member list A --project lettuce --format json
lettuce dimension member list A --project lettuce --format plain

Notes:

  • member is a sub-noun under dimension (like cell evidence). Members are the base pack's declared members for a closed dimension (source=pack) plus any the project added at runtime (source=project); an open dimension carries no enumerated members at rest. REST parity: GET /v1/projects/{project}/dimensions/{dimension}/members.
dimension member add

Usage: lettuce dimension member add DIMENSION MEMBER [--name N] [--description D] [--rank R] [--attr K=V ...] --project PROJECT

Add a FIRST-CLASS member {slug,name,description,rank,attributes} to a project's runtime dimension (GA-1), recording a dimension-member-added event; the member's human name + order become visible everywhere the effective pack resolves (dimension member list, dimension show, board export axes[].members[]). Additive-only (decision A6): members can only be added to a PROJECT-declared dimension — a pack-declared dimension's members are fixed by the pack (refused FW-CMD-USAGE), and a member slug already enumerated by the dimension is refused (no duplicate). --name is the human label (empty renders as the slug); --rank orders members (rank 0 = unranked, sorts by slug); repeatable --attr declares first-class key=value data beyond name/description/rank (self-described-scopes Phase 1 — e.g. a scope member's shape/row_noun/stages), which the board export carries inline and a generic renderer reads from data.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --name name - Human label for the member; defaults to rendering as the slug when omitted.
  • --description text - Optional one-line description of the member (shown on hover in a board).
  • --rank int - Optional integer sort order (ascending; rank 0 = unranked, falls back to slug order).
  • --attr key=value - Optional repeatable first-class attribute declaration (key: lowercase-letter start then [a-z0-9_-], max 64). Carried inline on the board export; Phase-1 scopes use shape/row_noun/stages. Repeatable.

Examples:

lettuce dimension member add unit task-set-where --name 'task set-where' --description 'Bulk-set a field on all matching tasks' --rank 210 --project lettuce --author agent-1 --format json

Notes:

  • member add is a mutation under the dimension member sub-noun (like dimension declare). The dimension must be one the project DECLARED at runtime (source=project); adding to a pack dimension is refused FW-CMD-USAGE. The member slug is validated and must be unique within the dimension; every refusal happens BEFORE any write, so a refused add leaves NO partial member on disk. REST parity: POST /v1/projects/{project}/dimensions/{dimension}/members.
dimension member update

Usage: lettuce dimension member update DIMENSION MEMBER [--name N] [--description D] [--rank R] [--attr K=V ...] --project PROJECT

EDIT an existing first-class member's name/description/rank/attributes on a project's runtime dimension (Phase 0c), recording a dimension-member-updated event. A PARTIAL update touches only the fields you pass — updating just --rank leaves the name/description intact; a repeatable --attr sets/overwrites the named keys and leaves unmentioned attributes intact. The inverse-companion to dimension member add: add creates a member (refuses a duplicate), update edits one (refuses an ABSENT member, FW-PATH-NOT-FOUND). Additive-only (decision A6): only a member of a PROJECT-declared dimension is editable — a pack-declared dimension's members are fixed by the pack (refused FW-CMD-USAGE). At least one of --name/--description/--rank/--attr is required (FW-CMD-MISSING-ARGUMENT otherwise).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --name name - New human label for the member (empty or whitespace-only clears it — renders as the slug).
  • --description text - New one-line description of the member.
  • --rank int - New integer sort order (ascending; rank 0 = unranked, falls back to slug order).
  • --attr key=value - Optional repeatable first-class attribute to set/overwrite (unmentioned keys stay intact). Carried inline on the board export; Phase-1 scopes use shape/row_noun/stages. Repeatable.

Examples:

lettuce dimension member update unit task-set-where --rank 150 --project lettuce --author agent-1 --format json
lettuce dimension member update unit task-set-where --name 'Task set-where' --description 'Bulk-set a field on matching tasks' --project lettuce --author agent-1 --format json

Notes:

  • member update is a mutation under the dimension member sub-noun (like dimension member add). The dimension must be one the project DECLARED at runtime (source=project); editing a pack dimension's member is refused FW-CMD-USAGE. The member MUST already exist — updating an absent member is refused FW-PATH-NOT-FOUND. Only the provided scalars change; every refusal happens BEFORE any write, so a refused update leaves the member UNCHANGED on disk. REST parity: PATCH /v1/projects/{project}/dimensions/{dimension}/members/{member}.
dimension declare

Usage: lettuce dimension declare SLUG --family FAMILY --applicability universal|conditional [--closed --member M ...] [--name N] [--description D] [--id ID] [--member-kind K] --project PROJECT

Author a project's runtime dimension in its additive layer (cells-v0.16 §4/§8), recording a dimension-declared event; the declared dimension becomes visible everywhere the effective pack resolves (cell set/show/rollup, board, query). Additive-only (decision A6): the slug must be UNIQUE against BOTH the active pack's dimensions AND the project's existing runtime dims — a runtime dimension can never shadow a pack dimension. A --closed dimension enumerates its members (repeatable --member); an open dimension carries none at rest.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --family family - Family this dimension groups under; required, and must resolve to one of the active pack's declared families. Required.
  • --applicability universal|conditional - Applicability class; required. universal = applies to every unit; conditional = applies only when a precondition holds. Required.
  • --closed - Mark the dimension closed (its members are a fixed enumeration). Requires at least one --member.
  • --member slug - A member of a --closed dimension (repeatable). Each must be a valid slug; an open dimension carries no members. Repeatable.
  • --name name - Human label for the dimension; defaults to the slug when omitted.
  • --description text - Optional one-line description of what the dimension measures.
  • --id id - Optional stable identifier for the dimension.
  • --member-kind kind - Optional member value-kind (e.g. string or a typed entity reference).

Examples:

lettuce dimension declare deployment-readiness --family operability --applicability conditional --project lettuce --author agent-1 --format json

Notes:

  • The slug is validated (a valid single-path-component slug) and refused FW-CMD-USAGE if it collides with a pack dimension or a dimension the project already declared (additive-only, A6). --family must resolve to a pack-declared family; --applicability must be universal or conditional; a --closed dimension must enumerate at least one --member. Every refusal happens BEFORE any write, so a refused declare leaves NO partial dimension on disk. The dimension is born active. REST parity: POST /v1/projects/{project}/dimensions.
dimension rename

Usage: lettuce dimension rename OLD NEW --project PROJECT

Rename a project's RUNTIME dimension: move projects/PROJECT/dimensions/OLD to .../NEW preserving EVERYTHING inside (family, closed-ness, name, description, members and the dimension's own event ledger), RE-ADDRESS every cell whose coordinate names OLD (a coordinate IS the cell's identity, so each affected cell directory moves to its new coordinate hash carrying its whole aggregate — state, note, revision, its events ledger, and its evidence links with their asserted_at/asserted_rev provenance), and rewrite every stored reference to the dimension and to the moved cells. A whole-store structural migration like project rename/merge, applied atomically under the mutation lock. The lower-harm alternative to declaring a fresh dimension and recreating the cells, which would lose every cell event, both ledgers and all evidence provenance.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce dimension rename unit coverage-unit --project lettuce --author agent-1 --format json

Notes:

  • OLD and NEW are POSITIONAL slug arguments (not --project). Only a dimension the project DECLARED is renameable — a pack-bundled dimension is compiled into the binary, so naming one is refused FW-PATH-NOT-FOUND. Refuses if NEW is already declared by the project or the active pack (a collision, FW-CMD-USAGE, additive-only A6) or is an invalid slug (FW-NAME-SLUG). REFUSES with FW-DIMENSION-RENAME-CONFLICT when the renamed coordinates cannot coexist: two cells collapsing onto one coordinate, a coordinate that would name one dimension twice, or one that would assert the reserved scope=unscoped bucket. REFUSES with FW-DIMENSION-RENAME-UNSAFE, writing nothing, for a reference it cannot rewrite: one folded into a CONTENT-ADDRESSED identity (a graph-run-case advance event or a carrier directory is named by the hash of its own payload), a stored saved-query FQL naming the dimension (the FQL cells source projects scope/unit/dim/group/kind as fixed columns, so no rewrite can re-point the query), or a move off/onto a reserved coordinate axis the project's DECLARED grid or DoD keys off. Prose is never rewritten, so the dimension-declared event's reason slot keeps the slug the dimension was declared under — an append-only ledger records what happened. On any failure the store is left byte-unchanged (atomic). Verify after with lettuce validate --strict. REST parity: POST /v1/projects/{project}/dimensions/{old}/rename.
dimension close

Usage: lettuce dimension close DIMENSION --project PROJECT

CLOSE a project's runtime dimension: flip its closed flag from false to true so the coordinate validator begins ENFORCING declare-before-use on that axis. From here on a cell set naming a member the dimension does not enumerate is refused instead of silently minting it — which is the whole point, since a coordinate is the cell's identity and a typo mints a NEW cell rather than editing the intended one. Enforcement and its refusal already existed; this is the transition into it that no command previously offered (declare is additive-only and refuses an existing slug, rename re-addresses, and member add/update never touch closed). CLOSED MEANS DECLARE-BEFORE-USE, NOT FROZEN: a new member can be added with dimension member add at any time and is usable immediately.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce dimension close unit --project lettuce --author agent-1 --format json

Notes:

  • DIMENSION is a POSITIONAL slug argument. Only a PROJECT-declared dimension is closable; the bundled pack's dimensions carry uppercase slugs, which the slug grammar refuses (FW-NAME-SLUG) before the pack-declared check is ever reached. REFUSES, writing nothing, when: the dimension is already closed (FW-CMD-USAGE naming the current state — a second close is an error, not a silent no-op); it enumerates NO members (mirroring declare --closed, which requires at least one); or — the gate that makes this safe to run against a live store — any member OBSERVED in a stored cell's coordinate on that axis is not declared. That last refusal NAMES the undeclared members in its actual slot, because closing then would start refusing coordinates that are valid today. The coverage gate reads the CELLS, not the registry: a registry-only check confirms the declared members are declared and stays blind to the ones the store actually uses. The result echoes cells_scanned so the no-op claim is checkable rather than asserted. There is deliberately no re-open counterpart: closing is the transition coordinate-integrity work needs, and an un-close would need its own coverage story. REST parity: POST /v1/projects/{project}/dimensions/{dimension}/close.

Links to

Core And Runtime — Commands

↑ top

reference/cmd-core-and-runtime

lettuce Core And Runtime commands — 12 entries — usage, skill, docs, okf, version, init, status, validate, doctor, recover, cleanup, reconcile.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Core And Runtime — Commands

lettuce command group Core And Runtime — 12 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • usage
  • skill
  • docs
  • okf
  • version
  • init
  • status
  • validate
  • doctor
  • recover
  • cleanup
  • reconcile

---

Initialize stores, inspect runtime health, validate data, recover locks, clean runtime state, and print usage.

usage

Usage: lettuce usage [command-prefix] [--format table|json|yaml|markdown|okf] [--out DIR]

Print complete CLI usage documentation for humans and agents. --format okf --out DIR emits the OKF command-reference bundle regenerated by 'make docs'.

  • kind: local
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --out dir - Destination directory for the OKF command-reference bundle (only with --format okf).

Examples:

lettuce usage --format markdown
lettuce usage query saved --format json
lettuce usage --format okf

Notes:

  • Does not require an initialized store.
  • Add --out DIR with --format okf to write the command-reference bundle (this is what 'make docs' runs); without --out it streams the bundle as a single document to stdout.
skill

Usage: lettuce skill

Print the embedded SKILL.md agent guide (also served at / and /SKILL.md by serve).

  • kind: local
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce skill
lettuce skill --format json

Notes:

  • Does not require an initialized store.
docs

Usage: lettuce docs [list | export | show CONCEPT]

Print the embedded, build-fresh wiki: the HTML explorer by default, 'docs list' to ENUMERATE every concept id (one per line for humans, a {concepts,count} envelope for machines), 'docs export --out DIR' to write the artifacts for an agent, 'docs show CONCEPT' to stream one concept. docs list and docs show resolve against the SAME conceptIDs source, so the list can never advertise a concept show rejects (LET-1001: concept was an enumerable noun whose only positive discovery path was provoking a refusal and reading its expected field). Also served at /docs and /docs/flat.md by serve.

  • kind: local
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce docs
lettuce docs list
lettuce docs list --format json
lettuce docs show concept-task

Notes:

  • Does not require an initialized store. The wiki is regenerated by 'make docs' and embedded in the binary.
  • 'docs export --out DIR' writes the embedded wiki artifacts (wiki.html + wiki-flat.md) for an agent to read offline; --out is a flag of the export subcommand.
okf

Usage: lettuce okf <okf-command> [args...] | lettuce okf docs <okf-command> [flags...]

Mount the embeddable okf CLI as a subcommand: lettuce okf validate ./bundle behaves exactly like okf validate ./bundle (validate, lint, render, render --site, export, graph, search, docs, version, help). lettuce okf docs <okf-command> runs the okf command against lettuce's OWN embedded wiki bundle (docs/wiki, compiled into the binary) — e.g. lettuce okf docs render --site ./site writes a single self-contained navigable HTML site of lettuce's documentation with no files on disk and no network.

  • kind: local
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce okf version
lettuce okf docs validate
lettuce okf docs lint
lettuce okf help

Notes:

  • Does not require an initialized store. Delegates to okf's embeddable pkg/okf facade; okf is vendor-neutral and fully offline. lettuce okf docs appends lettuce's materialized embedded-wiki bundle root as the trailing positional and passes every other flag through verbatim. Point okf at an arbitrary bundle with lettuce okf validate ./bundle or lettuce okf render --site ./out ./bundle (a bundle path / output dir the examples census does not fabricate, so those forms are shown here rather than auto-executed).
version

Usage: lettuce version

Print the lettuce binary version.

  • kind: local
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce version --format json
lettuce version --format plain
init

Usage: lettuce init [--author AUTHOR] [--bootstrap-project PROJECT] [--bootstrap-author] [--idempotent] [--yes] [--force]

Create a store root skeleton and optionally create a root author and bootstrap project.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): bootstrap_project, bootstrap_author, idempotent
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --author author - Root author to create or use for bootstrap project.
  • --bootstrap-project project - Create one project during initialization.
  • --bootstrap-author - Create/link the bootstrap author when needed.
  • --idempotent - Treat existing initialized state as success when valid.
  • --yes - Confirm that --bootstrap-project may add an ADDITIONAL project to a store that already holds one.
  • --force - Alias of --yes: confirm an additional project.

Examples:

lettuce init --root .lettuce --author agent-1 --bootstrap-project lettuce --bootstrap-author --idempotent --format json

Notes:

  • --bootstrap-project on an ALREADY-populated store would add a second project and is refused with FW-PROJECT-ADDITIONAL-UNCONFIRMED unless --yes (or --force) is passed; the first project of a fresh store never needs it. Over HTTP send "confirm": true in the POST /v1/init body.
status

Usage: lettuce status

Report store validity, runtime state, Git state, and capability flags.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce status --root . --format json
lettuce status --root . --format plain
validate

Usage: lettuce validate [--scope store|project|task|runtime] [--task REF] [--strict|--loose]

Validate canonical store or runtime state against the on-disk grammar. NOT the strictest available check, despite --strict: doctor runs this SAME validation plus a derived-divergence probe, so a store this reports clean can still be damaged (forged derived scalars, merge conflicts, ladder-overlay drift). Prefer doctor as a CI gate; use validate for a fast structural check.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --scope scope - Validation scope.
  • --task task-ref - Task reference for task scope.
  • --strict - Strict validation mode.
  • --loose - Inspection mode. Core filesystem integrity remains enforced.

Examples:

lettuce validate --scope store --strict --format json
lettuce validate --scope project --project lettuce --loose --format json
doctor

Usage: lettuce doctor [--shallow] [--format json|yaml|markdown]

Run validation plus a read-only derived-divergence probe (detects forged derived scalars, merge conflicts, and ladder-overlay drift that grammar validation misses) with LLM-friendly explanations and repair suggestions. --shallow skips the probe for performance.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --shallow - Skip the read-only derived-divergence probe and run grammar/structure validation only (faster; use when only the fast checks are needed).

Examples:

lettuce doctor --format json
lettuce doctor --shallow --format markdown
recover

Usage: lettuce recover [--abandon | --report-only]

Inspect runtime operations and recover safe interrupted mutations. Resolves a stuck active/failed recovery attempt so blocked mutations proceed. Use --abandon to force-clear an orphaned active operation whose owner cannot be proven dead. NOT RECLAIMED BY DESIGN (LET-1226): an operation left in a spec §17.2 non-terminal WRITE PHASE (preparing, writing, validating, committing) by a provably dead owner is reported and deliberately left in place, because a writer that died mid-write may have left a partially-written canonical file and the phase marker is the only evidence that happened — clearing it would destroy exactly what an operator needs to investigate. recover emits FW-RUNTIME-WRITE-PHASE-STRANDED naming each such record; run validate --strict to check the objects it was writing, then remove the record by hand if the store is intact. These persist across recover passes and that is expected, not a failure of this command. Use --report-only (LET-1533) to INSPECT without changing anything: three refusals (FW-RUNTIME-WRITER-ACTIVE, the interrupted-evidence advisory, and the lock advisory) tell an operator to "run lettuce recover to inspect", and until that flag existed there was no way to do so — a plain recover reaps released operation records, heals forward, quarantines foreign runtime directories and may reset the generation. --report-only takes no lock, writes nothing, and reports what a real recover WOULD reclaim, using the same released-state predicate the reaper uses so the preview cannot promise what the apply declines. It is also the affordable form: a normal recover pays a whole-store validation (61.4s of CPU on lettuce's own store) whose diagnostics only the heal passes consume, while the report reads the runtime scope alone. Mutually exclusive with --abandon, which forces a reclamation.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --abandon - Force-clear an orphaned active operation whose owner liveness is undeterminable.
  • --report-only - Inspect without writing: report what recover WOULD reclaim, taking no lock and changing nothing. Mutually exclusive with --abandon.

Examples:

lettuce recover --author operator --format json
lettuce recover --report-only --format json
lettuce recover --abandon --author operator --format json

Notes:

  • May mutate runtime and recovery state.
cleanup

Usage: lettuce cleanup

Remove released runtime operation data without changing canonical files.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce cleanup --format json
reconcile

Usage: lettuce reconcile --project PROJECT [--dry-run|--apply]

Store-merge-healing: scan a project for derived state that diverged from its event log (the shape a blind git merge leaves) and, with --apply, heal the deterministically-recomputable Class-A divergences (cell revision/state/note, task revision/status and field-set values, run status/timing, comment status, saved-query status, registry object fields, dimension active, and graph-run-case revision/state) under the write lock. Dry-run report is the default; --apply requires an author and mutates. Class-B conflicts — a genuine fork rather than a lagging scalar (e.g. a broken revision-chain, cell evidence/confirmation counts, or a graph-run-case whose value/coordinate diverged) — are reported, never rewritten.

  • kind: maintenance
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --dry-run - Report divergences without writing (the default).
  • --apply - Heal Class-A divergences under the write lock (requires --author).

Examples:

lettuce reconcile --project lettuce --format json
lettuce reconcile --project lettuce --apply --author agent-1 --format json

Notes:

  • Distinct from cell reconcile (which re-derives cell grades against the pack); this checks derived==f(events) coherence across cells, tasks, runs, comments, saved-queries, registry objects, dimensions, and graph-run-cases. Exit 1 when unresolved Class-B conflicts remain. Every conflict reports the diverged stored/expected; a revision-chain fork additionally names forked_at_revision, the colliding_events that both consumed it (id, author, kind, at, revision pair) and a suggested_actions repair path — for a class that is deliberately never rewritten, the report is the entire deliverable.

Links to

Coverage Grid — Commands

↑ top

reference/cmd-coverage-grid

lettuce Coverage Grid commands — 4 entries — grid scope add-unit, grid scope add-dim, grid scope show, grid show.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Coverage Grid — Commands

lettuce command group Coverage Grid — 4 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • grid scope add-unit
  • grid scope add-dim
  • grid scope show
  • grid show

---

Declare a project's per-scope coverage GRID (implicit cells, cells-v0.16 §A2): the units (rows) and applicable dims (cols) whose cross-product is the honest coverage denominator. Declare the grid once and every un-worked coordinate counts as implicit-untested — record real progress instead of minting cells one by one.

grid scope add-unit

Usage: lettuce grid scope add-unit SCOPE UNIT... --project PROJECT

Declare unit (row) members on a scope's grid — the things being covered under that scope (cells-v0.16 §A2). Records a project-updated event; each member slug is validated (a valid single-path-component slug) and refused FW-CMD-USAGE otherwise, BEFORE any write. Idempotent: a member already declared is a no-op. Once units AND applicable dims are declared, the scope's honest denominator is |units|×|dims| and every un-worked coordinate reads implicit-untested in rollup/board/dod.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce grid scope add-unit s1 validate recover reconcile --project lettuce --author agent-1 --format json

Notes:

  • Members are additive marker declarations under projects/<p>/grid/scopes/<scope>/units/<member>; storage stays sparse (only asserted cells are stored) while the denominator counts the declared grid. A malformed slug is refused before any write, so a refused add leaves nothing on disk. REST parity: declared over HTTP via POST /v1/projects/<p>/grid/scopes/<scope>/units — CLI local and client mode land the same project-updated event (differential parity guarded).
grid scope add-dim

Usage: lettuce grid scope add-dim SCOPE DIM... --project PROJECT

Declare applicable dimension (col) members on a scope's grid — the coverage dimensions that apply to that scope (cells-v0.16 §A2). Records a project-updated event; each slug is validated and refused FW-CMD-USAGE otherwise, BEFORE any write. Idempotent. Together with the scope's units, the applicable dims define the declared applicable space |units|×|dims| that becomes the honest coverage denominator.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce grid scope add-dim s1 t s --project lettuce --author agent-1 --format json

Notes:

  • Marker declarations under projects/<p>/grid/scopes/<scope>/dims/<member>; a scope that declares units but no applicable dims (or vice-versa) has grid size 0 and never reads a vacuous ratio. A malformed slug is refused before any write. REST parity: declared over HTTP via POST /v1/projects/<p>/grid/scopes/<scope>/dims (differential parity guarded).
grid scope show

Usage: lettuce grid scope show SCOPE --project PROJECT

Show ONE scope's declared grid — its unit (row) members, applicable dim (col) members, and the resulting size (|units|×|dims|). Read-only; a scope with no declared grid reads empty (size 0).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce grid scope show s1 --project lettuce --format json

Notes:

  • A pure read over projects/<p>/grid/scopes/<scope>; size is |units|×|dims| — the scope's contribution to the honest coverage denominator. REST parity: read over HTTP via GET /v1/projects/<p>/grid (one scope filtered client-side).
grid show

Usage: lettuce grid show --project PROJECT

Show a project's WHOLE declared grid — every scope with its units, applicable dims, and size, plus the project denominator (Σ per-scope |units|×|dims|). Read-only; a project that declares no grid reads declared=false with denominator 0 (the coverage denominator then falls back to the observed stored-cell count — backward-compatible).

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce grid show --project lettuce --format json

Notes:

  • The denominator here is the same declared applicable space rollup/board/dod use once a grid is declared (cells-v0.16 §A2). No declared grid ⇒ the observed-cell denominator (pre-implicit-cells behaviour). REST parity: read over HTTP via GET /v1/projects/<p>/grid.

Links to

Definition Of Done — Commands

↑ top

reference/cmd-definition-of-done

lettuce Definition Of Done commands — 10 entries — dod set, dod clear, dod show, defaults show, defaults state declare, defaults state set-default, defaults state hide, defaults transition declare, defaults gate declare, defaults reset.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Definition Of Done — Commands

lettuce command group Definition Of Done — 10 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • dod set
  • dod clear
  • dod show
  • defaults show
  • defaults state declare
  • defaults state set-default
  • defaults state hide
  • defaults transition declare
  • defaults gate declare
  • defaults reset

---

Declare and inspect a project's tunable Definition of Done — a required grade floor plus optional depth/recency floors, with per-scope overrides, evaluated as a strict per-scope AND-gate (never a blended percentage).

dod set

Usage: lettuce dod set --project PROJECT [--grade STATE] [--depth N] [--recency fresh|aging] [--scope SCOPE]

Persist a project's Definition-of-Done knobs. Without --scope it sets the PROJECT DEFAULTS: --grade is the required grade floor (a state the active pack declares, e.g. hardened — the minimum grade a cell must reach to count as done); --depth is the optional minimum distinct-rev confirmation DEPTH (FRESH-2, >=1); --recency is the optional minimum freshness bucket (FRESH-3: fresh or aging — never stale). With --scope it sets a PER-SCOPE OVERRIDE of any of those floors (an unset field inherits the project default). At least one knob is required; a first project-level declaration requires --grade. Records a project-updated event.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --grade state - Required grade floor: the minimum pack state a cell must reach to count toward done (e.g. hardened). Validated against the active pack's states.
  • --depth n - Optional minimum distinct-rev confirmation depth (FRESH-2; a positive integer). A cell below the floor is unmet.
  • --recency fresh|aging - Optional minimum freshness bucket (FRESH-3): fresh (must be fresh) or aging (fresh or aging, never stale). A cell whose freshness is presumed (no revision anchor) is UNKNOWN — unmet, remedied by re-affirming.
  • --scope scope - Set a per-scope override (e.g. s2) instead of the project defaults; an unset field inherits the project default.

Examples:

lettuce dod set --grade hardened --depth 2 --recency aging --project lettuce --author agent-1 --format json
lettuce dod set --scope s3 --depth 3 --project lettuce --author agent-1 --format json

Notes:

  • The verdict is a strict per-scope AND-gate over applicable (non-excluded) cells — a scope is met only when EVERY cell meets the bar, reported as a k/n count, never a blended percentage (docs/specs/dod-freshness-metrics-datascience.md). Setting knobs NEVER moves the hardened ratio: a scope can read 100% hardened yet DoD unmet (stale/shallow). The board masthead/section visual is DOD-2; this command sets the DATA.
  • This command sets ONLY the coverage floors (grade/depth/recency); the overall DoD verdict additionally layers two AUTO-DERIVED project-level outer gates you never set here — every committed milestone reached and zero non-terminal tickets — so a project can meet every coverage floor yet still read NOT DONE. Inspect them via dod show / board export (milestone_gate + ticket_gate).
dod clear

Usage: lettuce dod clear --project PROJECT [--scope SCOPE] [--depth] [--recency] [--grade]

Remove Definition-of-Done policy that dod set wrote. A BARE dod clear UNDECLARES the whole project DoD (removes every floor). --scope S removes scope S's override entirely. --depth/--recency (booleans here, optionally with --scope) clear just that floor. Clearing the PROJECT grade floor while the DoD stays declared is refused (a project DoD requires a grade) — undeclare the whole DoD instead. Records a project-updated event. Clearing a DoD/scope that is not declared returns FW-PATH-NOT-FOUND.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --scope scope - Target a scope override (e.g. s2) instead of the project defaults; with no floor flags it removes that scope's whole override.
  • --grade - Clear the grade floor (scope override only; refused at the project level — undeclare instead).
  • --depth - Clear the depth floor at the target.
  • --recency - Clear the recency floor at the target.

Examples:

lettuce dod clear --project lettuce --author agent-1 --format json
lettuce dod clear --scope s3 --project lettuce --author agent-1 --format json
lettuce dod clear --depth --project lettuce --author agent-1 --format json

Notes:

  • The DoD mutation surface was previously set-only; this closes that gap so a floor or override can be removed through lettuce instead of by hand-editing the store. HTTP-client parity: DELETE /v1/projects/{project}/dod.
dod show

Usage: lettuce dod show --project PROJECT

Show a project's Definition-of-Done policy (project-default grade/depth/recency floors + any per-scope overrides) AND the current verdict: per-scope met/unmet with a k/n met count and any unknown count, plus the project-level met_scopes/total_scopes (a strict AND-gate — done iff every scope is met). Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce dod show --project lettuce --format json
lettuce dod show --project lettuce --format plain

Notes:

  • A project that has declared no DoD (no grade floor) reports declared=false with no verdict — the board renders unchanged (DoD is opt-in). The verdict is the same strict-AND, per-scope, tri-state block board export carries under dod; a cell whose recency cannot be observed (presumed freshness) is unknown⇒unmet, counted separately so the remedy is visible.
  • Beyond the per-scope coverage gate, the verdict layers two ADDITIVE project-level outer gates the JSON carries as coverage_met plus milestone_gate {met,reached,total} and ticket_gate {met,open,total}: overall DONE ⟺ coverage-met AND every committed milestone reached (hypothesis-stage + canceled milestones are excluded from the committed set) AND zero non-terminal tickets. An unmet outer gate flips the overall verdict to unmet without touching the per-scope coverage rollup.
defaults show

Usage: lettuce defaults show --project PROJECT

Show a project's EFFECTIVE ladder — the resolved states, transitions, and gates (the bundled convention ⊕ the project's tweak layer), each tagged source=default|project, plus any hidden states. Read-only; the companion to the defaults tweak commands so an agent can inspect exactly what it changed without the (removed) pack show.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce defaults show --project lettuce --format json
lettuce defaults show --project lettuce --format plain

Notes:

  • A project that authors no tweak resolves byte-identically to the bundled default (every element source=default). CLI-only in this release (no REST route yet).
defaults state declare

Usage: lettuce defaults state declare SLUG --category open|in-progress|review|flagged --letter L [--rank N] [--name NAME] --project PROJECT

TWEAK the bundled convention's ladder: author an additive project STATE ('defaults not packs'). A project no longer authors a whole pack — it tweaks the default here. Additive-only: the slug must not already exist in the effective ladder. G3: only a working category (open/in-progress/review/flagged) — done/excluded are pack-structural and refused. Validate-on-write: a declare that would break the ladder's honesty invariants is refused with nothing written.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --category open|in-progress|review|flagged - Required working category for the new state (done/excluded are refused — they are pack-structural). Required.
  • --letter L - Required short grade glyph for the state (e.g. T). Required.
  • --rank int - Optional ladder rung (0 = unranked, sorts by slug).
  • --name name - Human label; defaults to the slug.

Examples:

lettuce defaults state declare triaging --category in-progress --letter T --rank 15 --project lettuce --author agent-1 --format json

Notes:

  • The effective ladder is the bundled default's states plus this additive project layer; a project that authors no tweak resolves byte-identically to the default. Every refusal happens BEFORE any write. REST parity: POST /v1/projects/{project}/states.
defaults state set-default

Usage: lettuce defaults state set-default SLUG --project PROJECT

Move the grading-at-entry DEFAULT onto a named state (a base or a project-declared state). Refused if the slug is not in the effective ladder, or if the move would leave the ladder without exactly one default (validate-on-write). A re-settable pointer.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce defaults state set-default smoke --project lettuce --author agent-1 --format json

Notes:

  • Records projects/<p>/ladder/default-state; the default flag moves everywhere the effective pack resolves. REST parity: PUT /v1/projects/{project}/ladder/default-state.
defaults state hide

Usage: lettuce defaults state hide SLUG --project PROJECT

HIDE a BASE-pack state (and its workflow edges) from the project's effective ladder — the subtractive tweak. Only a base state is hideable (a project-declared state is removed by deleting it). Refused if hiding would leave no default or no done state, or if the state still holds CELLS (they would be orphaned). Hiding cascade-drops the transitions into/out of the state.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce defaults state hide blocked --project lettuce --author agent-1 --format json

Notes:

  • Records a marker under projects/<p>/ladder/hidden/<slug>; ResolveEffectivePack drops the state + its edges. REST parity: PUT /v1/projects/{project}/ladder/hidden/{slug}.
defaults transition declare

Usage: lettuce defaults transition declare ACTION --from STATE --to STATE [--gate GATE] [--machine] --project PROJECT

Author an additive project TRANSITION (a workflow edge). The (action, from) pair is its identity; additive-only, create-once. Validate-on-write: --from/--to must resolve to declared states and --gate to a declared gate, else refused with nothing written. --gate is REQUIRED when --to is the done-category state (hardened): only a gate promotes to done (spec cells-v0.16.md §5 invariant 5), and an ungated entry would make cell set --state hardened unguarded for the whole project.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --from state - Required source state slug (must resolve in the effective ladder). Required.
  • --to state - Required target state slug (must resolve in the effective ladder). Required.
  • --gate gate - Guard gate slug (must resolve to a declared gate). Optional in general, REQUIRED when --to is the done state.
  • --machine - Mark the transition machine-applicable.

Examples:

lettuce defaults transition declare expedite --from untested --to gap --project lettuce --author agent-1 --format json
lettuce defaults transition declare fast-harden --from smoke --to hardened --gate guard-bite --project lettuce --author agent-1 --format json

Notes:

  • REST parity: POST /v1/projects/{project}/transitions.
defaults gate declare

Usage: lettuce defaults gate declare SLUG --check-kind KIND [--description D] --project PROJECT

Author an additive project GATE (a transition guard) a transition may then reference. Additive-only, create-once. Validate-on-write: --check-kind must be a shipped evaluator (e.g. guard-bite, consistency), else refused with nothing written.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --check-kind kind - Required gate evaluator (a shipped check-kind, e.g. guard-bite or consistency). Required.
  • --description text - Optional one-line description of what the gate checks.

Examples:

lettuce defaults gate declare peer-review --check-kind consistency --description 'two approvals' --project lettuce --author agent-1 --format json

Notes:

  • REST parity: POST /v1/projects/{project}/gates.
defaults reset

Usage: lettuce defaults reset [--only ladder|dod|dimensions] --project PROJECT

Clear a project's tweak layer back to the bundled convention. --only ladder (the default) removes the states/transitions/gates/set-default/hidden overlay; --only dod removes the Definition-of-Done policy (the project reverts to UNDECLARED); --only dimensions removes the project's runtime dimension layer. Per-scope orphan guards refuse a reset that would strand cells: the ladder reset is refused if a cell holds a project-declared state it would remove, and the dimensions reset if a cell coordinate names a project-declared dimension it would remove (reassign or clear those cells first); the dod reset carries no cell-orphan concern. A no-op-clean reset (nothing to clear) still succeeds.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --only ladder|dod|dimensions - Which tweak layer to clear (default: ladder). dod reverts the project's Definition-of-Done to undeclared; dimensions removes the project's declared runtime dimensions.

Examples:

lettuce defaults reset --only ladder --project lettuce --author agent-1 --format json
lettuce defaults reset --only dod --project lettuce --author agent-1 --format json
lettuce defaults reset --only dimensions --project lettuce --author agent-1 --format json

Notes:

  • Deleting the tweak subtrees is recorded as a project-defaults-reset lifecycle event scoped to the cleared layer. CLI-only in this release (no REST route yet).

Links to

Graph Authoring — Commands

↑ top

reference/cmd-graph-authoring

lettuce Graph Authoring commands — 10 entries — graph-def create, graph-def revise, graph-def show, graph-def list, graph-def compile, graph-def lint, graph-def viz, graph-def catalog list, graph-def catalog show, graph-def use.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Graph Authoring — Commands

lettuce command group Graph Authoring — 10 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • graph-def create
  • graph-def revise
  • graph-def show
  • graph-def list
  • graph-def compile
  • graph-def lint
  • graph-def viz
  • graph-def catalog list
  • graph-def catalog show
  • graph-def use

---

Author graph-defs — the first-class, named, versioned authoring object a run-case enacts (mission-graph-engineering SCH-3a/3b/4). A graph-def is DATA at projects/<p>/graph-defs/<slug>/: nodes (typed by concern) wired by edges, plus a start node; its spec body is stored append-only-versioned like a task body. CREATE folds in the CORE soundness gate — an unsound spec (dangling edge, unreachable node, missing start, uncapped cycle) is refused FW-GRAPH-DEF-UNSOUND and never stored, so every stored graph-def is sound by construction, and pins the compiled effective-hash (F30). A node may also be a SUBGRAPH that inlines another def by name (uses: <slug>@<version>) and binds its open ports (bind) — COMPOSITION (SCH-4): COMPILE resolves the transitive uses closure, inlines every referenced def, and hashes the WHOLE expansion, so editing a used pattern moves every parent's effective-hash; a composition cycle is refused FW-GRAPH-DEF-CYCLE and a missing used def FW-PATH-NOT-FOUND. LINT reports advisory design smells (warnings, never fatal). STRUCTURED PARALLELISM (fork/join/quorum, SCH-2b) and LOOP ITERATION primitives (min_times/until_stable/until_drain/circuit_breaker on a capped back-edge, SCH-2b-2) are authored, validated, and hashed here; their RUNTIME enactment is live in graph-run-case — fork opens concurrent branches, a K-of-M join fires only once quorum arrives (else FW-GRAPH-JOIN-UNSATISFIED), and a loop back-edge exits only when its oracle is satisfied (ENACT-1/2/3). ROUTER GUARDS (ENACT-5) are authored here too: a router's out-edge MAY carry a when condition over recorded run-case facts, refused FW-GRAPH-DEF-UNSOUND (invalid-guard) if malformed / off a router / leaving two default edges, and folded into the effective-hash — its RUNTIME enactment is live in graph-run-case (FW-GRAPH-ROUTE-UNSATISFIED / -AMBIGUOUS / -NO-MATCH). The remaining schema surface (carrier-types) and an HTTP route remain deferred. Local + dedicated-git only (no HTTP route yet).

graph-def create

Usage: lettuce graph-def create SLUG --spec-file PATH --project PROJECT --author AUTHOR

Author a graph-def from a JSON spec file. Reads and parses the spec, runs the CORE soundness gate (every edge references a declared node; no unreachable node; a declared start node; every loop back-edge capped), and — only if sound — stores it as a versioned object with provenance (author/created-at/created-by) plus the compiled effective-hash pin. A node may be a SUBGRAPH (uses: <slug>@<version>) that inlines another def and binds its open ports (bind); an EXPLICIT <slug>@N reference need not exist yet at authoring time (a forward or deliberately-cyclic reference pins the hash provisionally and is enforced at compile). A FLOATING reference (<slug>@latest or an omitted version) is RESOLVED and PINNED to the current highest stored version of <slug> AT AUTHOR TIME, so the stored spec is reproducible: its effective-hash can never move when a child later gains a version. A @latest (or omitted) reference to a child that does not exist yet cannot be pinned and is refused FW-GRAPH-DEF-UNPINNABLE — name an explicit <slug>@N or author the child first. The soundness gate also covers STRUCTURED PARALLELISM (SCH-2b): a fork must branch (out-degree ≥ 2, else degenerate-fork), a join must merge (in-degree ≥ 2, else degenerate-join), and a join's quorum K must satisfy 0≤K≤M over its M inputs (else invalid-quorum; a non-zero quorum off a join is also invalid). It also covers LOOP ITERATION (SCH-2b-2): the min_times/until_stable/until_drain/circuit_breaker primitives are valid only on a capped loop back-edge (else invalid-iteration) and every bound must stay inside 0..cap. It also covers the NODE EXEC-POLICY (SCH-7): an optional per-node exec_policy {model, effort, residency} must use the closed effort ladder (low|medium|high) and the closed residency set (resident|ephemeral), a model/capability-tier token matching the open token grammar, and must not be an empty object — anything else is invalid-exec-policy naming the node. A subgraph (uses) node carries no exec_policy of its own — it may instead carry exec_policy_default (SCH-7b), the COMPOSITION-SEAM policy port: a default applied to the BEHAVIORAL stations of the subtree it inlines, knob by knob and ONLY where that station left the knob unset, so a composite can staff a reuse at its tier's price while an atom that declared its own policy always wins. exec_policy on a uses node, or exec_policy_default on a leaf, is refused. And it covers ROUTING GUARDS (ENACT-5): a when guard is valid only on a ROUTER's out-edge, must parse against the closed fact vocabulary (carrier./outcome./effect.), and a guarded router may keep at most ONE unguarded default out-edge — anything else is invalid-guard, so a bad guard is learned at AUTHORING time, never as a runtime surprise. An unsound spec is refused FW-GRAPH-DEF-UNSOUND naming the offending node/edge, and nothing is written. A malformed (non-JSON) spec, or a malformed uses/bind ref, is a usage error. UNKNOWN KEYS ARE WARNED, NOT REFUSED (LET-734): a spec is stored VERBATIM and its bytes fold into effective-hash, so a key the schema does not recognise reads BACK as declared (graph-def show's spec field returns it, the hash covers it, and a run-case pins that hash) while NOTHING reads it. create/revise scan the raw JSON and report every unrecognised key with its path (nodes[<id>].<key>, edges[<from>-><to>].<key>, nodes[<id>].exec_policy.<key>, or a bare top-level key) on BOTH surfaces (LET-913): the human line on stderr, and the same diagnostic in the success envelope's warnings[] array under --format json|yaml, so an automated author sees it too; exit stays 0 and the def is still stored, because unknown-field tolerance is deliberate and refusing would make every already-stored spec unrewritable. The truth is the PARSED view — the nodes/edges arrays of the same payload — and it shows by ABSENCE. Note produces on an EDGE is NOT a schema field: the produces post-check validates the CALLER's --produces flag against stored carriers, never the edge's declaration.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --spec-file path - Path to the graph-def JSON spec: {"start":NODE,"nodes":[{"id":…,"concern":producer|reviewer|router|gate|human|verifier|terminal|fork|join,"quorum":K?,"instruction":TEXT?,"exec_policy":{"model":TOKEN?,"effort":low|medium|high?,"residency":resident|ephemeral?}?} | {"id":…,"uses":"<slug>@<version>","bind":{"start":NODE,"terminal":NODE},"exec_policy_default":{"model":TOKEN?,"effort":low|medium|high?,"residency":resident|ephemeral?}?}],"edges":[{"from":…,"to":…,"edge":…,"cap":N?,"min_times":K?,"until_stable":N?,"until_drain":bool?,"circuit_breaker":M?,"when":GUARD?}]}. A loop back-edge must carry a positive cap; a subgraph node carries uses (not concern) and binds its open ports. SHAPE vs BEHAVIOR (SCH-6): concern is the SHAPE/role term (the structure the runtime enforces); instruction is the optional per-node BEHAVIORAL CONTRACT — what the agent at this station DOES (e.g. an interrogator's 'generate probing questions over edge cases and require a satisfactory answer to each'). It is a leaf-node attribute (a subgraph/uses node inherits behavior from the referenced def and carries none) and it FOLDS INTO the effective-hash, so behavior is part of the content-addressed identity: two defs of identical shape but different instructions hash differently. It is optional — a leaf def without one still validates (only the advisory missing-instruction lint warns on a behavioral node that lacks one). STRUCTURED PARALLELISM (SCH-2b): a fork must branch (out-degree ≥ 2) and a join must merge (in-degree ≥ 2); a join MAY carry quorum:K (a K-of-M threshold over its M inputs; 0/omitted = an AND-join over all M) — quorum is valid only on a join and folds into the effective-hash. LOOP ITERATION (SCH-2b-2): a capped loop back-edge MAY refine how it iterates/exits — min_times (a floor of K iterations), until_stable (exit after N consecutive clean waves), until_drain (exit when the work-queue drains), circuit_breaker (trip after M unproductive iterations). Each is valid ONLY on a cap>0 back-edge (else invalid-iteration) and every bound must stay inside 0..cap; all fold into the effective-hash. Loop runtime enactment is live in graph-run-case (ENACT-3): a back-edge taken before the oracle is satisfied is refused FW-GRAPH-LOOP-NOT-CONVERGED / FW-GRAPH-ITERATION-FLOOR, and a visit past the cap FW-GRAPH-LOOP-CAP-EXCEEDED. NODE EXEC-POLICY (SCH-7) — the THIRD vocabulary beside SHAPE (concern) and BEHAVIOR (instruction): exec_policy declares HOW a station is RUN. model is the model or capability-tier the agent at this node should use (an OPEN, grammar-checked token — model names evolve, so the set is deliberately not closed; tier words like frontier/balanced/fast work too); effort is the reasoning-effort tier from the CLOSED ladder low|medium|high; residency is the CLOSED actor lifecycle resident|ephemeral — whether the actor KEEPS ITS CONTEXT across loop iterations (resident) or is spawned FRESH each wave (ephemeral). Every knob is independently optional, but an EMPTY exec_policy object is refused. Like instruction it is a leaf-node attribute and it FOLDS INTO the effective-hash, so HOW a node runs is part of the content-addressed identity and flipping resident->ephemeral mints a new version. THE COMPOSITION SEAM (SCH-7b): a SUBGRAPH (uses) node may carry exec_policy_default — the same three knobs, but read as a DEFAULT for the behavioral stations of the subtree it inlines. It FILLS BLANKS and never overrides: a station keeps every knob it set and gains only the knobs it left unset, so a composite can run one reuse cheap and another dear (the composite knows the TIER; the atom cannot) while an atom author's explicit staffing stays authoritative. It applies to behavioral concerns only (fork/join/terminal have no agent to staff), reaches the WHOLE inlined subtree, and nests nearest-wins. It does not appear in the expansion — the uses node disappears when inlined — so what folds into the hash is the RESULT: a def declaring no default expands byte-identically to before the field existed. The advisory missing-residency lint warns when a behavioral node INSIDE a declared loop leaves its residency implicit. ROUTER GUARDS (ENACT-5): an out-edge of a ROUTER node MAY carry when:GUARD — a boolean condition over facts the run-case RECORDS, in a tiny deterministic grammar: REF == "VALUE" / REF != "VALUE" combined with and/or/not and parentheses, where REF is carrier.<key>, outcome.<clean|progress|level-up|queue-remaining> or effect.<cell-hardened|task-opened|artifact-added|dod-progressed|transition> (e.g. carrier.decision == "approved"). Semantics are EXACTLY-ONE-MATCH: at most one out-edge may hold, and a guarded router may declare at most ONE unguarded out-edge as its default (else) route. A malformed guard, a guard on a non-router out-edge, or a second default edge is refused invalid-guard; the guard folds into the effective-hash (changing it moves the def's identity). Runtime enactment is live in graph-run-case (FW-GRAPH-ROUTE-UNSATISFIED / FW-GRAPH-ROUTE-AMBIGUOUS / FW-GRAPH-ROUTE-NO-MATCH). Required.

Examples:

lettuce graph-def create review-linear --spec-file ./graph-def.json --project lettuce --author agent-1 --format json

Notes:

  • The spec is stored verbatim (a fuller authored spec's extra fields are preserved, ignored by this slice) EXCEPT that a floating uses: <slug>@latest / omitted-version ref is rewritten to the concrete <slug>@N it resolved to at author time (so a stored version is reproducible). Soundness is checked BEFORE storage so a run-case can never enact a broken topology. Local + dedicated-git only.
graph-def revise

Usage: lettuce graph-def revise SLUG --spec-file PATH --project PROJECT --author AUTHOR

REVISE an existing graph-def: append a NEW spec version (spec/{N+1}) from a JSON spec file and re-pin the effective-hash from that NEW version. Revise is the in-band spec-version authoring path (SCH-4b) — the counterpart to create: create is for a NEW slug (a slug already in use is refused), revise APPENDS to a slug that already exists (a missing slug is refused FW-PATH-NOT-FOUND). It reads and parses the new spec, runs the SAME CORE soundness gate as create (every edge references a declared node; no unreachable node; a declared start; every loop back-edge capped; the fork/join/quorum + loop-iteration checks) and — only if sound — appends it as the next version and moves the pin: after revise, graph-def show/compile reflect the LATEST spec and its new effective-hash. An UNSOUND spec is refused FW-GRAPH-DEF-UNSOUND and NOTHING is appended (the latest version is unchanged). The append is version-safe: earlier versions are never touched, so a parent that pins uses: <slug>@1 still compiles to the OLD expansion while uses: <slug>@2 picks up the new one — that is the version-pin payoff. Revise applies the SAME author-time pinning as create: a floating uses: <slug>@latest / omitted-version ref in the NEW spec is resolved and PINNED to the current highest stored version before the version is appended (so every stored version is reproducible); a @latest of an unauthored child is refused FW-GRAPH-DEF-UNPINNABLE. A malformed (non-JSON) spec, or a malformed uses/bind ref, is a usage error. UNKNOWN KEYS ARE WARNED, NOT REFUSED (LET-734): a spec is stored VERBATIM and its bytes fold into effective-hash, so a key the schema does not recognise reads BACK as declared (graph-def show's spec field returns it, the hash covers it, and a run-case pins that hash) while NOTHING reads it. create/revise scan the raw JSON and report every unrecognised key with its path (nodes[<id>].<key>, edges[<from>-><to>].<key>, nodes[<id>].exec_policy.<key>, or a bare top-level key) on BOTH surfaces (LET-913): the human line on stderr, and the same diagnostic in the success envelope's warnings[] array under --format json|yaml, so an automated author sees it too; exit stays 0 and the def is still stored, because unknown-field tolerance is deliberate and refusing would make every already-stored spec unrewritable. The truth is the PARSED view — the nodes/edges arrays of the same payload — and it shows by ABSENCE. Note produces on an EDGE is NOT a schema field: the produces post-check validates the CALLER's --produces flag against stored carriers, never the edge's declaration.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --spec-file path - Path to the NEW graph-def JSON spec to append as the next version (same schema as graph-def create). It is parsed + soundness-checked before storage; an unsound spec is refused and nothing is appended. Unrecognised keys are WARNED on stderr AND in the success envelope's warnings[] array (exit 0), never refused — see the command description. Required.

Examples:

lettuce graph-def revise review-linear --spec-file ./review-linear-v2.json --project lettuce --author agent-1 --format json

Notes:

  • A <slug>@<version> reference PINS a specific spec version; a floating @latest (or omitted version) is pinned to the current highest version AT AUTHOR TIME so the stored spec is reproducible. Reusing a slug in create is still refused (create=new, revise=append). Local + dedicated-git only.
graph-def show

Usage: lettuce graph-def show SLUG --project PROJECT

Render a stored graph-def: its identity, start node, nodes (id + concern/SHAPE + a behavioral node's instruction/BEHAVIOR + a node's exec_policy/EXECUTION (or a subgraph node's exec_policy_default seam default) + a join's quorum), edges (from/to + optional carrier/cap + a router out-edge's ENACT-5 when routing guard), the compiled effective-hash, and the raw stored spec. concern is the SHAPE (role/geometry), instruction is the BEHAVIOR (what the agent does), and exec_policy is the EXECUTION policy (model/effort/residency — how the station is run) — three distinct fields so you can SEE what a node IS, what it DOES, and how it RUNS. Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-def show review-linear --project lettuce --format json

Notes:

  • Reads the latest spec version back and re-parses it for the node/edge view; the effective-hash is recomputed and agrees with the stored pin (it folds in each node's instruction AND its exec_policy, so behavior and execution are both part of identity).
graph-def list

Usage: lettuce graph-def list --project PROJECT

List a project's graph-defs (slug, identity, start node, and node/edge counts), sorted by slug. Read-only; a project with no graph-defs lists empty.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-def list --project lettuce --format json

Notes:

  • A light summary; use graph-def show SLUG for the full spec.
graph-def compile

Usage: lettuce graph-def compile SLUG --project PROJECT --author AUTHOR

Compile a stored graph-def to its CANONICAL effective form and content-hash it, re-pinning the effective-hash scalar (the F30 pin a run-case records at open). Canonicalization is deterministic and order-invariant: nodes are sorted by id, edges by their full tuple, and insignificant whitespace is dropped via a canonical JSON re-encode, so any spelling of the same topology yields the same sha256 hash. Idempotent — re-compiling an unchanged def rewrites the identical hash (a no-op). For a leaf def compile is exactly canonicalize + hash; for a COMPOSITE def (SCH-4) it resolves the transitive uses closure, inlines every referenced def (namespacing inlined node ids), and hashes the WHOLE expansion — so editing a used def and recompiling moves the parent's hash. Compile is the composition ENFORCEMENT point: a cycle is refused FW-GRAPH-DEF-CYCLE, a missing used def FW-PATH-NOT-FOUND, and an unbound port / unsound expansion FW-GRAPH-DEF-UNSOUND.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce graph-def compile review-linear --project lettuce --author agent-1 --format json

Notes:

  • The effective-hash covers the executable topology (start/nodes/edges) of the full expansion, NOT the graph-identity label — a rename does not move the hash; a real topology change (here or in any used subgraph) does. Local + dedicated-git only.
graph-def lint

Usage: lettuce graph-def lint SLUG --project PROJECT

Lint a stored graph-def for ADVISORY design smells — legal-but-questionable topological shapes: a fan-out with no join (a leaked parallel split), a terminal node with an out-edge (a terminal should be a sink), a gate/verifier that dead-ends (routes nowhere), a review/verify edge carrying no evidence carrier, a behavioral node with no instruction (missing-instruction — its SHAPE is declared but its BEHAVIOR is left implicit; SCH-6), a behavioral node INSIDE a declared loop with no exec_policy.residency (missing-residency — a looping actor is either resident, keeping context across iterations, or ephemeral, respawned each wave, and the same topology behaves differently either way; SCH-7), and a SUBGRAPH node whose uses child cannot be resolved in this project (unresolvable-subgraph — an explicit <slug>@N reference is deliberately storable before the child exists, so a def can sit in this state indefinitely; LET-1202). Smells are WARNINGS surfaced via warnings[] (machine) / stderr (human) with exit 0 — distinct from soundness, which is fatal. A smelly def is still sound and still runs; lint is advice, not a gate. Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-def lint review-linear --project lettuce --format json

Notes:

  • A clean def lints with an empty warnings[] and clean:true. Each smell names its kind + offending node/edge (FW-GRAPH-DEF-SMELL).
graph-def viz

Usage: lettuce graph-def viz SLUG [--format mermaid|dot] --project PROJECT

VISUALIZE a stored graph-def as a diagram (INT-4) — mermaid (default) or dot. Node SHAPE encodes the concern: producer (stadium), gate (diamond), human (parallelogram), router (hexagon), terminal (subroutine box), fork/join (trapezoids), reviewer/verifier (rectangle); a SUBGRAPH (uses) node renders as ONE cylinder labelled with its uses ref (the default view does NOT recursively inline it). SHAPE vs BEHAVIOR (SCH-6): the node shape + concern tag are the SHAPE; a behavioral node ALSO gets a labelled 'behavior: <short instruction>' line (a short tooltip form of its instruction) so the diagram shows both what a node IS and what it DOES, kept on distinct lines. SCH-7 adds a THIRD labelled line, 'exec: model=… effort=… residency=…', for a node carrying an exec_policy — how the station is RUN; a SUBGRAPH node renders its SCH-7b seam default as 'exec default: …' instead, since it staffs everything inside it rather than a station of its own. A join's label annotates its quorum (join (2 of 3)); a loop back-edge (cap>0) renders DASHED with its cap and iteration primitives (cap=5 min_times:1 until_stable:2); a ROUTER out-edge carrying an ENACT-5 routing guard appends it (when: carrier.decision == "approved"), so the diagram SHOWS the condition under which each branch is taken. The diagram is DETERMINISTIC (nodes sorted by id, edges by tuple) so it is stable/diffable, and always VALID mermaid (ids are made safe, labels escaped). The global --format selects the wrapper: mermaid|dot print the raw diagram to stdout (pipe it to a .mmd/.dot file or a renderer, or paste into a GitHub/artifact mermaid block); json|yaml wrap it in the envelope's diagram field; the human default prints the raw mermaid. Read-only; an unknown slug is FW-PATH-NOT-FOUND.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-def viz review-linear --project lettuce --format mermaid

Notes:

  • mermaid renders natively on GitHub, mobile, and artifacts and converts cleanly to PNG. A --expand flag that inlines composite (uses) subgraphs is deferred; the default view shows a uses node as one node.
graph-def catalog list

Usage: lettuce graph-def catalog list

List the SHIPPED named-pattern catalog (mission-graph-engineering SCH-5a) — canonical, versioned, VERIFIED graph-def patterns embedded in the binary (usage by name). Each row is a pattern key (name@vN), its declared cost_hint (the WORST-CASE cost band for one full run of the pattern — an ordinal minimal/low/moderate/high/very-high, deliberately not a currency or a duration), its one-line description, and its compiled effective-hash. Browse by cost_hint to pick the CHEAPEST process that will do. Read-only and project-independent (the catalog is embedded, not stored per-project); browse it, then materialize a pattern with graph-def use.

  • kind: read
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-def catalog list --format json

Notes:

  • The catalog ships gate@v1, tracer-bullet@v1, review-panel@v1, claim-verification@v1, audit-wave@v1 (a review panel looped until N consecutive clean waves — convergence), harden-loop@v1 (a fix→verify cycle with a circuit-breaker), red-team@v1 (an adversarial panel whose join is unanimous — every attack branch must clear), question-based-verification@v1 (an interrogator verifier feeding a must-answer gate), external-audit@v1 (a convergence audit loop signed off by a distinct out-of-loop auditor), review-panel@v2 (a raised-bar voting panel — 5 reviewers, 4-of-5 supermajority quorum), claim-verification@v2 (a raised-bar unanimous 3-of-3 claim check), and deep-review@v1 (a COMPOSITE-AND-high-bar pipeline that REUSES the atoms via version-pinned uses: subgraph nodes — tracer-bullet@1 → review-panel@2 → red-team@1 → claim-verification@2 → question-based-verification@1 → external-audit@1 → harden-loop@1 → gate@1 — pinning the raised-quorum @v2 atoms for the panel and claim stages), and escalating-review@v1 (the CHEAP-FIRST cost gradient: a Tier-0 screening gate staffed at low effort on a fast model, a ROUTER that climbs to Tier-1 review-panel@1 only when a carrier recorded tier0-verdict == "escalate", a second router that climbs to Tier-2 deep-review@1 only when a carrier recorded tier1-verdict == "escalate", and each router's single UNGUARDED out-edge landing on a terminal — so an unrecorded verdict EXITS cheap instead of buying an expensive review), escalating-review@v2 (the same gradient with its INTERIORS staffed — the two uses: nodes carry an exec_policy_default that fills in whatever staffing the inlined atoms left open), tournament@v1 (pairwise competition whose crown ROUTER DECLARES NO DEFAULT EDGE: an advance with no recorded comparison dead-ends FW-GRAPH-ROUTE-NO-MATCH instead of falling through to a champion, and a 2-of-2 join is the match barrier — a winner must have BEATEN someone), and generate-and-filter@v1 (many candidates against ONE bar pinned BEFORE generation, whose tally router's single UNGUARDED out-edge lands on an EMPTY terminal — rejecting every candidate is the DEFAULT outcome and reaching the shortlist is what a recorded keep verdict earns, so the filter can always return zero). Every pattern declares a cost_hint: an AUTHORING-TIME ordinal band for the WORST case of one run (the ceiling over every route, never the expected cost, which depends on the population of work). It is catalog metadata beside the description, so it does NOT fold into the effective-hash, and the RUNTIME NEVER READS IT — escalation is decided by router guards over recorded evidence, while observed cost stays ENACT-6 evidence. It is validated against the closed ladder and must be MONOTONE over composition: a composite's band is at least the band of every pattern in its uses-closure, so a thin wrapper can never advertise deep-review@v1 as cheap. A pattern may be a uses:-composite of other catalog patterns; its effective-hash covers the fully-inlined expansion (catalog-hash == compile-hash == the hash a materialized def compiles to), and re-pinning a stage to a new atom version is what moves the composite's hash while patterns pinned to an older version stay reproducible (older atom versions are immutable). Every pattern is sound by construction and compiles to a stable effective-hash; a def materialized from a pattern (graph-def use) compiles to that SAME hash. Does not require an initialized store.
graph-def catalog show

Usage: lettuce graph-def catalog show NAME@vVERSION

Show ONE shipped catalog pattern (SCH-5a): its declared cost_hint (the worst-case cost band for one full run), its start node, nodes (id + concern/SHAPE, a join's quorum, each behavioral node's instruction/BEHAVIOR, and any exec_policy/EXECUTION), edges (from/to + optional carrier/cap + a router out-edge's ENACT-5 when routing guard), the compiled effective-hash, and the raw pattern spec. Every shipped pattern carries a real instruction on each behavioral node (the catalog holds itself to that bar), so a pattern named for a behavior actually carries the words that make it do it. Read-only and project-independent; an unknown pattern is refused FW-PATH-NOT-FOUND naming the requested name@version.

  • kind: read
  • requires root: false
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-def catalog show review-panel@v1 --format json

Notes:

  • The effective-hash shown here is the pin a def materialized from this pattern (graph-def use) will compile to — the pattern is faithfully reproduced. Does not require an initialized store.
graph-def use

Usage: lettuce graph-def use NAME@vVERSION --as SLUG --project PROJECT --author AUTHOR

MATERIALIZE a shipped catalog pattern (SCH-5a) as a NEW graph-def SLUG in the project — usage by name. It resolves the pattern by name (unknown -> FW-PATH-NOT-FOUND), then stores its spec via the same path as graph-def create: the CORE soundness gate runs and the compiled effective-hash is pinned, so the new def compiles to the SAME hash the catalog reports (a faithful materialize). The result is an ordinary stored graph-def — composable (a uses node), compilable, and enactable by a run-case. A slug already in use is refused exactly as create. --bind re-wiring of a pattern's open ports at use time is DEFERRED; specialize a materialized pattern the normal way (a parent def that uses it and binds its ports).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --as slug - The slug for the new graph-def the pattern is materialized as (required). A slug already in use is refused, exactly as graph-def create. Required.

Examples:

lettuce graph-def use review-panel@v1 --as my-review --project lettuce --author agent-1 --format json

Notes:

  • A straight materialize: the pattern's verified spec becomes the new def's body, so soundness + the effective-hash pin apply. Compile the new def (graph-def compile SLUG) to confirm its hash equals the catalog's. Local + dedicated-git only.

Links to

Graph Run-Cases — Commands

↑ top

reference/cmd-graph-run-cases

lettuce Graph Run-Cases commands — 12 entries — graph-run-case open, graph-run-case advance, graph-run-case close, graph-run-case abandon, graph-run-case show, graph-run-case viz, graph-run-case list, graph-run-case conform, graph-run-case refs-to, carrier produce, carrier list, carrier show.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Graph Run-Cases — Commands

lettuce command group Graph Run-Cases — 12 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • graph-run-case open
  • graph-run-case advance
  • graph-run-case close
  • graph-run-case abandon
  • graph-run-case show
  • graph-run-case viz
  • graph-run-case list
  • graph-run-case conform
  • graph-run-case refs-to
  • carrier produce
  • carrier list
  • carrier show

---

Enact a linear graph run-case on the real ledger (mission-graph-engineering slice 1): open a run-case, produce its write-once edge carriers, advance it across gated edges, and close it. A graph-run-case is an event-sourced object at projects/<p>/graph-run-cases/ whose state == f(events); carriers are content-addressed write-once data at projects/<p>/carriers/. Fork branches, K-of-M join quorum firing, loop iteration/convergence, and CONDITIONAL ROUTING out of a router are all enacted at runtime here (ENACT-1/2/3/5), each guarded by a refusal (FW-GRAPH-JOIN-UNSATISFIED, FW-GRAPH-LOOP-NOT-CONVERGED, FW-GRAPH-ROUTE-UNSATISFIED). A router picks its out-edge from the run-case's OWN recorded evidence (carriers, wave outcomes, produced effects) evaluated through a small deterministic guard grammar — never from the caller's say-so. An HTTP surface remains deferred. CLI + local/dedicated-git only.

graph-run-case open

Usage: lettuce graph-run-case open --graph GRAPH --start NODE --project PROJECT

Open a new run-case enacting a graph-def, positioned at its declared start node. --graph must name a graph-def the project DECLARES (an unknown slug is refused FW-GRAPH-DEF-UNKNOWN listing the defs that exist) and --start must be that def's declared start (anything else is refused FW-GRAPH-START-UNDECLARED, stating the start that works) — a reference must resolve at the moment it is recorded, else the pin below binds to nothing. Writes a case-opened event (revision 1) asserting state==start-node, and returns the minted grc id for advance/close. The event ALSO records the REPRODUCIBILITY PIN when the named graph-def has a stored effective-hash: graph_effective_hash binds this run to the exact compiled topology it started on, so a later graph-def revise/compile moves the DEF's hash without re-pointing this run's evidence — the ledger stays falsifiable. The pin is copied verbatim from the def's effective-hash scalar (never recomputed here) and cached on the run-case as a derived scalar the merge-heal derived-check re-reads from the event.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --graph graph-def - The graph-def SLUG this run-case enacts; it must name a def stored in the project, else FW-GRAPH-DEF-UNKNOWN (e.g. review-linear). The stored def's effective-hash is pinned onto the case-opened event as graph_effective_hash. Required.
  • --start node - The start node the case opens at (the case-opened event asserts it as the run-case state). It must equal the graph-def's declared start, else FW-GRAPH-START-UNDECLARED; a composite whose start is a uses-node also accepts the inlined effective start. Required.

Examples:

lettuce graph-run-case open --graph review-linear --start producer --project lettuce --author agent-1 --format json

Notes:

  • The engine stays graph-def-free AFTER open — advance reads no spec, so --to/--edge/--quorum are caller-supplied evidence and an in-flight run is never stranded by a def edit. OPEN is the exception (LET-733): --graph must resolve to a stored def and --start must be its declared start, because the reproducibility pin taken here is what binds the run to a process. The gate is on NEW opens only — a run-case already recorded still shows, lists, advances, closes, conforms and validates even if its def is later revised, renamed or deleted, and a historical case with no pin stays legal. Local + dedicated-git only — there is no HTTP route yet.
graph-run-case advance

Usage: lettuce graph-run-case advance GRC --from NODE --to NODE --edge EDGE [--visit N] [--open-branch | --branch COORD | --fire-join --quorum K | --wave-close (--clean|--not-clean) [--progress] [--level-up] [--queue-remaining N] | --loop-exit --loop-edge EDGE [--min-times K] [--until-stable N] [--until-drain] [--circuit-breaker M]] [--cap N] [--route-edge EDGE=WHEN]... [--route-else EDGE] [--duration-ms N] [--cost-usd AMOUNT] [--produces KEY]... [--effect KIND|REF[|CARRIER]]... [--gate-task REF --gate-action ACTION --gate-reason TEXT]

Advance a run-case across an edge. Before writing the case-advanced event it runs the produces post-check (each --produces KEY must already exist as a carrier on the leaving edge×visit → else FW-GRAPH-PRODUCES-UNSATISFIED) and, when the gate trio is set, the reused task requires-* PRE-gate (a missing requirement bites FW-WF-REQUIREMENT-UNSATISFIED). Each --effect records an INT-5 produced-effect (the mutation this node performed as it left) on the case-advanced event, foldable back via the event log. On success state==--to, revision bumps by one. ENACT-1 concurrent branches: --open-branch opens a branch OUT of the fork node --from (the main state stays on the fork so its OTHER out-edges each open their own branch) instead of moving the single state; --branch COORD advances WITHIN an open branch, guarded on THAT branch's tip. A plain advance (neither flag) is the unchanged linear single-state walk. ENACT-3 loop iteration: --wave-close records one closed wave's outcome (a self-transition at the loop head) on the loop back-edge×visit; a NORMAL back-edge advance is bounded by --cap (visit<=cap, else FW-GRAPH-LOOP-CAP-EXCEEDED) and barred once --circuit-breaker M consecutive non-progress waves have tripped (FW-GRAPH-CIRCUIT-TRIPPED); --loop-exit advances out of the loop only when the derived oracle (--min-times/--until-stable/--until-drain over the wave-closed log) is met or the breaker tripped. Every loop decision is a pure fold over the wave-closed event log (replay-stable), and a fabricated exit is refused at merge-heal (Class-B). ENACT-5 conditional routing: when the advance leaves a ROUTER, pass the router's out-edge guard set with repeatable --route-edge 'EDGE=WHEN' (plus --route-else EDGE for the single unguarded default). The engine resolves the guards' facts from THIS run-case's ledger — carrier values on this visit, the latest closed wave's outcome, recorded produced-effect kinds — evaluates every guard, and refuses unless --edge is the edge the guards SELECT (FW-GRAPH-ROUTE-UNSATISFIED), the selection is unique (FW-GRAPH-ROUTE-AMBIGUOUS: two guards true, or a carrier fact with two divergent values) and something matches (FW-GRAPH-ROUTE-NO-MATCH when no guard holds and no default is declared). A refused route leaves the main state UNCHANGED. The decision and the evidence it consumed are recorded on the case-advanced event (route-taken/route-guard + the route/ and route-facts/ groups) and folded into its content-addressed id, so the routing is auditable, replay-stable, de-duping across clones, and a fabricated route is refused at merge-heal (Class-B). ENACT-6 run telemetry: --duration-ms and --cost-usd record the OBSERVED cost of the step this advance performed, stored VERBATIM on the case-advanced / branch-advanced event as immutable evidence (the engine reads no clock — the CALLER supplies the numbers). Telemetry is EVIDENCE, NEVER CONTROL INPUT: no derived-state reader folds it, so routing, joins, loops, the terminal and replay are all untouched by what a step cost — the same run with different telemetry folds to an identical state, revision and transition sequence. It IS folded into the content-addressed event id (like --effect and the routing decision), so an identical re-record de-dupes while a DIVERGENT reading for the same transition forks the chain (Class-B) instead of being silently unioned. It is refused (never silently dropped) on the control-bookkeeping intents --open-branch/--fire-join/--wave-close/--loop-exit, which do not perform the work; graph-run-case show reports the per-run totals.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --from node - The node being left. Required.
  • --to node - The resolved node being entered (stored verbatim so state is always recomputable). Required.
  • --edge edge - The producing/traversed edge, e.g. producer->gate. With --fire-join it is instead the ARRIVING BRANCH edge (e.g. v1->join), because a join fire collapses the fork onto the join rather than traversing an edge — see --fire-join. Required.
  • --visit n - Loop-iteration index for the traversal (default 0 for the single-flow linear slice).
  • --open-branch - ENACT-1: OPEN a concurrent branch OUT of the fork node --from along --edge, instead of moving the single state. The branch id is content-addressed (sha256 of grc·fork·edge·visit); the fork stays the main state so each out-edge opens a distinct branch. Mutually exclusive with --branch.
  • --branch coord - ENACT-1: advance WITHIN the open branch of this content-addressed coordinate (from --open-branch/show), guarded on the branch's own tip rather than the main state. Mutually exclusive with --open-branch.
  • --fire-join - ENACT-2: FIRE a K-of-M join — collapse the main state from the fork --from onto the join --to, exactly-once, once at least --quorum distinct branches have ARRIVED (tip == the join). Refused with FW-GRAPH-JOIN-UNSATISFIED below quorum. A fire is NOT an edge traversal, so --edge names one of those ARRIVING BRANCH edges (v1->join) and never <from>-><to>: fork->join — the value --from/--to make obvious — is refused FW-GRAPH-JOIN-EDGE-UNARRIVED, naming the edges branches did arrive on. That fact is read from THIS run-case's branch ledger, not the graph-def, so the runtime stays graph-def-free. The join-fired event is content-addressed over the fork→join transition ALONE — grc·fork·visit·join, independent of the arrived-set, the quorum AND the arrival --edge — and records the fired-on branch coords as a coordinate-named set that unions coordination-free, so two clones firing the same join de-dupe to one fired state whichever arrived edge each of them named (LET-918: with three branches arrived there are three equally TRUE edges, so folding the caller's pick forked the chain on honest concurrent work). The recorded --edge is therefore provenance rather than identity, and stays accountable through the derived check: a fire must cite an edge one of its recorded arrived branches genuinely came in on, else FW-STORE-MERGE-CONFLICT at heal. Because the id no longer varies with --edge, firing a LOOPED fork/join a second time with the FIRST lap's --visit would address the first lap's event: that is refused FW-GRAPH-JOIN-ALREADY-FIRED (pass the --visit this lap's branches were opened with), where before it overwrote the earlier fire in place. Mutually exclusive with --open-branch and --branch.
  • --quorum k - ENACT-2: the effective K-of-M threshold for --fire-join (>=1) — the number of distinct arrived branches required to fire. The caller resolves the join schema's quorum=0 (AND-join) to K=M before firing (this runtime slice is graph-def-free, like --produces).
  • --wave-close - ENACT-3: record a WAVE-CLOSED event — one wave (a traversal producer→…→loop head) has completed. A self-transition at the loop head (--from must equal --to; state unchanged) that bumps the revision and records the wave's outcome (--clean/--not-clean, --progress, --level-up, --queue-remaining) on --edge (the loop back-edge) × --visit. Content-addressed over (grc·edge·visit·outcome): two clones closing the same wave with the same outcome de-dupe; a divergent outcome forks the chain (Class-B). Mutually exclusive with --loop-exit/--open-branch/--branch/--fire-join.
  • --loop-exit - ENACT-3: advance OUT of the loop (loop head → --to), guarded on the derived exit oracle folded from the wave-closed log for --loop-edge. Refused (FW-GRAPH-ITERATION-FLOOR / FW-GRAPH-LOOP-NOT-CONVERGED, state unchanged) unless min_times/until_stable/until_drain are satisfied — or the circuit breaker has tripped (a forced failure exit). The loop-exited event records the effective params so the exit stays derivable (a fabricated exit is Class-B). Mutually exclusive with --wave-close/--open-branch/--branch/--fire-join.
  • --loop-edge edge - ENACT-3: the loop back-edge whose wave-closed log the --loop-exit oracle folds (e.g. gate->fork).
  • --clean - ENACT-3 (--wave-close): the wave converged cleanly — extends the consecutive-clean run (until_stable). Opposite of --not-clean; the default is not-clean.
  • --not-clean - ENACT-3 (--wave-close): the wave did NOT converge — resets the consecutive-clean run (until_stable).
  • --progress - ENACT-3 (--wave-close): the wave made a defined outcome delta — resets the consecutive-non-progress run (circuit_breaker). Its absence is a non-progressing wave.
  • --level-up - ENACT-3 (--wave-close): the wave recorded a level-up finding — RESETS the consecutive-clean run even if the wave was clean (waves cover the full scope, so a level-up restarts convergence).
  • --queue-remaining n - ENACT-3 (--wave-close): the work-queue depth the wave observed (until_drain). The loop exits when the LATEST wave records --queue-remaining 0.
  • --cap n - ENACT-3: the effective hard cap on a loop back-edge advance — a back-edge advance at --visit > --cap is refused (FW-GRAPH-LOOP-CAP-EXCEEDED). The provably-terminating backstop.
  • --min-times k - ENACT-3 (--loop-exit): the loop floor — the exit is refused until at least K waves have closed.
  • --until-stable n - ENACT-3 (--loop-exit): convergence — the exit is enabled only after N consecutive clean (non-level-up) waves.
  • --until-drain - ENACT-3 (--loop-exit): the exit is enabled when the latest wave records --queue-remaining 0 (the work-queue drained).
  • --circuit-breaker m - ENACT-3: trip the loop after M consecutive non-progressing waves. On a back-edge advance a tripped breaker bars the loop (FW-GRAPH-CIRCUIT-TRIPPED); on --loop-exit a tripped breaker permits a forced failure exit.
  • --route-edge edge=when - ENACT-5: one GUARDED out-edge of the router being left — the edge name, an =, and the when guard authored on it (only the FIRST = separates, so the guard's own == stays intact). Repeatable: pass the router's WHOLE guard set, because the semantics are exactly-one-match (two guards true is FW-GRAPH-ROUTE-AMBIGUOUS). The guard is a boolean over facts the run-case RECORDS: REF == "VALUE" / REF != "VALUE" with and/or/not and parentheses, REF being carrier.<key>, outcome.<clean|progress|level-up|queue-remaining> or effect.<kind>. An unrecorded fact reads as the empty string. Graph-def-free like --quorum/--produces: the caller resolves the guards from the stored def. Repeatable.
  • --route-else edge - ENACT-5: the router's single UNGUARDED out-edge — the DEFAULT (else) route taken when no guard holds. Without it a no-match is a loud dead-end (FW-GRAPH-ROUTE-NO-MATCH) rather than an arbitrary fall-through. A matching guard always beats the default.
  • --duration-ms n - ENACT-6: the OBSERVED wall-clock duration of this step, in milliseconds (non-negative). Recorded verbatim on the advance event as immutable evidence — the engine measures nothing itself. An explicit 0 means "observed, cost nothing" and is distinct from omitting the flag (not observed). Valid on a plain or --branch advance only.
  • --cost-usd amount - ENACT-6: the OBSERVED cost of this step in USD (a non-negative decimal with at most 6 decimal places, e.g. 0.42). Converted EXACTLY to micro-USD (1 USD = 1000000) and stored as an integer, so sums are exact and 0.42 / 0.420000 record identical evidence; a finer precision is refused FW-CMD-USAGE rather than rounded away. Valid on a plain or --branch advance only.
  • --produces key - An output carrier key the leaving node declares; the produces post-check refuses the advance unless a carrier exists on this edge×visit for the key. Repeatable.
  • --effect kind|ref[|carrier] - An INT-5 produced-effect recorded on the case-advanced event, pipe-separated: an effect KIND (one of cell-hardened, task-opened, artifact-added, dod-progressed, transition), the object-REF it mutated, and an OPTIONAL carrier back-ref to the justifying evidence. Pipe is unambiguous (it appears in neither a kind nor an object-ref). Valid on a plain or --branch advance only: like the ENACT-6 telemetry flags it is REFUSED, never silently dropped, on the control-bookkeeping intents --open-branch/--fire-join/--wave-close/--loop-exit, which open/reconverge/count rather than perform the work an effect attests to (LET-1507 — the drop returned ok:true and left the completion gate reporting the task referenced 0 times). Repeatable.
  • --gate-task task-ref - Backing task whose workflow transition is the reused requires-* PRE-gate; runs before the advance.
  • --gate-action action - Workflow action to fire on --gate-task (the gated transition).
  • --gate-reason text - Reason recorded on the gate transition (for transitions that require one).

Examples:

lettuce graph-run-case advance grc_… --from producer --to gate --edge producer->gate --produces artifact --project lettuce --author agent-1 --format json
lettuce graph-run-case advance grc_… --from fork --to r1 --edge fork->r1 --open-branch --project lettuce --author agent-1 --format json
lettuce graph-run-case advance grc_… --from r1 --to join --edge r1->join --branch 4f… --project lettuce --author agent-1 --format json
lettuce graph-run-case advance grc_… --from producer --to gate --edge producer->gate --duration-ms 1250 --cost-usd 0.42 --project lettuce --author agent-1 --format json
lettuce graph-run-case advance grc_… --from route --to approve --edge route->approve --route-edge 'route->approve=carrier.decision == "approved"' --route-edge 'route->reject=carrier.decision == "rejected"' --project lettuce --author agent-1 --format json

Notes:

  • The produces post-check and the reused-task PRE-gate are the contract's teeth; a refused advance leaves state unchanged. An --effect is a RECORD of a mutation performed through the shipped ops path (declared by the executor, never sniffed). ENACT-1 opens/advances branches; ENACT-2 --fire-join reconverges them (K-of-M quorum gating the fork→join main-state fire, exactly-once and coordination-free); ENACT-5 --route-edge/--route-else make a ROUTER pick its own out-edge from recorded evidence — they guard a plain main-state advance and are mutually exclusive with --open-branch/--branch/--fire-join/--wave-close/--loop-exit (routing INSIDE an open branch is deferred). Local + dedicated-git only.
graph-run-case close

Usage: lettuce graph-run-case close GRC --from NODE [--outcome TEXT] [--disposition VALUE] --project PROJECT

Close a run-case at a terminal node. Writes a case-closed event asserting the terminal sentinel state (__closed__) with the given outcome (default completed).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --from node - The terminal node being closed from. Required.
  • --disposition value - LET-728: the CLOSED structural claim about this run — completed | abandoned | failed (default completed). Separate from --outcome because it decides whether the run-case ledger is CONFORMANCE-CHECKED, and a claim expressible in free prose would let the checked party suppress a real error with text it writes itself. completed claims the process was walked to a terminal node; failed asserts the process DID run and the work did not pass, so it stays checked; abandoned claims nothing and is NOT checked — which is what stops honest closure of an unfinished run being punished with an error while leaving it open stayed a mere warning.
  • --outcome text - The close outcome recorded on the event (default completed). FREE PROSE, deliberately — the codebase records meaningful domain results here (haiku-accepted, cleared-at-tier-0, again) and a closed set would destroy that. The structural claim lives in --disposition.

Examples:

lettuce graph-run-case close grc_… --from terminal --outcome completed --project lettuce --author agent-1 --format json

Notes:

  • Local + dedicated-git only.
graph-run-case abandon

Usage: lettuce graph-run-case abandon GRC --reason TEXT --project PROJECT

LET-915: record a terminal ABANDONED disposition on a run-case that was opened and never walked to the end — the recorded answer to "what happened to this run", never a delete. It resolves the node the case is parked on ITSELF (there is no --from: abandoning claims nothing about where the run got to, so it bypasses no gate, and having to show a stranded case before you could dispose of it was most of why such cases read as unreachable). --reason is REQUIRED, unlike close's --outcome: an abandonment records no work, so the reason is the whole of what the ledger can say. It writes the SAME case-closed event close --disposition abandoned writes, through the same writer under the same lock — no second terminal, no second event kind — and refuses a CLOSED run-case (FW-GRAPH-CASE-CLOSED): terminal is terminal, and two dispositions is a fork in the record. An abandoned run is then EXCLUDED from the conformance denominator (graph-run-case conform reports excluded=true and exits 0 rather than judging a walk that never happened) while staying fully VISIBLE in list/show/doctor. Abandoning a run with concurrent branches still open is allowed and WARNS (FW-GRAPH-RUN-CASE-BRANCHES-UNRESOLVED) naming each leftover tip: a branch has no disposition of its own, so the abandonment collapses the main state and leaves each tip where it stood rather than inventing a terminal nobody enacted.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Why the run was stopped. REQUIRED — recorded verbatim as the close event's outcome (the free-prose field), alongside disposition=abandoned. Without it the ledger says no more than the stranded state it replaces. Required.

Examples:

lettuce graph-run-case abandon grc_… --reason 'superseded by a rerun; the walk was never completed' --project lettuce --author agent-1 --format json

Notes:

  • Local + dedicated-git only.
  • NOT a delete: the run-case directory, its events, its branch ledger and its reproducibility pin all stay exactly where they are; one terminal event is appended. Deleting an event-sourced object to tidy a count is the tamper shape this family exists to refuse.
graph-run-case show

Usage: lettuce graph-run-case show GRC --project PROJECT

Read a run-case's derived scalars (graph, graph_effective_hash, state, revision) plus, for a CLOSED case, its CLOSE RECORD — disposition (the structural claim: completed|abandoned|failed) and outcome (the prose explaining it, which for an abandonment is the REQUIRED --reason). LET-1100: that reason was WRITE-ONLY, projected by no read surface, so retrieving the one field whose stated purpose is to answer "what happened to this run" meant cat-ing a file inside a content-addressed event directory. Both are omitted for an open case. Plus its PROVENANCE (opened_by/opened_at, folded from the case-opened event on each read — never a stored scalar, so the event stays the evidence) back from the ledger, plus the ENACT-1 in-flight branch projection (branches[]: each open branch's content-addressed coordinate, fork node, edge, visit, and current tip) and the ENACT-6 observed-cost totals (telemetry: how many steps carried an observation, the summed duration_ms, the exact cost_micro_usd and its human cost_usd rendering). The totals are DERIVED = f(events) — refolded from the durable event log (main chain + every branch) on each read, never a stored cache — and are EVIDENCE only: nothing in the run's control flow reads them. Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-run-case show grc_… --project lettuce --format json

Notes:

  • Reads the committed derived cache; the cache is a faithful projection of the event log (a crash mid-write is heal-forward-completable to the same fold). branches[] is empty/absent for a linear (no-fork) run-case, and telemetry is absent for a run that recorded no observations. opened_by/opened_at answer WHO opened this run and WHEN — the question graph-run-case abandon raises first, since on a shared store you do not dispose of a colleague's stranded case. They are DISTINCT from graph-run-case list's updated_by/updated_at, which report who last TOUCHED the run: for a never-walked case the two coincide, which is exactly why the near-miss misleads once anybody else advances it. Both are omitted (legally) when the case-opened event records no author — a half-written event is a real on-disk shape, and show reports what the ledger says rather than inventing a value. graph_effective_hash is the reproducibility pin recorded at open — the graph-def content identity this run walked; it is absent (legally, and permanently) for a run-case opened without one, and it does NOT move when the graph-def is later revised.
graph-run-case viz

Usage: lettuce graph-run-case viz GRC [--format mermaid] --project PROJECT

VISUALIZE a run-case as a MERMAID diagram with its run state OVERLAID (INT-4): the run-case's underlying graph-def is rendered (same shape-by-concern as graph-def viz), then the CURRENT node is highlighted and every VISITED node is styled distinctly (classDef current / classDef visited). It reuses the grc read path — the underlying def (by the grc's graph slug) plus the current state and the visited trail folded from the event log. The topology drawn is the spec version the run-case PINNED at open, resolved from its graph_effective_hash by the same resolver graph-run-case conform uses — NOT the def's latest version, so revising a graph-def never redraws a run that walked the earlier text. The global --format selects the wrapper: mermaid or the human default print the raw diagram to stdout; json|yaml wrap it in the envelope's diagram field (also carrying current + the visited trail). dot is not offered (the overlay is mermaid-specific). Read-only; an unknown run-case is FW-PATH-NOT-FOUND.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-run-case viz grc_… --project lettuce --format mermaid

Notes:

  • Every diagram STATES which spec text produced it, both as the envelope's basis field (pinned | latest-unpinned | trail-pin-unresolvable | trail-def-missing, alongside pinned_version / latest_version) and as a mermaid %% comment on the line under the flowchart header, so the provenance survives redirecting the raw diagram to a file. LET-1100: a NON-PROVING disposition (abandoned|failed) rides that same mechanism — a second %% comment under the basis, plus a disposition envelope field beside state — because an abandoned walk otherwise draws exactly the picture a completed one does, and an envelope-only fix is lost the moment the diagram is redirected. An ordinary completed or still-open run emits no such comment: a banner on every healthy run is the noise that trains a reader to skim the one that matters. A run-case that recorded NO pin is drawn against the latest spec and says so — absence is the pre-pin shape, not an error. If the graph-def is not stored, or the pin matches none of its stored spec versions (so the latest is a topology the run provably did not walk), a minimal graph is synthesized from the visited trail so viz always yields a diagram. A closed run-case (state __closed__) highlights no current node; all occupied nodes remain visited.
graph-run-case list

Usage: lettuce graph-run-case list [--open|--state STATE] --project PROJECT

ENUMERATE a project's graph-run-cases with their disposition (LET-726). Before this, run-cases were not listable AT ALL — no list command, no FQL source (from graph_run_cases is refused), and doctor carries no grc family — so SKILL.md 9.1's rule that "an opened-and-abandoned run-case is exactly as unproving as no run-case at all" was a doctrine nobody could measure; counting abandonment required ls on the store. Reports open AND abandoned as FIRST-CLASS counts. LET-1100: open alone was advertised as the abandonment figure and is not one — it counts cases with no close event, while an ABANDONED case IS closed. The unproving population §9.1 names is open+abandoned, so a reader taking total-open as "walks that proved something" over-counted by exactly the abandoned figure. Each case also carries its own disposition (completed|abandoned|failed, empty while open): before LET-1100 an abandoned case was byte-identical to a completed one here, so the census built to find unproving walks reported them as finished ones. CLOSED is the only name for finished: a run-case parked on a terminal NODE has NOT been closed (close is a distinct, explicit act), and conflating the two is exactly how a stalled case reads as complete. --open keeps only unclosed cases; --state NODE keeps only cases parked on that node (the abandonment query); the two are mutually exclusive and combining them is refused rather than silently resolved. Directory names are grammar-checked, so a stray directory cannot inflate the count. Deterministic order (run-case id). Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --open - Keep only run-cases that have NOT been closed — the population SKILL.md 9.1 calls unproving. Mutually exclusive with --state.
  • --state state - Keep only run-cases in this state. __closed__ selects finished cases; any node id selects cases parked on that node. Mutually exclusive with --open.

Examples:

lettuce graph-run-case list --project lettuce --format json
lettuce graph-run-case list --open --project lettuce --format json
graph-run-case conform

Usage: lettuce graph-run-case conform GRC --project PROJECT

CONFORMANCE REPLAY (LET-720): does this run-case's WALK match the graph-def it PINNED at open? The runtime is graph-def-free by design — advance reads no spec, so --to/--edge accept any string and a case can traverse an edge the def does not declare, name a node absent from it, or fire a K-of-M join below the declared K, and still close validate --strict clean. Every OTHER check over a run-case re-derives its verdict from parameters the run itself recorded (the join re-folds the quorum the caller wrote), which makes each one a fixed point: internally honest, and structurally unable to notice that the RECORDED number is not the DECLARED one. conform is the read-time counterpart that makes graph_effective_hash a binding rather than a label naming the topology a run merely claims to have followed. THE BASIS IS THE PINNED VERSION (LET-919): the pinned hash is resolved back to the spec/N that mints it and the walk is judged against THAT text, so revising a def cannot retroactively change a prior verdict — until LET-919 the pin was unresolvable and every walk was in fact judged against the def's LATEST spec, which moved the yardstick under every completed run. pinned_version/latest_version report the basis; a run-case that recorded NO pin (the pre-pin shape) is still judged against the latest and says so, because absence is history, not guilt. Findings: FW-GRAPH-CONFORM-UNDECLARED-EDGE (a transition the def does not declare), FW-GRAPH-CONFORM-QUORUM-BELOW-DECLARED (a join fired under its declared threshold), FW-GRAPH-CONFORM-UNKNOWN-NODE (a node the def does not contain), FW-GRAPH-CONFORM-CARRIER-MISSING (the walk CROSSED an edge whose pinned spec declares carrier: K and no carrier with that key is bound to it — reported per DECLARED EDGE, not per run-case, so a walk holding some of its verdicts and not others is caught; edges the walk never crossed are NOT reported, because demanding evidence on an edge a run-case has not reached would fire on honest in-flight work), FW-GRAPH-CONFORM-DEF-MISSING (the pinned def is gone, so conformance is UNKNOWN — never reported as conforming, because an absent def reading as a pass is the always-passes shape this command exists to remove), FW-GRAPH-CONFORM-PIN-UNRESOLVABLE (the def is here but NO stored spec version mints the pinned hash, so the topology walked cannot be recovered — no verdict is computed rather than one silently computed against the latest). A REPORT, not a refusal: existing run-cases predate the check and a non-conforming walk is evidence to read rather than corruption to block. EXIT 1 when the walk does not conform (or the def is missing, or the pin is unresolvable) so a script can gate on it without parsing JSON. A revised def is still reported as hash drift — that answers a different question, namely whether the def has moved since the run, and stays useful alongside the resolved basis. Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-run-case conform grc_5e9f90e2e3ec22c4588ef09c0b442b57 --project lettuce --format json

Notes:

  • A join FIRE is not an edge traversal: it collapses the main state from the fork onto the join, so its recorded from is the FORK while its edge names one of the ARRIVING BRANCH edges (declared out of the branch node, not out of the fork). conform checks a fire against the join's IN-edges accordingly.
graph-run-case refs-to

Usage: lettuce graph-run-case refs-to OBJECT-REF --project PROJECT

BACK-REFERENCE from an object to the run-cases that touched it (INT-15) — the REVERSE of the INT-5 forward effect edge. Given an OBJECT-REF (a cell coordinate-hash ref lettuce/cells/<hash>, a task, or any well-formed project/kind-plural/id ref), it scans every graph-run-case's case-advanced events and returns each recorded produced-effect that referenced that object: the run-case, the transition it was recorded on (from/to/edge), the effect kind, the exact stored effect ref, and the optional carrier back-ref to the justifying evidence. So a cell (or an evidence artifact) answers WHICH DECISIONS TOUCHED ME. The reverse index is DERIVED = f(events) — recomputed from the durable event log, never a cache — with deterministic ordering (grc id, then event order). Matching is on object identity (project/kind/id): a query for lettuce/cells/<hash> matches an effect that pinned lettuce/cells/<hash>@4 (the revision pin narrows a citation, not the object). An object nothing references returns an EMPTY references[] with ok=true — 'no back-references' is a valid answer, like an empty query, NOT a not-found error. A malformed OBJECT-REF is refused FW-CMD-USAGE with the ref grammar. Read-only.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce graph-run-case refs-to lettuce/cells/9f3a1c2b4d5e6f70 --project lettuce --format json

Notes:

  • The forward edge is recorded by graph-run-case advance --effect 'KIND|OBJECT-REF[|CARRIER]'; refs-to inverts it. Works for ANY object kind, not just cells — the operator's cell→GCR navigation and the general reverse lookup are one command. Local + dedicated-git only (no HTTP route yet). The cell-facing view of this reverse index is surfaced inline by cell show --with-references (INT-15b), so a cell viewer sees its provenance without a separate refs-to call.
carrier produce

Usage: lettuce carrier produce --graph-run-case GRC --node NODE --edge EDGE --key KEY --value VALUE [--visit N] [--carrier-type TYPE] [--ref ROLE|REF[|NOTE]]... --project PROJECT

Produce the write-once carrier an edge emits on one visit — an evented, content-addressed datum at projects/<p>/carriers/. The produces post-check on graph-run-case advance reads it back. Two clones producing the SAME value mint the SAME dir (git de-dupe); a divergent value on the same coordinate is a Class-B double-produce, refused HERE at the front door (FW-CARRIER-DOUBLE-PRODUCE) and, for divergence that arrives by merge rather than by a local call, at merge-heal. Before LET-1545 only the merge-heal half existed, so on a single filesystem-mode clone the refusal never ran. Each --ref attaches an INT-5 typed enrichment ref (folded into the carrier identity alongside value), turning the flat value into a navigable graph edge.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --graph-run-case grc-id - The run-case this carrier belongs to. Required.
  • --node node - The producing node (the node being left). Required.
  • --edge edge - The producing edge, e.g. producer->gate. Required.
  • --key key - The carrier key, e.g. artifact. Required.
  • --value value - The produced value (a ref/string in this slice, not a blob). Required.
  • --visit n - Loop-iteration index (default 0 for the single-flow linear slice). Must be a NON-NEGATIVE INTEGER with no leading zeros (0, 1, 2, …): the value is hashed VERBATIM into the coordinate, so "00" or " 0 " would give one iteration a second identity, and a non-index value mints a carrier no visit lookup can ever reach.
  • --carrier-type type - The value-kind tag (default string).
  • --ref role|ref[|note] - An INT-5 typed enrichment ref, pipe-separated: a ROLE (one of evidence, subject, tool, author, derived-from, produced-effect), the object-REF it points at, and an OPTIONAL free-text NOTE. Pipe is unambiguous (it appears in neither a role nor an object-ref); the note MAY contain pipes (only the first two are separators). Repeatable.

Examples:

lettuce carrier produce --graph-run-case grc_… --node producer --edge producer->gate --key artifact --value art:GATE-1/1 --project lettuce --author agent-1 --format json
lettuce carrier produce --graph-run-case grc_… --node producer --edge producer->gate --key artifact --value art:GATE-1/1 --ref 'subject|lettuce/tasks/LET-1|the ticket' --ref 'derived-from|lettuce/graph-run-cases/grc_…' --project lettuce --author agent-1 --format json

Notes:

  • Write-once: the carrier's coordinate is sha256(grc·edge·key·visit) and its dir id content-addresses (coordinate·value·refs). key is load-bearing — two distinct keys on one edge×visit are distinct carriers. node and carrier-type are RECORDED BUT NOT part of the identity (an edge already names its source node), so a produce differing only in those de-dupes onto the existing carrier, writes nothing, and keeps what the FIRST produce recorded — reported as a FW-CARRIER-DEDUPE-FIELD-DISCARDED warning rather than a refusal, since an exact re-produce is legitimate. A malformed --ref (bad role, malformed object-ref) is refused at the ops front door before any write. Local + dedicated-git only.
  • A carrier PRESENCE is what the LET-1446 transition gate and the LET-1448 conform check both test; NEITHER reads its VALUE. --value "." satisfies both exactly as well as a considered verdict. That is deliberate, because quality is not mechanizable, but it means a green gate proves evidence was RECORDED and nothing about whether it is any good.
carrier list

Usage: lettuce carrier list [--graph-run-case GRC [--visit N]] --project PROJECT

List the project's carriers, optionally narrowed to one graph-run-case and one visit. --visit narrows WITHIN a run-case and therefore REQUIRES --graph-run-case: a carrier stores its coordinate = sha256(grc·edge·key·visit) but NOT the visit, so membership of a visit is decided by RECOMPUTING the coordinate, which is impossible without the run-case. The same walk and the same recomputation back the router's fact projection, so carrier list and graph-run-case route can never disagree about which carriers belong to a visit.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --graph-run-case grc - Narrow to one graph-run-case id. The id is checked to EXIST: a run-case that is not stored is REFUSED (FW-PATH-NOT-FOUND), never reported as a run-case holding no carriers.
  • --visit n - Narrow to one loop-iteration index (non-negative integer, no leading zeros). Requires --graph-run-case.

Examples:

lettuce carrier list --project lettuce --format json
lettuce carrier list --graph-run-case grc_… --visit 0 --project lettuce --format table

Notes:

  • A carrier with no key or no edge is omitted: both are components of the coordinate, so such a carrier cannot be addressed by any lookup and is a member of no visit.
  • An unstored --graph-run-case is REFUSED rather than answered (LET-1029). Otherwise a mistyped or stale id and a real run-case holding nothing return the same bytes — (none) / count 0 / exit 0 — and the caller reads a typo as a finding. A run-case that EXISTS and holds no carriers still answers count 0, which is the distinction the refusal preserves.
carrier show

Usage: lettuce carrier show CARRIER-ID --project PROJECT

Show ONE carrier by its dir id, with its INT-5 typed enrichment refs. Reads through the same projection as carrier list, so show can never surface a carrier list omits nor render a field differently. An id that resolves to nothing is REFUSED (FW-PATH-NOT-FOUND) rather than reported as an empty carrier — a typo and a carrier with no fields are different answers.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce carrier show car_0123456789abcdef --project lettuce --format json

Notes:

  • The id is the content-addressed dir name: car_ + sha256(coordinate·value·refs) truncated. Get one from carrier list.

Links to

Import Export Repair And Sync — Commands

↑ top

reference/cmd-import-export-repair-and-sync

lettuce Import Export Repair And Sync commands — 10 entries — export, import, repair plan, repair check, repair apply, repair automatic, sync status, sync push, sync pull, conflict bundle.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Import Export Repair And Sync — Commands

lettuce command group Import Export Repair And Sync — 10 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • export
  • import
  • repair plan
  • repair check
  • repair apply
  • repair automatic
  • sync status
  • sync push
  • sync pull
  • conflict bundle

---

Move stores, repair issues, inspect conflicts, and synchronize dedicated Git mode.

export

Usage: lettuce export --bundle PATH

Write a deterministic export bundle outside the store root.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --bundle path - Output bundle path outside the store root. Required.

Examples:

lettuce export --bundle /tmp/lettuce-export.json --format json
import

Usage: lettuce import --bundle PATH

Import a supported bundle.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --bundle path - Input bundle path. Required.

Examples:

lettuce import --bundle /tmp/lettuce-export.json --author importer --format json
repair plan

Usage: lettuce repair plan

Produce a repair plan for current diagnostics.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce repair plan --format json
lettuce repair plan --format plain
repair check

Usage: lettuce repair check --plan PATH [--allow-high-intrusion] [--semantic-plan PATH]

Validate a repair plan without applying it.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): plan, semantic_plan, allow_high_intrusion
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --plan path - Repair plan JSON file.
  • --semantic-plan path - Conflict semantic plan JSON file.
  • --allow-high-intrusion - Allow high-intrusion semantic actions during checks.

Examples:

lettuce repair check --plan ./repair-plan.json --format json
repair apply

Usage: lettuce repair apply --plan PATH [--dry-run] [--allow-high-intrusion] [--semantic-plan PATH]

Apply or dry-run a validated repair plan.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): plan, semantic_plan, dry_run, allow_high_intrusion
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --plan path - Repair plan JSON file.
  • --semantic-plan path - Conflict semantic plan JSON file.
  • --dry-run - Preview without writing.
  • --allow-high-intrusion - Allow high-intrusion semantic actions.

Examples:

lettuce repair apply --plan ./repair-plan.json --dry-run --author agent-1 --format json
repair automatic

Usage: lettuce repair automatic --code CODE --path PATH [--dry-run]

Apply a supported safe automatic repair action. The action is selected by --code: FW-RUNTIME-MISSING and FW-RUNTIME-DIR-MISSING (runtime-skeleton-create), FW-RUNTIME-GITIGNORE-MISSING (runtime-git-exclude), FW-RUNTIME-CACHE-CORRUPT and FW-RUNTIME-CACHE-STALE (runtime-cache-delete), FW-PATH-MISSING-REQUIRED-DIR (required-empty-dir-create), FW-FILE-MISSING-NEWLINE (scalar-final-lf), FW-FILE-LIST-DUPLICATE and FW-FILE-LIST-UNSORTED (list-canonicalize), FW-REVISION-CHAIN-BROKEN (revision-heal-forward, or revision-field-heal-forward when the path is a settable task field). Any other code refuses with FW-REPAIR-UNSUPPORTED-ACTION.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --code diagnostic-code - Diagnostic code to repair. Required.
  • --path path - Diagnostic path to repair. Required.
  • --dry-run - Preview without writing.

Examples:

lettuce repair automatic --code FW-FILE-MISSING-NEWLINE --path projects/lettuce/tasks/LET-1/title --dry-run --format json
sync status

Usage: lettuce sync status

Inspect dedicated Git sync state.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce sync status --mode dedicated-git --format json
sync push

Usage: lettuce sync push

Push dedicated Git changes upstream.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce sync push --mode dedicated-git --format json
sync pull

Usage: lettuce sync pull

Pull dedicated Git upstream changes and validate.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce sync pull --mode dedicated-git --format json
conflict bundle

Usage: lettuce conflict bundle

Build a conflict-resolution bundle for semantic repair.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce conflict bundle --format json

Links to

Queries — Commands

↑ top

reference/cmd-queries

lettuce Queries commands — 13 entries — query run, query search, query tasks, query audit, query timeline, query graph, query saved create, query saved update, query saved archive, query saved unarchive, query saved list, query saved show, query saved run.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Queries — Commands

lettuce command group Queries — 13 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • query run
  • query search
  • query tasks
  • query audit
  • query timeline
  • query graph
  • query saved create
  • query saved update
  • query saved archive
  • query saved unarchive
  • query saved list
  • query saved show
  • query saved run

---

Run task queries, FQL, timelines, audits, full-text search, and saved queries.

query run

Usage: lettuce query run FQL [--case-sensitive] [--group-by FIELD] [--include-archived]

Execute one FQL statement.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): fql, case_sensitive
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --case-sensitive - Make the contains operator match case-sensitively.
  • --group-by field - Aggregate the matching tasks into buckets by a task field (one of assignee, component, milestone, severity, status, type, workflow); returns ordered {value,count} groups (count desc, value asc; a missing value falls into (none)) instead of the flat row list.
  • --include-archived - Include archived tasks in the results (hidden by default).

Examples:

lettuce query run 'from tasks where status = ready select task,title' --project lettuce --format json
lettuce query run 'from tasks select task,title,status' --project lettuce --format plain
lettuce query run 'from tasks select task,status' --group-by status --project lettuce --format json
lettuce query run 'from dimensions select dimension,family,applicability' --project lettuce --format json
lettuce query run 'from cells where dod = blocking select coordinate,state' --project lettuce --format json
lettuce query run 'from cells where freshness = stale select coordinate' --project lettuce --format json
lettuce query run 'from cells where depth >= 2 select coordinate' --project lettuce --format json
lettuce query run 'from cells where dod-reason = grade select coordinate' --project lettuce --format json
lettuce query run 'from cells where scope = s1 and grade = hardened select coordinate,scope,unit,grade' --project lettuce --format json

Notes:

  • FQL is positional. Read files yourself and pass the statement as an argument.
  • Sources: tasks, events, registry, authors, projects, dimensions (a project's active convention pack's declared evidence dimensions), and cells (the project's STORED coverage cells — sparse pack-defaults are NOT rows).
  • The cells source exposes the stored fields coordinate, state, hash (plus cell/project/pack identity) AND the DOD-4 derived axes freshness (fresh|aging|stale), depth (distinct-rev confirmation count, an int), dod (blocking|met), and dod-reason (grade|depth|recency|unknown for a blocking cell) — so from cells where dod = blocking / where freshness = stale / where depth >= 2 orient you at exactly what is not yet done. It ALSO exposes the coordinate-DIMENSION columns scope, unit, dim, group, kind (each the member the cell's coordinate names for that dimension) and grade (an alias of the cell's state slug), so where scope = s1 and grade = hardened slices a dimension directly instead of the opaque where coordinate contains "scope=s1"; a cell whose coordinate omits a dimension leaves that column absent.
  • Soft-archived tasks are hidden by default (matching task list / query tasks); pass --include-archived to include them.
query search

Usage: lettuce query search TEXT [--scope SCOPE] [--limit N] [--offset N] [--include-archived]

Search canonical task, comment, run, artifact, version, and registry text.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): text, scope, limit, offset
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --scope tasks|comments|runs|artifacts|versions|registry|all - Search scope.
  • --limit n - Maximum hits (positive integer).
  • --offset n - Hit offset (non-negative integer).
  • --include-archived - Include soft-archived tasks in the results (hidden by default).

Examples:

lettuce query search migration --project lettuce --scope tasks --format json
lettuce query search task --project lettuce --scope all --limit 20 --offset 0 --format json

Notes:

  • Soft-archived tasks are hidden by default (the same hidden-by-default contract as task list / query tasks); pass --include-archived to include them. Archived comments and artifacts remain searchable — archive hides them from list views, not from discovery.
query tasks

Usage: lettuce query tasks [--status STATUS] [filters] [--fields a,b] [--group-by FIELD] [--refs-only] [--include-archived] [--limit N] [--offset N]

Run the structured task list query.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): status, workflow, assignee, reporter, label, component, milestone, type, severity, priority_min, priority_max, due_before, due_after, updated_before, updated_after, parent, watcher, text, fields, group_by, refs_only, limit, offset
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --status status - Filter by workflow status.
  • --workflow workflow - Filter by workflow reference.
  • --assignee author - Filter by assignee.
  • --reporter author - Filter by reporter.
  • --label slug - Filter by label. Repeatable.
  • --component slug - Filter by component.
  • --milestone slug - Filter by milestone.
  • --type slug - Filter by task type.
  • --severity slug - Filter by severity.
  • --priority-min n - Minimum priority, inclusive.
  • --priority-max n - Maximum priority, inclusive.
  • --due-before timestamp - Due at or before this timestamp.
  • --due-after timestamp - Due at or after this timestamp.
  • --updated-before timestamp - Updated at or before this timestamp.
  • --updated-after timestamp - Updated at or after this timestamp.
  • --parent task-ref - Filter by parent task reference.
  • --watcher author - Filter by watcher. Repeatable.
  • --text text - Filter by free-text match.
  • --custom key=value - Filter by a custom-field value (repeatable; AND across keys). Repeatable.
  • --fields csv - Selected fields.
  • --group-by field - Aggregate the matching tasks into buckets by a task field (one of assignee, component, milestone, severity, status, type, workflow); returns ordered {value,count} groups (count desc, value asc; a missing value falls into (none)) instead of the flat row list. Parity with query run --group-by.
  • --refs-only - Return task references only.
  • --limit n - Maximum tasks.
  • --offset n - Task offset.
  • --include-archived - Include archived tasks in the results (hidden by default).

Examples:

lettuce query tasks --project lettuce --status ready --fields task,title,status --format json
lettuce query tasks --project lettuce --refs-only --format json
lettuce query tasks --project lettuce --group-by status --format json

Notes:

  • Soft-archived tasks are hidden by default (the same hidden-by-default contract as task list); pass --include-archived to include them.
query audit

Usage: lettuce query audit REF

Read audit events for a supported object reference.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): reference
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Examples:

lettuce query audit lettuce/LET-1 --format json
lettuce query audit lettuce/LET-1 --format plain
query timeline

Usage: lettuce query timeline --project PROJECT [filters]

Read a merged event timeline.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): task_ref, author_filter, kind, since, until
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --task task-ref - Restrict to a task.
  • --author author - Restrict to an event author.
  • --kind event-kind - Restrict to an event kind.
  • --since timestamp - Inclusive lower bound.
  • --until timestamp - Inclusive upper bound.

Examples:

lettuce query timeline --project lettuce --kind object-created --format json
lettuce query timeline --project lettuce --task lettuce/LET-1 --format json
query graph

Usage: lettuce query graph --project PROJECT [--relation depends-on|blocks] [--include-archived]

Analyze the project dependency DAG: report cycles and the critical (longest) dependency path.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --relation depends-on|blocks - Dependency relation to analyze (default depends-on).
  • --include-archived - Include soft-archived tasks in the DAG (default: hidden, consistent with query run / task graph); archived tasks otherwise distort roots/cycles/critical-path.

Examples:

lettuce query graph --project lettuce --format json
lettuce query graph --project lettuce --relation blocks --format json
query saved create

Usage: lettuce query saved create SLUG --title TITLE --fql FQL [--description TEXT] [--description-file PATH]

Create a project-scoped saved FQL query.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): slug, title, fql, description
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --title title - Saved query title. Required.
  • --fql statement - Stored FQL statement. Required.
  • --description text - Optional Markdown description.
  • --description-file path - Read description from file.

Examples:

lettuce query saved create ready-tasks --project lettuce --author agent-1 --title 'Ready Tasks' --fql 'from tasks where status = ready select task,title' --format json
query saved update

Usage: lettuce query saved update REF [--title TITLE] [--fql FQL] [--expect-revision N] [--description TEXT] [--description-file PATH]

Update saved query fields.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): reference, title, fql, description, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --title title - Replacement title.
  • --fql statement - Replacement FQL statement.
  • --description text - Replacement Markdown description.
  • --description-file path - Read replacement description from file.
  • --expect-revision n - Expected saved query revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce query saved update ready-tasks --project lettuce --author agent-1 --title 'Ready Work' --expect-revision 1 --format json
lettuce query saved update ready-tasks --project lettuce --author agent-1 --fql 'from tasks where status = ready select task,title,priority' --expect-revision 2 --format plain
query saved archive

Usage: lettuce query saved archive REF --expect-revision N

Archive a saved query without hard deleting history. Reversible with query saved unarchive.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): reference, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected saved query revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch. Required.

Examples:

lettuce query saved archive ready-tasks --project lettuce --author agent-1 --expect-revision 2 --format json
query saved unarchive

Usage: lettuce query saved unarchive REF --expect-revision N

Restore an archived saved query to active. The inverse of query saved archive, and like every other archival pair a NORMAL mutation in both directions: it requires an explicit author, records a saved-query-unarchived event, and is refused on a query that is not archived. Before LET-1516 this verb did not exist, so a single archive disabled the object permanently — re-creating under the same slug is refused, a saved query is not a registry kind so registry update cannot reach it, and query saved list kept showing a tombstone that could not be revived.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): reference, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected saved query revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch. Required.

Examples:

lettuce query saved unarchive ready-tasks --project lettuce --author agent-1 --expect-revision 3 --format json
query saved list

Usage: lettuce query saved list --project PROJECT

List saved query metadata.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce query saved list --project lettuce --format json
lettuce query saved list --project lettuce --format plain
query saved show

Usage: lettuce query saved show REF

Read one saved query.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): reference
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Examples:

lettuce query saved show lettuce/ready-tasks --format json
lettuce query saved show lettuce/ready-tasks --format plain
query saved run

Usage: lettuce query saved run REF [--include-archived]

Execute a stored saved query.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): reference
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --include-archived - Include archived tasks in the results (hidden by default).

Examples:

lettuce query saved run lettuce/ready-tasks --format json
lettuce query saved run lettuce/ready-tasks --format plain

Notes:

  • Soft-archived tasks are hidden by default (matching query run); pass --include-archived to include them.

Links to

Registries And Workflow — Commands

↑ top

reference/cmd-registries-and-workflow

lettuce Registries And Workflow commands — 14 entries — registry create, registry update, registry list, registry show, milestone create, milestone list, milestone show, milestone close, milestone reopen, milestone set-stage, workflow list, workflow show, workflow transition list, workflow revise.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Registries And Workflow — Commands

lettuce command group Registries And Workflow — 14 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • registry create
  • registry update
  • registry list
  • registry show
  • milestone create
  • milestone list
  • milestone show
  • milestone close
  • milestone reopen
  • milestone set-stage
  • workflow list
  • workflow show
  • workflow transition list
  • workflow revise

---

Manage labels, components, milestones, workflow, task types, artifact types, severities, and custom fields.

registry create

Usage: lettuce registry create KIND SLUG [registry flags]

Create a registry object.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): kind, slug, title, status, color, owner, due_at, rank, value_kind, required, description, allowed_values, workflow
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --title title - Registry title.
  • --status status - Registry object status (active/inactive; milestones also open/done/canceled).
  • --color #rrggbb - Display color.
  • --owner author - Owner author.
  • --due-at timestamp - Due timestamp.
  • --rank rank - Sort rank.
  • --value-kind kind - Custom field value kind: string, number, boolean, date, timestamp, author, label, task, graph-run-case, url, or slug. The REFERENCE kinds (author/label/task/graph-run-case) are resolved against the store, not pattern-matched — custom set refuses a value that names nothing, and a workflow requires-field gate over such a field is satisfied only by a value that still resolves. graph-run-case is the strongest: the gate additionally requires the cited run-case to have recorded a produced-effect on the gated task (the reverse of graph-run-case refs-to), so citing a real run-case that never touched the ticket is refused.
  • --required true|false - Custom field required policy.
  • --allowed-value value - Allowed custom field value. Repeatable.
  • --description text - Markdown description.
  • --description-file path - Read description from file.
  • --workflow-file path - Workflow definition JSON file.
  • --workflow-json json - Inline workflow definition JSON.
  • --idempotent - Treat an existing matching registry object as success.

Examples:

lettuce registry create label backend --project lettuce --author agent-1 --title Backend --color '#12abef' --format json

Notes:

  • KIND values include label, component, milestone, workflow, task-type, artifact-type, severity, and custom-field.
registry update

Usage: lettuce registry update KIND SLUG [registry flags]

Update mutable registry object fields.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): kind, slug, title, status, color, owner, due_at, rank, stage, confidence, value_kind, required, description, allowed_values
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --title title - Registry title.
  • --status status - Registry object status (active/inactive; milestones also open/done/canceled).
  • --color #rrggbb - Display color.
  • --owner author - Owner author.
  • --due-at timestamp - Due timestamp.
  • --rank rank - Sort rank.
  • --value-kind kind - Custom field value kind: string, number, boolean, date, timestamp, author, label, task, graph-run-case, url, or slug. The REFERENCE kinds (author/label/task/graph-run-case) are resolved against the store, not pattern-matched — custom set refuses a value that names nothing, and a workflow requires-field gate over such a field is satisfied only by a value that still resolves. graph-run-case is the strongest: the gate additionally requires the cited run-case to have recorded a produced-effect on the gated task (the reverse of graph-run-case refs-to), so citing a real run-case that never touched the ticket is refused.
  • --required true|false - Custom field required policy.
  • --allowed-value value - Allowed custom field value. Repeatable.
  • --description text - Markdown description.
  • --description-file path - Read description from file.
  • --stage stage - Milestone hypothesis-ladder stage (milestone kind only; drives its S4 ladder rung).
  • --confidence confidence - Milestone stage confidence label (milestone kind only).

Examples:

lettuce registry update label backend --project lettuce --author agent-1 --status inactive --format json
registry list

Usage: lettuce registry list KIND

List registry objects of one kind.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce registry list label --project lettuce --format json
lettuce registry list label --project lettuce --format plain
registry show

Usage: lettuce registry show (KIND SLUG | REF) [--with-description]

Read one registry object.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-description - Include the object's description text in the payload. OMITTED by default: descriptions are free-form prose and can be long, so a plain read stays compact and the caller opts in when they want it (LET-615).

Examples:

lettuce registry show label backend --project lettuce --format json
lettuce registry show label backend --with-description --project lettuce --format json
lettuce registry show label backend --project lettuce --format yaml
milestone create

Usage: lettuce milestone create SLUG [--title TITLE] [--due-at TS] [milestone flags]

Create a milestone. Convenience wrapper over registry create milestone with the milestone kind implied.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: true

Flags:

  • --title title - Registry title.
  • --status status - Registry object status (active/inactive; milestones also open/done/canceled).
  • --color #rrggbb - Display color.
  • --owner author - Owner author.
  • --due-at timestamp - Due timestamp.
  • --rank rank - Sort rank.
  • --value-kind kind - Custom field value kind: string, number, boolean, date, timestamp, author, label, task, graph-run-case, url, or slug. The REFERENCE kinds (author/label/task/graph-run-case) are resolved against the store, not pattern-matched — custom set refuses a value that names nothing, and a workflow requires-field gate over such a field is satisfied only by a value that still resolves. graph-run-case is the strongest: the gate additionally requires the cited run-case to have recorded a produced-effect on the gated task (the reverse of graph-run-case refs-to), so citing a real run-case that never touched the ticket is refused.
  • --required true|false - Custom field required policy.
  • --allowed-value value - Allowed custom field value. Repeatable.
  • --description text - Markdown description.
  • --description-file path - Read description from file.
  • --workflow-file path - Workflow definition JSON file.
  • --workflow-json json - Inline workflow definition JSON.
  • --idempotent - Treat an existing matching registry object as success.

Examples:

lettuce milestone create release-1 --project lettuce --author agent-1 --title 'Release 1' --format json

Notes:

  • Equivalent to lettuce registry create milestone SLUG [flags].
milestone list

Usage: lettuce milestone list

List milestones in a project.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce milestone list --project lettuce --format json
lettuce milestone list --project lettuce --format plain
milestone show

Usage: lettuce milestone show (SLUG | REF)

Read one milestone, including its task-completion progress rollup.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce milestone show release-1 --project lettuce --format json
lettuce milestone show release-1 --project lettuce --format yaml
milestone close

Usage: lettuce milestone close SLUG

Close a milestone (sets status=done).

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: true

Examples:

lettuce milestone close release-1 --project lettuce --author agent-1 --format json

Notes:

  • Equivalent to lettuce registry update milestone SLUG --status done.
milestone reopen

Usage: lettuce milestone reopen SLUG

Reopen a milestone (sets status=active). The symmetric inverse of milestone close, and the same status a freshly created milestone carries, so a closed or LET-436 strict-invalid milestone can be reactivated from the milestone surface itself.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: true

Examples:

lettuce milestone reopen release-1 --project lettuce --author agent-1 --format json

Notes:

  • Equivalent to lettuce registry update milestone SLUG --status active.
milestone set-stage

Usage: lettuce milestone set-stage SLUG --stage STAGE [--confidence C]

Progress a milestone's first-class hypothesis-ladder STAGE (and optional CONFIDENCE) — the fields the board S4 ladder renders its rung from. --stage is required; --confidence is optional. Both are stored as first-class scalar fields (not parsed from the description), so the ladder position is real data. Each is an evented mutation.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --stage stage - The milestone's hypothesis-ladder stage (drives its S4 ladder rung; e.g. hypothesis, validated). Required. Required.
  • --confidence confidence - Confidence label in that stage (e.g. low, high). Optional.

Examples:

lettuce milestone set-stage release-1 --stage validated --confidence high --project lettuce --author agent-1 --format json

Notes:

  • The stage/confidence are also settable one-at-a-time via registry update milestone SLUG --stage STAGE / --confidence C; set-stage is the compound convenience. The S4 ladder falls back to parsing a legacy milestone's stage (confidence): description prefix only when these fields are empty.
workflow list

Usage: lettuce workflow list

List workflow registry objects.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce workflow list --project lettuce --format json
lettuce workflow list --project lettuce --format plain
workflow show

Usage: lettuce workflow show WORKFLOW

Show workflow states and transitions, plus the LET-727 judgement-policy version record: which append-only version under workflows/<slug>/spec/ the live states and transitions correspond to (policy.matched_version), the hash of the policy as it stands right now (policy.live_hash), and any finding that the two disagree. A workflow is the BAR a task is judged against, so 'what does it enforce' is only half the answer without 'and is that the policy it has on record'. The policy block is OMITTED entirely for a workflow with no recorded versions — every store predating LET-727 — because absent history is not a finding, and an all-zero verdict would read as one.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): workflow
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Examples:

lettuce workflow show default --project lettuce --format json
lettuce workflow show default --project lettuce --format plain

Notes:

  • An in-place edit of a gate (say removing transitions/N/requires-lease by hand) leaves the workflow perfectly well-formed, so validate --strict still passes; it shows up HERE as a live_hash matching no recorded version, and as FW-WF-POLICY-UNVERSIONED from lettuce doctor.
workflow transition list

Usage: lettuce workflow transition list WORKFLOW

List workflow transitions.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): workflow
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Examples:

lettuce workflow transition list default --project lettuce --format json
lettuce workflow transition list default --project lettuce --format plain
workflow revise

Usage: lettuce workflow revise WORKFLOW (--workflow-file PATH|--workflow-json JSON) [--yes]

REVISE an existing workflow: replace its states and transitions with a complete new definition and append the resulting judgement policy as the next immutable version under workflows/<slug>/spec/{N+1}, re-pinning effective-hash from it. This is the verb that INSTALLS a gate on a store that already has tasks — registry create workflow --idempotent refuses (FW-CMD-IDEMPOTENCY-CONFLICT, correctly: idempotent means no-op, not overwrite) and a task cannot be moved between workflows, so before this a gated workflow could be authored but never applied. An IDENTICAL definition is a NO-OP: it reports revised=false and mints no version, so re-running a deploy script cannot inflate the history. An UNSOUND definition is refused with NOTHING written, and prior versions are never mutated. A revision that would leave in-flight tasks unable to make the transition in front of them is refused FW-WF-REVISE-UNCONFIRMED, NAMING those tasks, unless --yes is passed — which makes an unconfirmed run a safe dry run of what a revision would cost.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --workflow-file path - Path to the COMPLETE new workflow definition (same JSON schema as registry create's --workflow-file). Required unless --workflow-json is given; there is no default, because defaulting a revision to the built-in workflow would silently reset a customised policy.
  • --workflow-json json - The COMPLETE new workflow definition as inline JSON (same schema as --workflow-file).
  • --yes - Confirm a revision that would strand in-flight tasks (--force is accepted too).

Examples:

lettuce workflow revise default --workflow-file ./gated.json --project lettuce --author agent-1 --format json
lettuce workflow revise default --workflow-file ./gated.json --yes --project lettuce --author agent-1 --format json

Notes:

  • Run it WITHOUT --yes first: the refusal lists every task the new gates would block and writes nothing.
  • requires_lease and requires_reason are never reported as breakage — they are satisfied by the caller at transition time, not by task state.
  • Local + dedicated-git only; it refuses against --server-url.

Links to

Server And GitHub — Commands

↑ top

reference/cmd-server-and-github

lettuce Server And GitHub commands — 2 entries — serve, github init-repo.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Server And GitHub — Commands

lettuce command group Server And GitHub — 2 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • serve
  • github init-repo

---

Run the HTTP server and bootstrap GitHub repositories.

serve

Usage: lettuce serve [--listen ADDR] [--secret SECRET | --wordmade-id-verify-url URL ...] [--authz-policy PATH] [server flags]

Start the HTTP API server. Fail-closed (ADR-0008): a non-loopback --listen requires either shared-secret authentication or complete Wordmade ID authentication, unless --allow-unauthenticated-nonloopback is given, in which case startup warns.

  • kind: server
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --listen addr - Listen address. Default 127.0.0.1:8727. A non-loopback address requires authentication (see fail-closed note).
  • --secret secret - Legacy bearer token secret; cannot be combined with Wordmade ID mode.
  • --secret-file path - Read legacy bearer token secret from file (also via LETTUCE_API_SECRET_FILE).
  • --allow-ip ip-or-cidr - Allowed client IP or CIDR. Repeatable.
  • --trusted-proxy-cidr ip-or-cidr - Trusted proxy source range. Repeatable.
  • --rate-limit rpm - Legacy per-IP requests/minute (seeds --rate-ip-rpm; see the four ADR-0003 gates below). Also LETTUCE_RATE_LIMIT.
  • --rate-ip-rpm rpm - Per-IP requests/minute (ADR default 600). Also LETTUCE_RATE_IP_RPM.
  • --rate-actor-mutation-rpm rpm - Per-actor mutating requests/minute (ADR default 300); Wordmade ID derives the actor from the verified agent UUID. Also LETTUCE_RATE_ACTOR_MUTATION_RPM.
  • --rate-global-mutation-rpm rpm - Global mutations/minute across all actors (ADR default 60). Also LETTUCE_RATE_GLOBAL_MUTATION_RPM.
  • --rate-burst n - Per-IP burst: max requests in a 1s window (ADR default 60). Also LETTUCE_RATE_BURST.
  • --authz-policy path - Authorization policy JSON file. Required in Wordmade ID mode.
  • --auth-subject subject - Legacy authenticated subject name (ignored in Wordmade ID mode).
  • --wordmade-id-verify-url url - Wordmade ID /v1/verify endpoint. Enables Wordmade ID mode when combined with its required settings. Also LETTUCE_WORDMADE_ID_VERIFY_URL.
  • --wordmade-id-audience audience - Exact OAuth audience expected from Wordmade ID. Also LETTUCE_WORDMADE_ID_AUDIENCE.
  • --wordmade-id-organization name - Required X-Lettuce-Organization header value. Also LETTUCE_WORDMADE_ID_ORGANIZATION.
  • --wordmade-id-organization-token-file path - Required X-Lettuce-Organization-Token secret file. Also LETTUCE_WORDMADE_ID_ORGANIZATION_TOKEN_FILE.
  • --auto-provision-actors - Create missing derived agent authors for authorized mutations.
  • --allow-unauthenticated-nonloopback - Explicitly permit serving on a non-loopback address WITHOUT authentication (ADR fail-closed override); startup warns.
  • --recover-on-start - Self-heal a crashed prior writer at startup (dedicated-git): break its orphaned write.lock and DISCARD any uncommitted torn partial back to the last commit. Discards uncommitted state — your assertion that this server is the SOLE writer. Also LETTUCE_RECOVER_ON_START.
  • --push-interval duration - Auto-push to git remote at interval (e.g. 5m). dedicated-git only.

Examples:

lettuce serve --root . --listen 127.0.0.1:8727
github init-repo

Usage: lettuce github init-repo --org ORG --repo REPO [--pat TOKEN] [repo flags]

Create and initialize a GitHub repository for a store.

  • kind: maintenance
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --org org - GitHub organization. Required.
  • --repo repo - Repository name. Any name GitHub accepts; no prefix is required or enforced. Required.
  • --pat token - GitHub personal access token.
  • --pat-file path - Read GitHub token from file.
  • --remote name - Git remote name.
  • --default-branch branch - Default branch name.
  • --api-url url - GitHub API base URL (defaults through LETTUCE_GITHUB_API_URL). Set for GitHub Enterprise.
  • --private - Create the repository private (the default).
  • --public - Create the repository public.
  • --idempotent - Accepted for compatibility; NO-OP. Repository creation is ALWAYS idempotent here (GitHub 422 already-exists is treated as success whether or not this flag is passed), so it toggles nothing. Unlike init --idempotent, which does gate behaviour.

Examples:

lettuce github init-repo --org huru-io --repo lettuce-demo --author agent-1 --format json

Links to

Task Local Objects — Commands

↑ top

reference/cmd-task-local-objects

lettuce Task Local Objects commands — 35 entries — comment add, comment edit, comment status, comment list, comment show, comment archive, comment unarchive, comment delete, lease acquire, lease renew, lease release, lease steal, lease show, lease list, run start, run finish, run log add, run summar

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Task Local Objects — Commands

lettuce command group Task Local Objects — 35 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • comment add
  • comment edit
  • comment status
  • comment list
  • comment show
  • comment archive
  • comment unarchive
  • comment delete
  • lease acquire
  • lease renew
  • lease release
  • lease steal
  • lease show
  • lease list
  • run start
  • run finish
  • run log add
  • run summary add
  • run list
  • run show
  • run log list
  • run log show
  • run summary list
  • run summary show
  • artifact add
  • artifact replace
  • artifact list
  • artifact show
  • artifact archive
  • artifact unarchive
  • artifact delete
  • artifact file get
  • version add
  • version list
  • version show

---

Manage comments, leases, runs, artifacts, and versioned documents under tasks.

comment add

Usage: lettuce comment add REF [--body TEXT|--body-file PATH] [--parent COMMENT] [--expect-revision N]

Add a task comment.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, body, parent, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --body text - Comment body.
  • --body-file path - Read comment body from file.
  • --parent comment-id - Parent comment id.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce comment add lettuce/LET-1 --author agent-1 --body 'Looks good.' --format json
comment edit

Usage: lettuce comment edit REF COMMENT (--body TEXT|--body-file PATH) [--expect-revision N]

Add a new comment body version.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, comment_id, body, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --body text - Body text. Required.
  • --body-file path - Read body from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce comment edit lettuce/LET-1 1 --author agent-1 --body 'Updated.' --format json
comment status

Usage: lettuce comment status REF COMMENT STATUS [--expect-revision N]

Change comment status.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, comment_id, status, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected current revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce comment status lettuce/LET-1 1 resolved --author agent-1 --format json
comment list

Usage: lettuce comment list REF [--include-archived]

List task comments.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --include-archived - Include archived comments in the results (hidden by default).

Examples:

lettuce comment list lettuce/LET-1 --format json
lettuce comment list lettuce/LET-1 --include-archived --format json

Notes:

  • Archived comments are hidden by default, the same hidden-by-default contract task list and project list document. Archiving hides a comment from this list view, not from query search.
comment show

Usage: lettuce comment show REF COMMENT [--with-body] [--body-version V]

Read one task comment.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-body - Include comment body content.
  • --body-version v - Read a SPECIFIC historical body version instead of the latest (requires --with-body). Comment bodies are versioned by comment edit exactly as task bodies are by task body add, and this is the same flag the task show sibling documents. A version that does not exist is REFUSED and the existing ones are named — never silently served as the latest.

Examples:

lettuce comment show lettuce/LET-1 1 --with-body --format json
lettuce comment show lettuce/LET-1 1 --with-body --body-version 1 --format json
lettuce comment show lettuce/LET-1 1 --format plain
comment archive

Usage: lettuce comment archive REF COMMENT [--reason TEXT] [--expect-revision N]

Soft-archive a task comment without deleting it. Reversible with lettuce comment unarchive.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce comment archive lettuce/LET-1 1 --author agent-1 --reason 'Off-topic.' --format json

Notes:

  • Reversible and history-preserving; use lettuce comment delete for a hard removal.
comment unarchive

Usage: lettuce comment unarchive REF COMMENT [--reason TEXT] [--expect-revision N]

Restore a previously archived task comment.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce comment unarchive lettuce/LET-1 1 --author agent-1 --format json

Notes:

  • Only an archived comment can be unarchived; the inverse of lettuce comment archive.
comment delete

Usage: lettuce comment delete REF COMMENT (--yes|--force) [--reason TEXT] [--expect-revision N]

Hard-delete a task comment. Non-reversible: requires --yes (or --force) to confirm.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --yes - Confirm the non-reversible deletion.
  • --force - Alias for --yes: confirm the non-reversible deletion.
  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce comment delete lettuce/LET-1 1 --yes --author agent-1 --format json

Notes:

  • This is a hard, non-reversible removal; prefer lettuce comment archive when you only want to hide the comment.
lease acquire

Usage: lettuce lease acquire REF --expires-at TIMESTAMP [--token TOKEN]

Acquire a task lease.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, expires_at, lease_token, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expires-at timestamp - Lease expiration timestamp. Required.
  • --token token - Lease token of the form lease-YYYYMMDD-HHMMSS-<4..32 alphanumerics>. Generated when omitted for acquire.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce lease acquire lettuce/LET-1 --author agent-1 --expires-at 2099-12-31T00:00:00Z --format json
lease renew

Usage: lettuce lease renew REF --expires-at TIMESTAMP [--token TOKEN]

Renew a task lease.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, expires_at, lease_token, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expires-at timestamp - Lease expiration timestamp. Required.
  • --token token - Lease token of the form lease-YYYYMMDD-HHMMSS-<4..32 alphanumerics>. Generated when omitted for acquire.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce lease renew lettuce/LET-1 --author agent-1 --expires-at 2099-12-31T01:00:00Z --format json
lease release

Usage: lettuce lease release REF [--force --reason TEXT]

Release a task lease.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, force, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --force - Explicit safety override for supported cases.
  • --reason text - Reason text.
  • --reason-file path - Read reason from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce lease release lettuce/LET-1 --author agent-1 --format json

Notes:

  • --force requires --reason (or --reason-file): a forced release overrides another holder's lease, so an audit reason is mandatory. A normal (non-forced) release takes neither.
lease steal

Usage: lettuce lease steal REF --expires-at TIMESTAMP --reason TEXT [--force]

Steal an expired or abandoned task lease.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, expires_at, lease_token, force, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expires-at timestamp - Lease expiration timestamp. Required.
  • --token token - Lease token of the form lease-YYYYMMDD-HHMMSS-<4..32 alphanumerics>. Generated when omitted for acquire.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.
  • --force - Explicit safety override for supported cases.
  • --reason text - Reason text.
  • --reason-file path - Read reason from file.

Examples:

lettuce lease steal lettuce/LET-1 --author agent-2 --force --reason 'Worker expired.' --expires-at 2099-12-31T00:00:00Z --format json
lease show

Usage: lettuce lease show REF

Read current lease state — the reference and whether a lease is present, plus for a lease that IS present its holder, expires-at, and a derived active/expired status. The status answers the question the lease family exists for — is this lease stale, can I take it — without the caller re-deriving it against the clock and having to reproduce the boundary convention exactly to agree with lease list.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce lease show lettuce/LET-1 --format json
lettuce lease show lettuce/LET-1 --format plain

Notes:

  • status is OMITTED when no lease is present: present:false already states there is no lease, so there is nothing to classify. An absent status means "no lease", never "unknown". This differs from lease list, whose rows always carry a status because a row only exists for a lease that is there.
  • Derived from the operation clock by the same classifier lease list uses, so the two reads cannot disagree: active means expires-at is strictly in the future, at or after it is expired, and an unparseable or absent expires-at is conservatively expired (the same "not provably still held" stance the acquire and steal guards take). The ownership-asserting mutations — acquire, renew, steal, release — report what the caller just did rather than a state read, and carry no status.
lease list

Usage: lettuce lease list --project PROJECT [--holder AUTHOR] [--status active|expired] [--limit N] [--offset N]

Enumerate a project's held leases — each row carries the task reference, holder, expires-at, and a derived active/expired status, so an operator can see who holds leases and which are stale to steal without walking every task.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --holder author - Only leases held by this author (the filter is --holder, not --author: --author is the global acting-author flag).
  • --status active|expired - Only leases with this derived status (active = expires-at in the future, expired = at/after it).
  • --limit n - Return at most N rows (unbounded when omitted).
  • --offset n - Skip the first N rows.

Examples:

lettuce lease list --project lettuce --format json
lettuce lease list --project lettuce --status expired --format plain
lettuce lease list --project lettuce --holder agent-1 --limit 20 --offset 0 --format json

Notes:

  • Project-scoped (requires --project), unlike the task-scoped lease acquire/renew/release/steal/show verbs. Rows are sorted by task reference ascending; status is derived from the operation clock. The lease record stores no acquired-at, so rows report expires-at + status rather than an acquired-at.
run start

Usage: lettuce run start REF [--force] [--reason TEXT] [--expect-revision N]

Start a task run.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, force, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --force - Explicit safety override for supported cases.
  • --reason text - Reason text.
  • --reason-file path - Read reason from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce run start lettuce/LET-1 --author agent-1 --format json
run finish

Usage: lettuce run finish REF RUN STATUS [--force --reason TEXT] [--expect-revision N]

Finish a task run.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, run_id, status, force, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --force - Explicit safety override for supported cases.
  • --reason text - Reason text.
  • --reason-file path - Read reason from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce run finish lettuce/LET-1 1 succeeded --author agent-1 --format json

Notes:

  • By default the run's agent or the holder of the task's active lease may finish it. --force finishes a run you neither started nor hold the lease for and REQUIRES --reason (or --reason-file): a forced finish overrides the lease holder, so an audit reason is mandatory (BUG-77).
run log add

Usage: lettuce run log add REF RUN --type TYPE --message MESSAGE [--details TEXT] [--details-file PATH] [--expect-revision N]

Add a run log entry. A run log is an APPEND-ONLY ledger of semantic notable entries, not raw stdout, so entries MAY be appended after the run reaches a terminal status (succeeded/failed/aborted) — a terminal run is NOT append-closed. That run finish is gated (FW-RUN-NOT-RUNNING) is not an inconsistency: finish writes the run's single authoritative OUTCOME and the gate stops a recorded result being overwritten, whereas this appends and overwrites nothing. A post-terminal entry is self-describing rather than ambiguous — every entry carries an at, and ended-at is required once status is not running, so an annotation is detectable as at >= ended-at (LET-399, spec section 14).

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, run_id, type, message, details, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --type type - Log entry type. Required.
  • --message text - Log message. Required.
  • --details text - Optional details.
  • --details-file path - Read details from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce run log add lettuce/LET-1 1 --author agent-1 --type progress --message 'Started.' --format json
lettuce run log add lettuce/LET-1 1 --author agent-1 --type progress --message 'Tests running.' --details 'go test ./...' --format json

Notes:

  • A terminal run stays APPENDABLE: this is a decided allowance (LET-399), not an unguarded path. Only run finish is gated, because it writes the outcome rather than appending to a ledger.
run summary add

Usage: lettuce run summary add REF RUN (--body TEXT|--body-file PATH) [--reason TEXT] [--expect-revision N]

Add a run summary version.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, run_id, body, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --body text - Summary body. Required.
  • --body-file path - Read summary body from file.
  • --reason text - Reason for summary.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce run summary add lettuce/LET-1 1 --author agent-1 --body 'Tests pass.' --format json
lettuce run summary add lettuce/LET-1 1 --author agent-1 --body 'Revised summary.' --reason 'Corrected results.' --format json

Notes:

  • Summaries are VERSIONED, so a later revision adds a new version and leaves earlier ones readable. A summary version MAY therefore be added after the run reaches a terminal status — a terminal run is not append-closed (LET-399, spec section 14).
run list

Usage: lettuce run list REF

List task runs.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce run list lettuce/LET-1 --format json
lettuce run list lettuce/LET-1 --format plain
run show

Usage: lettuce run show REF RUN [--full] [--with-logs] [--with-summaries]

Read one task run.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --full - Include every sub-object (logs and summaries).
  • --with-logs - Include the run's log entries.
  • --with-summaries - Include the run's summary versions.

Examples:

lettuce run show lettuce/LET-1 1 --format json
lettuce run show lettuce/LET-1 1 --with-logs --with-summaries --format json
run log list

Usage: lettuce run log list REF RUN [--with-body]

List a run's log entries.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-body - Include each entry's details body (hidden by default).

Examples:

lettuce run log list lettuce/LET-1 1 --format json
run log show

Usage: lettuce run log show REF RUN ENTRY [--with-body]

Read one run log entry.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-body - Include the entry's details body (hidden by default).

Examples:

lettuce run log show lettuce/LET-1 1 1 --with-body --format json
run summary list

Usage: lettuce run summary list REF RUN [--with-body]

List a run's summary versions.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-body - Include each version's summary body (hidden by default).

Examples:

lettuce run summary list lettuce/LET-1 1 --format json
run summary show

Usage: lettuce run summary show REF RUN VERSION [--with-body]

Read one run summary version.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-body - Include the summary body (hidden by default).

Examples:

lettuce run summary show lettuce/LET-1 1 1 --with-body --format json
artifact add

Usage: lettuce artifact add REF --type TYPE --primary-file PATH --file SRC:DEST

Create a task artifact.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, type, title, primary_file, from_run, files, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --type artifact-type - Artifact type. Required.
  • --title title - Artifact title.
  • --primary-file path - Primary artifact file path. Required.
  • --file source:dest - Payload descriptor. Required. Repeatable.
  • --from-run run-id - Associated run id.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce artifact add lettuce/LET-1 --author agent-1 --type test-report --primary-file report.md --file ./report.md:report.md --format json
artifact replace

Usage: lettuce artifact replace REF ARTIFACT --type TYPE --primary-file PATH --file SRC:DEST

Replace an artifact with a new artifact revision.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, artifact_id, type, title, primary_file, from_run, files, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --type artifact-type - Artifact type. Required.
  • --title title - Artifact title.
  • --primary-file path - Primary artifact file path. Required.
  • --file source:dest - Payload descriptor. Required. Repeatable.
  • --from-run run-id - Associated run id.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce artifact replace lettuce/LET-1 1 --author agent-1 --type test-report --primary-file report.md --file ./report.md:report.md --format json
artifact list

Usage: lettuce artifact list REF [--include-archived]

List task artifacts.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --include-archived - Include archived artifacts in the results (hidden by default).

Examples:

lettuce artifact list lettuce/LET-1 --format json
lettuce artifact list lettuce/LET-1 --include-archived --format json

Notes:

  • Archived artifacts are hidden by default, the same hidden-by-default contract task list and project list document. Archiving hides an artifact from this list view, not from query search.
artifact show

Usage: lettuce artifact show REF ARTIFACT

Read artifact metadata.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce artifact show lettuce/LET-1 1 --format json
lettuce artifact show lettuce/LET-1 1 --format plain
artifact archive

Usage: lettuce artifact archive REF ARTIFACT [--reason TEXT] [--expect-revision N]

Soft-archive a task artifact without deleting it. Reversible with lettuce artifact unarchive.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce artifact archive lettuce/LET-1 1 --author agent-1 --reason 'Stale.' --format json

Notes:

  • Reversible and history-preserving; use lettuce artifact delete for a hard removal.
artifact unarchive

Usage: lettuce artifact unarchive REF ARTIFACT [--reason TEXT] [--expect-revision N]

Restore a previously archived task artifact.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce artifact unarchive lettuce/LET-1 1 --author agent-1 --format json

Notes:

  • Only an archived artifact can be unarchived; the inverse of lettuce artifact archive.
artifact delete

Usage: lettuce artifact delete REF ARTIFACT (--yes|--force) [--reason TEXT] [--expect-revision N]

Hard-delete a task artifact. Non-reversible: requires --yes (or --force) to confirm.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --yes - Confirm the non-reversible deletion.
  • --force - Alias for --yes: confirm the non-reversible deletion.
  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce artifact delete lettuce/LET-1 1 --yes --author agent-1 --format json

Notes:

  • This is a hard, non-reversible removal; prefer lettuce artifact archive when you only want to hide the artifact.
artifact file get

Usage: lettuce artifact file get REF ARTIFACT PATH

Read an artifact payload file.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce artifact file get lettuce/LET-1 1 report.md --format json
lettuce artifact file get lettuce/LET-1 1 report.md --format plain
version add

Usage: lettuce version add REF CATEGORY NAME (--body TEXT|--body-file PATH) [--reason TEXT]

Create a task versioned document.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, category, name, body, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --body text - Document body. Required.
  • --body-file path - Read document body from file.
  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce version add lettuce/LET-1 plans implementation --author agent-1 --body 'Plan.' --format json
version list

Usage: lettuce version list REF [--category CATEGORY] [--name NAME]

List task versioned documents.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --category category - Filter by category.
  • --name name - Filter by name.

Examples:

lettuce version list lettuce/LET-1 --category plans --format json
lettuce version list lettuce/LET-1 --category plans --name implementation --format json
version show

Usage: lettuce version show REF CATEGORY NAME VERSION [--with-body]

Read one versioned document.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --with-body - Include body content.

Examples:

lettuce version show lettuce/LET-1 plans implementation 1 --with-body --format json
lettuce version show lettuce/LET-1 plans implementation 1 --format plain

Links to

Tasks — Commands

↑ top

reference/cmd-tasks

lettuce Tasks commands — 19 entries — task create, task show, task list, task exists, task set, task set-where, task unset, task set-list, task transition, task clone, task reopen, task archive, task unarchive, task delete, task body add, task audit, task graph, custom set, custom clear.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Tasks — Commands

lettuce command group Tasks — 19 commands. Generated from lettuce usage --format okf (always in sync with the binary).

Back to Command Reference.

Commands in this group
  • task create
  • task show
  • task list
  • task exists
  • task set
  • task set-where
  • task unset
  • task set-list
  • task transition
  • task clone
  • task reopen
  • task archive
  • task unarchive
  • task delete
  • task body add
  • task audit
  • task graph
  • custom set
  • custom clear

---

Create, inspect, mutate, transition, audit, and graph tasks.

task create

Usage: lettuce task create (TASK-ID | --next PREFIX) --title TITLE [--body TEXT|--body-file PATH] [task flags]

Create a task and initial body.

  • kind: mutation
  • requires root: true
  • requires project: true
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_id, title, body, workflow, status, priority, type, severity, assignee, reporter, component, milestone, estimate, due_at, parent, label, depends_on, blocks, watcher
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --next prefix - Allocate the task id as PREFIX-N instead of naming one, where N is one past the highest existing number in that series. Mutually exclusive with the positional TASK-ID; supplying both is refused rather than silently preferring one. Closes the read-to-write window in which two agents reading the same maximum pick the same id.
  • --title title - Task title. Required.
  • --body text - Initial body text.
  • --body-file path - Read initial body from file.
  • --workflow workflow - Workflow slug.
  • --status state - Initial workflow state.
  • --priority 0..100 - Task priority.
  • --type task-type - Task type.
  • --severity severity - Severity slug.
  • --assignee author - Assignee author.
  • --reporter author - Reporter author.
  • --component component - Component slug.
  • --milestone milestone - Open or active milestone slug.
  • --estimate estimate - Estimate scalar.
  • --due-at timestamp - Due timestamp.
  • --parent task-ref - Same-project parent task.
  • --label slug - Label to attach. Repeatable.
  • --depends-on task-ref - Task this task depends on. Repeatable.
  • --blocks task-ref - Task this task blocks. Repeatable.
  • --watcher author - Watcher to add. Repeatable.
  • --custom key=value - Set a custom field value; active required custom fields must be supplied. Repeatable.

Examples:

lettuce task create LET-1 --project lettuce --author agent-1 --title 'First task' --body 'Do the work.' --format json
task show

Usage: lettuce task show REF [--full] [--with-body] [--body-version V] [--body-versions] [--with-comments] [--with-runs] [--with-artifacts] [--with-events]

Read one task.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --full - Include the body and every sub-object (comments, runs, artifacts, events).
  • --with-body - Include task body content.
  • --body-version v - Read a SPECIFIC historical body version instead of the latest (requires --with-body). The value is a version SLOT as stored, not an ordinal: only the create-time body occupies the numbered slot 1; every task body add writes a content-addressed bod_<hash>. Naming a slot that does not exist is refused with the slots that DO, and --body-versions lists them. Local stores only — over --server-url it is refused rather than silently returning the latest, because handing back the current version when a historical one was asked for is the worst possible answer.
  • --body-versions - List the task body-version history — each slot with the author and timestamp of that VERSION (not of the task). This is the command the --body-version refusal names; LET-159 shipped the refusal naming it before the flag existed, so following the guidance used to land in FW-CMD-UNKNOWN-FLAG. Same ordering as the refusal listing, so the two cannot disagree. Local stores only.
  • --with-comments - Include task comments, METADATA ONLY — comment bodies are not included, because they are unbounded and a task can carry many. A warning (FW-READ-COMMENT-BODIES-OMITTED) announces the omission whenever at least one comment is projected. Use --full for every body, or comment show REF ID --with-body for one.
  • --with-runs - Include task runs.
  • --with-artifacts - Include task artifacts.
  • --with-events - Include task-affecting events.

Examples:

lettuce task show lettuce/LET-1 --with-body --format json
lettuce task show lettuce/LET-1 --full --format json
task list

Usage: lettuce task list [filters] [--refs-only] [--include-archived] [--limit N] [--offset N]

List tasks in a project, filtered by the required Section 20.4 task-list flags.

  • kind: read
  • requires root: true
  • requires project: true
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --status status - Filter by workflow status.
  • --workflow workflow - Filter by workflow reference.
  • --assignee author - Filter by assignee.
  • --reporter author - Filter by reporter.
  • --label slug - Filter by label. Repeatable.
  • --component slug - Filter by component.
  • --milestone slug - Filter by milestone.
  • --type slug - Filter by task type.
  • --severity slug - Filter by severity.
  • --priority-min n - Minimum priority, inclusive.
  • --priority-max n - Maximum priority, inclusive.
  • --due-before timestamp - Due at or before this timestamp.
  • --due-after timestamp - Due at or after this timestamp.
  • --updated-before timestamp - Updated at or before this timestamp.
  • --updated-after timestamp - Updated at or after this timestamp.
  • --parent task-ref - Filter by parent task reference.
  • --watcher author - Filter by watcher. Repeatable.
  • --text text - Filter by free-text match.
  • --custom key=value - Filter by a custom-field value (repeatable; AND across keys). Repeatable.
  • --refs-only - Return task references only.
  • --limit n - Maximum tasks.
  • --offset n - Task offset.
  • --include-archived - Include archived tasks in the results (hidden by default).

Examples:

lettuce task list --project lettuce --status ready --format json
lettuce task list --project lettuce --assignee jota --label backend --format plain
lettuce task list --project lettuce --limit 20 --offset 0 --format json
task exists

Usage: lettuce task exists REF

Exit successfully when a task reference exists.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce task exists lettuce/LET-1 --format json
lettuce task exists lettuce/LET-1 --format plain
task set

Usage: lettuce task set REF FIELD VALUE [--expect-revision N]

Set a mutable scalar task field (title, priority, severity, type, assignee, reporter, component, milestone, estimate, due-at, parent, workflow). Status is NOT settable here — use task transition. Reassigning workflow carries two conditions: the task's CURRENT status must exist in the target workflow (spec §23.10), and the target may not DROP a requirement the current workflow enforces on a shared outgoing action — moving a task gated on custom/grc into an ungated workflow would otherwise let it close with no evidence. Neither field can be cleared: title and workflow are required.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, field, value, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected current revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task set lettuce/LET-1 priority 50 --author agent-1 --expect-revision 1 --format json
lettuce task set lettuce/LET-1 workflow hardened --author agent-1 --format json

Notes:

  • A workflow reassignment refused with FW-TASK-WORKFLOW-GATE-WEAKENED names every requirement the target would lose; FW-TASK-WORKFLOW-STATUS-ABSENT lists the states the target does have.
task set-where

Usage: lettuce task set-where --where '<fql>' FIELD VALUE [--confirm] [--dry-run] [--include-archived]

Bulk-set a mutable scalar field on every task matching an FQL where-filter. Requires --confirm to mutate more than one task; --dry-run previews the matched refs without writing.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false
  • external input keys (these go INSIDE data, not at the top level): where, field, value, confirm, dry_run
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --where fql - FQL where-clause selecting the tasks to mutate (same syntax as query tasks/task list --where). Required.
  • --confirm - Confirm applying the change to all matched tasks (required for more than one match).
  • --dry-run - List the matched tasks and intended change without writing.
  • --include-archived - Also mutate soft-archived tasks matching the filter (excluded by default so a retired, list-hidden task is never silently bulk-mutated).

Examples:

lettuce task set-where --where 'status = "open"' priority 50 --confirm --author agent-1 --format json
lettuce task set-where --where 'component = "api"' milestone release-1 --dry-run --author agent-1 --format json

Notes:

  • Soft-archived tasks are EXCLUDED from the where-filter match by default: a task you archived to retire it is not silently bulk-mutated. Pass --include-archived to consciously mutate archived tasks too.
task unset

Usage: lettuce task unset REF FIELD [--expect-revision N]

Clear an optional scalar task field.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, field, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected current revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task unset lettuce/LET-1 priority --author agent-1 --format json
task set-list

Usage: lettuce task set-list REF FIELD --value VALUE [--value VALUE...] [--expect-revision N]

Replace a mutable task list field.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, field, values, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --value value - List value. Required. Repeatable.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task set-list lettuce/LET-1 labels --value backend --value api --author agent-1 --format json

Notes:

  • The referenced custom field, label, or component must first be created with lettuce registry create.
task transition

Usage: lettuce task transition REF ACTION [--reason TEXT] [--facilitate] [--expect-revision N]

Apply a workflow transition. Every requires-* gate the transition declares is checked first, and a gate whose value is a REFERENCE is satisfied only by a reference that still resolves — an archived task, an inactive label, or a custom field whose declared value-kind names something missing does not count. Refusals distinguish the reason so a client can branch on the code: FW-WF-REQUIREMENT-UNSATISFIED (the bar is not met at all), FW-WF-REQUIREMENT-REFERENT-MISSING (the cited object does not exist or was withdrawn), FW-WF-REQUIREMENT-REFERENT-UNLINKED (the cited object exists but recorded no link back to this task — the graph-run-case case), FW-WF-REQUIREMENT-REFERENT-INCOMPLETE (the cited run-case exists and is linked, and never produced the carriers its own graph-def declares — linkage is one edge, a graph is a walk).

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, action, reason, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --reason text - Reason text.
  • --reason-file path - Read reason from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.
  • --facilitate - Record-not-enforce an unsatisfied requires-* gate (LET-1560): proceed with the transition even though a requirement is not met, recording the unsatisfied requirement AND the mandatory --reason on the transition event as a facilitated annotation — the task-level twin of cell transition --facilitate. The default is refusal (FW-WF-REQUIREMENT-UNSATISFIED); --facilitate REQUIRES --reason (the exception's rationale), records rather than bypasses (a reader of task state encounters it), never touches the lease gate, and is inert when the gate already passes.

Examples:

lettuce task transition lettuce/LET-1 start-work --author agent-1 --reason 'Ready.' --format json
lettuce task transition lettuce/LET-966 complete --facilitate --reason 'closing on a documented exception; grc gate unsatisfiable, see LET-1560' --author agent-1 --format json

Notes:

  • start-work and other lease-gated actions require an active lease; acquire one with lettuce lease acquire first.
  • --facilitate (LET-1560) is record-not-enforce, not a bypass: it proceeds past an unsatisfied requires-* gate while writing the unsatisfied requirement and the mandatory --reason onto the transition event, so the exception is a ledger fact. It REQUIRES --reason, never relaxes the gate for a non-facilitate transition, and never bypasses the lease gate.
  • A requires-field gate over a custom field of value-kind graph-run-case demands THREE things: that the run-case exists, that it recorded a produced-effect on this task (the reverse of graph-run-case refs-to), and that it produced a carrier for every edge its own graph-def declares one on. WHAT IT DOES NOT COVER (LET-1449): the gate checks that a carrier EXISTS on each declared edge and never reads its VALUE, so --value "." satisfies it exactly as well as a real verdict, and it cannot tell whether the verifier did any work. Presence is not quality; a green gate proves evidence was recorded, not that it is any good. The demand is read from the def, so a def declaring no carriers is asked for none, and a run-case whose def or pin cannot be resolved is left unjudged rather than refused. Full conformance of the walk is still graph-run-case conform.
task clone

Usage: lettuce task clone REF NEW-ID

Duplicate a task's authored content (title, body, scalar + list + custom fields) into a fresh task.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Examples:

lettuce task clone lettuce/LET-1 LET-2 --author agent-1 --format json

Notes:

  • The clone resets id, status (to the workflow's initial state), revision, and timestamps; it does NOT copy runs, comments, artifacts, the lease, or the event history.
task reopen

Usage: lettuce task reopen REF [--reason TEXT] [--expect-revision N]

Move a terminal task (done/failed/canceled) back to its workflow's initial state.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --reason-file path - Read reason from file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task reopen lettuce/LET-1 --author agent-1 --reason 'Regression found.' --format json

Notes:

  • Only a terminal task can be reopened; a non-terminal task returns FW-TASK-NOT-TERMINAL. Records a transition-applied event so the audit trail matches a normal transition.
task archive

Usage: lettuce task archive REF [--reason TEXT] [--expect-revision N]

Soft-archive a task: hide it from default listings without deleting history. Reversible with lettuce task unarchive.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task archive lettuce/LET-1 --author agent-1 --reason 'Superseded.' --format json

Notes:

  • Archived tasks are hidden from task list unless --include-archived is passed. This is reversible and preserves the full event history; use lettuce task delete for a hard, non-reversible removal.
task unarchive

Usage: lettuce task unarchive REF [--reason TEXT] [--expect-revision N]

Restore a previously archived task back to normal (unarchived) visibility.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task unarchive lettuce/LET-1 --author agent-1 --format json

Notes:

  • Only an archived task can be unarchived; the inverse of lettuce task archive.
task delete

Usage: lettuce task delete REF (--yes|--force) [--cascade] [--reason TEXT] [--expect-revision N]

Hard-delete a task and its sub-objects. Non-reversible: requires --yes (or --force) to confirm. A task with child tasks needs --cascade.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: false

Flags:

  • --yes - Confirm the non-reversible deletion.
  • --force - Alias for --yes: confirm the non-reversible deletion.
  • --cascade - Also delete child tasks; without it a task with children is refused rather than orphaning them.
  • --reason text - Reason text.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task delete lettuce/LET-1 --yes --author agent-1 --format json

Notes:

  • This is a hard, non-reversible removal recorded in the operation ledger; prefer lettuce task archive when you only want to hide the task. --cascade also deletes child tasks; without it a task that has children returns an error rather than orphaning them.
task body add

Usage: lettuce task body add REF (--body TEXT|--body-file PATH) [--expect-revision N]

Add a new task body version.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, body, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --body text - Body text. Required.
  • --body-file path - Read body text from a file.
  • --expect-revision n - Expected task revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce task body add lettuce/LET-1 --author agent-1 --body 'Updated body.' --format json
task audit

Usage: lettuce task audit REF

Read task event history.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Examples:

lettuce task audit lettuce/LET-1 --format json
lettuce task audit lettuce/LET-1 --format plain
task graph

Usage: lettuce task graph REF [--relation REL] [--depth N] [--include-archived]

Traverse task relations.

  • kind: read
  • requires root: true
  • requires project: false
  • requires author: false
  • stable snapshot: true
  • idempotency key: false

Flags:

  • --relation depends-on|blocks|parent|children - Relation to traverse.
  • --depth n - Traversal depth (default 1). A traversal capped by --depth sets truncated:true and marks each boundary node has_more, so an incomplete closure is never silently returned — raise --depth to see the rest.
  • --include-archived - Include soft-archived tasks in the traversal (default: hidden, consistent with query run / task list); an included archived node is marked archived.

Examples:

lettuce task graph lettuce/LET-1 --relation depends-on --depth 2 --format json
lettuce task graph lettuce/LET-1 --relation blocks --depth 1 --format json
custom set

Usage: lettuce custom set REF FIELD VALUE [--expect-revision N]

Set a task custom field value. The value is validated against the field's declared value-kind, and the REFERENCE kinds (author, label, task, graph-run-case) must resolve to something that exists — a value naming a missing author/label/task/run-case is refused FW-REF-MISSING-* rather than stored. A graph-run-case value must name an existing run-case; the additional requirement that the run-case recorded an effect on THIS task is enforced where the claim is cashed in — the workflow requires-field gate on task transition.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, field, value, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected current revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce custom set lettuce/LET-1 customer acme --author agent-1 --format json
lettuce custom set lettuce/LET-1 grc grc_9f3a1c2b --project lettuce --author agent-1 --format json

Notes:

  • The referenced custom field, label, or component must first be created with lettuce registry create.
custom clear

Usage: lettuce custom clear REF FIELD [--expect-revision N]

Clear an optional task custom field value.

  • kind: mutation
  • requires root: true
  • requires project: false
  • requires author: true
  • stable snapshot: false
  • idempotency key: true
  • external input keys (these go INSIDE data, not at the top level): task_ref, field, expected_revision
  • external input envelope: {"schema_version":"v0.16","kind":"lettuce-command-input","data":{ ...command fields... }}

Flags:

  • --expect-revision n - Expected current revision. Compared against the store THIS COMMAND READS — fetched shared state in dedicated-git mode, the LOCAL tree in filesystem mode, where a concurrent write by another agent is invisible. See lettuce usage Agent Guidance for what that does not catch.

Examples:

lettuce custom clear lettuce/LET-1 customer --author agent-1 --format json

Notes:

  • The referenced custom field, label, or component must first be created with lettuce registry create.

Links to

Command Reference

↑ top

reference/command-reference

Exhaustive lettuce CLI reference — 184 commands across 13 groups, generated from the binary.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Command Reference

The complete lettuce command-line surface — 184 commands across 13 groups. Generated by lettuce usage --format okf, so it never drifts from the binary.

Command groups

Links to

+1 more

reference/index

↑ top

reference/index reserved

No description.

<!-- GENERATED by 'lettuce usage --format okf' — DO NOT EDIT. Run: make docs -->

Links to

+2 more

Why lettuce (and not just Markdown + a convention)

↑ top

why-lettuce

lettuce moves the guarantee from instruction-following to code — validated transitions, atomic leases, and evidence-gated coverage cells the binary refuses to fake.

Why lettuce (and not just Markdown + a convention)

A Markdown board in your repo is only as honest as the agent editing it. An agent can write done or hardened with nothing behind it, and the next reader believes it. lettuce moves the guarantee from instruction-following to code.

  • State transitions are validated, not requested. A task moves between states only along declared, legal transitions; an illegal move is refused, not recorded.
  • Leases are atomic, expiring, and audited — not a naming convention. Two agents cannot both believe they hold the same work.
  • A coverage cell cannot reach hardened — or earn hardening depthwithout linked evidence. The tool refuses the write.

The store is still ordinary text: greppable, diffable, exportable. But what that text claims is enforced by the binary, not by the goodwill of whoever wrote it. That is the whole point — determinism over "please follow the convention."

If a rule in CLAUDE.md reliably did the job, you would not need lettuce. You reach for lettuce when verified must mean proven, not merely asserted.

Consequence for autonomous agents

Because claims are enforced, an autonomous loop can trust the store as its orientation and evidence substrate: it can ask "what is unfinished and provable?" and act on the answer without a human re-checking every assertion. See the core agent loop and Command Reference.

Links to

Broken links (0)

No broken internal links.

↑ Top