---
name: lettuce
description: Use lettuce, the hosted work tracker and coverage store, correctly from the CLI. Quickstart only — bootstrap, orient, claim, work, close. Everything else is in the reference tier.
---

# Using lettuce — quickstart

`lettuce` is a hosted, agent-first work tracker and coverage/quality store: a CLI that
talks to a server over HTTP. This page is the <=10KB QUICKSTART (LET-2012): bootstrap →
orient → claim → work → close, nothing else. For everything else (migration, dedicated-git
mode, the full command map, FQL, the coverage model, graph authoring, output formats,
modes, invariants) read the REFERENCE tier: `docs/guides/SKILL-REFERENCE.md`, or run
`lettuce skill reference`. The binary always wins over this prose: `lettuce usage <cmd>`.

**Drive the store through the binary only** — never read or write its files directly.

## 0. Bootstrap

**No server? Use a local store** (skip §0.1-0.2; locally your name is `LETTUCE_AUTHOR`):

```sh
export LETTUCE_ROOT=$PWD/.lettuce-local LETTUCE_AUTHOR=<your-name> LETTUCE_PROJECT=<projectname>
lettuce init --author <your-name> --bootstrap-project <projectname> --bootstrap-author
lettuce orient
```

### 0.1 Pin your binary to the server's release

A mismatched client may speak an older/newer wire contract; the server tells you its
release at `/v1/version` and on every response's `X-Lettuce-Server-Version` header (your
own version rides `X-Lettuce-Client-Version` on every request). A mismatch is the
non-fatal warning `FW-CLIENT-VERSION-SKEW` — stop writing, run `lettuce self-update`, then
re-check `lettuce status`.

No binary yet:

```bash
V=$(curl -fsS -H @<(printf 'Authorization: Bearer %s\n' "$LETTUCE_BEARER") https://api.lettuce.huru.ca/v1/version | jq -r .data.version)
OS=$(uname -s | tr '[:upper:]' '[:lower:]'); ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -fsS -H @<(printf 'Authorization: Bearer %s\n' "$LETTUCE_BEARER") -o "lettuce-$OS-$ARCH" "https://api.lettuce.huru.ca/v1/client/$OS-$ARCH"
curl -fsS -H @<(printf 'Authorization: Bearer %s\n' "$LETTUCE_BEARER") -o "lettuce-$OS-$ARCH.sha256" "https://api.lettuce.huru.ca/v1/client/$OS-$ARCH.sha256"
# fallback (FW-CLIENT-BINARY-UNAVAILABLE), needs GitHub read access:
# gh release download "$V" -R huru-io/lettuce -p "lettuce-$OS-$ARCH*"
sha256sum --check "lettuce-$OS-$ARCH.sha256"   # macOS: shasum -a 256 --check …
chmod +x "lettuce-$OS-$ARCH" && mv "lettuce-$OS-$ARCH" ~/.local/bin/lettuce
lettuce version   # must print "$V"
```

Already have `lettuce`? Just run `lettuce self-update` — it reads your server binding,
matches the server's release, verifies the sha256, and replaces itself atomically. Full
detail (fallbacks, version-floor refusals, old-client handling): reference §0.1.

### 0.2 Connect, and say who you are

`.lettuce` at the repo root (a credential-free FILE naming the server, `project:`, and
`domain:`) decides the store; set it up once per repo, or pass `--store
https://<token>@host/` / `--server-url` + `--project` one-off. Effective domain:
`--domain` → `LETTUCE_DOMAIN` → the pointer's `domain:` line → your token's default
domain. Effective project: `--project` → `LETTUCE_PROJECT` → the pointer's binding. An
explicit `--project` or `LETTUCE_PROJECT` that differs from the binding still runs but
prints a warning. Credentials: `export LETTUCE_BEARER_FILE=<0600 file>` (never in the
pointer or on a command line). In Wordmade-ID mode, use `--auth-mode wordmade-id` with
`--organization`/`--organization-token-file` and send no `--author` at all — the server
resolves attribution from verified context, and a present actor header is refused.

Otherwise (shared-bearer mode) **declare your own stable `--author <name>`** — never a
shared or borrowed name — then register and link it once:

```sh
export LETTUCE_BEARER_FILE=~/.config/lettuce/token LETTUCE_ACTOR=<your-name>
lettuce status                                                     # server, release, domain, project — and their sources
lettuce author add <your-name> --idempotent                        # root-scoped
lettuce project author add <projectname> <your-name> --idempotent --author <your-name>
```

A server with `--auto-provision-actors` on does both for you: a refusal on this path then
says "just perform the first write as --author <name>" — do that instead of the two
commands above. Every other refusal here names its own next step by diagnostic code
(`FW-CMD-MISSING-AUTHOR`, `FW-API-AUTHZ-DENIED`); follow it.

**Confirm before writing:** `lettuce status --format json` (`data.connection`: server,
release, domain, project, their sources; no `FW-CLIENT-VERSION-SKEW` warning).

## What lettuce is for — the features

Tickets are the core loop below; the rest is what makes lettuce more than a ticket list.
`lettuce skill features` prints each feature's what/when/why and its minimal loop;
`lettuce skill features <id>` prints one.

<!-- feature-map: generated from internal/cli/feature_map.go; UPDATE_GOLDEN=1 rewrites it -->
| Feature | Reach for it when | Start with |
|---|---|---|
| Tickets and the leased lifecycle (`tickets`) | Any piece of work worth tracking: pick it up, record progress, close it with evidence. | `lettuce task create --next <PREFIX> --title "<title>" --project <project>` |
| Workflows and gates (`workflows`) | Before a transition you have not made before (read the task's next_actions), or when a project needs a rule such as 'no close without a verification record'. | `lettuce task show <project>/<TASK>` |
| Coverage: dimensions, cells and the definition of done (`coverage`) | To answer 'how proven is this part of the product?' and to choose what to harden next. | `lettuce dimension list --project <project>` |
| Graph-defs, run-cases and close-walks (`graphs`) | When a process must be provably followed, such as three independent verifiers before a ticket closes. `close-walk` installs the shipped `ticket-claim-verify` if the project has none, and also closes an archived project's tickets. | `lettuce graph-def list --project <project>` |
| Orientation: orient, work and board next (`orientation`) | At the start of every session and whenever you finish something. | `lettuce orient --project <project>` |
| Queries and search (`queries`) | When a list command's filters are not enough, or to find earlier work on a topic. | `lettuce query run 'from tasks where status = ready select task,title' --project <project>` |
| Stores, identity and hosted mode (`hosted`) | Once per repo and per agent: connect, confirm where you are, register your name. | `lettuce status` |
| Health: doctor first, then recover (`health`) | When anything looks wrong: a refusal you do not understand, a stuck lock, a store that will not validate. | `lettuce doctor` |
| Messaging between agents (`messaging`) | To ask or tell a peer something that belongs to no single task. | `lettuce message inbox --project <project>` |
<!-- /feature-map -->

## 1. Orient — find work

`lettuce orient` is one screen: connection, work's next steps, the board headline.

```sh
lettuce project list --format json                           # which project(s) may I use?
lettuce task list --project <projectname> --format json       # concrete open items
lettuce board next --project <projectname> --format json      # higher-order: weakest-first work map
```

`lettuce work` ends with NEXT: the commands to run now, derived from the project's state
(an available task to lease, an expired lease to take over, an empty project to fill).

`board next` (and `query search`) is an O(project) build the server runs in the
background; it answers fast with the current board, or the last board marked STALE while
a fresh one builds, or (new project, no board yet) `FW-API-READ-PENDING` — the client
waits by default (`--wait`, default 3m) and exits 8 if still not ready: rerun in a minute.

## 2. Claim it

```sh
lettuce lease acquire "<project>/<TASK>" --author <you> --for 1h --format json
# or, if your server needs an absolute timestamp instead of a duration:
lettuce lease acquire "<project>/<TASK>" --author <you> --format json \
  --expires-at "$(date -u -d '+1 hour' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v+1H +%Y-%m-%dT%H:%M:%SZ)"
lettuce task transition "<project>/<TASK>" start-work --author <you> --format json
```

Keep the lease SHORT and renew rather than taking one long window — a lease that never
ends is a lock whose only remedy is a forced steal. `start-work` (and other lease-gated
actions) refuse `FW-WF-REQUIREMENT-UNSATISFIED` without an active lease.

## 3. Work

Record progress as you go — `comment add` is the one command every agent needs:

```sh
lettuce comment add "<project>/<TASK>" --body "What you found / did." --author <you> --format json
```

(`run`/`artifact`/`version` are a separate, OPTIONAL structured execution-log domain —
not part of the core loop, not deprecated. Reference §5/§6 if your project uses them.)

**If something looks wrong, run `lettuce doctor --format json` first** and follow its
`suggested_actions` — it is the one health front door; do not reach for `validate`,
`recover`, `repair`, `reconcile`, or `cleanup` on your own initiative (reference §13).

## 4. Close

```sh
lettuce task transition "<project>/<TASK>" complete --reason "Done + verified" --author <you> --format json
```

`complete` ends your lease. If you stop WITHOUT closing, hand the task back:
`lettuce lease release "<project>/<TASK>" --author <you>`. Leases expire by
themselves (1h); keep one with `lease renew <ref> --for 1h` (reference §0.4).

## Flags and docs you'll use

Global: `--store`, `--server-url`, `--bearer` (or `LETTUCE_BEARER_FILE`), `--domain`, `--project`,
`--author` (shared-bearer mode; Wordmade-ID mode: §0.2). `--idempotency-key` makes a retry safe —
see reference for its exact per-working-copy scope.

`lettuce usage` is the exhaustive, always-current flag reference; `lettuce usage <cmd>`
for one command. `lettuce skill reference` is everything else (see the top of this page).
Diagnostics are the API: every error carries `code`, `expected`/`actual`,
`repairability`, and `suggested_actions` — branch on the code, not the message text.
