Use Weave
Decisions & history
Decision records, the operation log, timeline, blame and symbol history, revert and undo, tags and attestations.
Every change in Weave carries what it was for and why. History only moves forward: revert and undo add new entries, nothing is rewritten.
Decision records#
A decision record says why code is the way it is: a title (≤ 80 characters), the why (≤ 240), rejected alternatives and constraints, anchored to symbols. Records are files, .weave/decisions/D-xxxx.toml, that travel draft → stitch → weaved with the code, so they are owned, promoted, inherited and reverted like the code they explain. Agents need .weave/decisions/** in their pathScope to stitch them.
Record decisions#
# at stitch time: -w drafts a record anchored to the symbols you changed (confirm it, or -y)
weave stitch -i "Keep bcrypt" -w "login p99 budget is 250ms" -y
# directly
weave decision add -t "Keep bcrypt cost at 12" -w "login p99 budget is 250ms" \
--on src/auth.rs::hash_password --alt "argon2id" --constraint "p99 login < 250ms" --comment
--comment puts a one-line why: … [D-xxxx] comment above each anchor. That tag is the strongest anchor: the record follows it through moves and renames. WEAVE_DECISION_YES=1 records drafted decisions without asking.
Read decisions (within a token budget)#
weave decision for src/auth.rs::login # one short line per decision on it and its neighbours
weave decision for src/auth.rs::login --format constraints
weave decision search "password hashing" --near src/auth.rs::login
weave decision impact src/auth.rs::login --depth 2 # callers and callees with their decision counts
weave decision show D-7f3a
weave decision list --all # or --status active|needs_review|superseded|stale|retired
--format constraints prints rules for an agent's starter pack, best decision first:
KEEP: Keep bcrypt cost at 12 — login p99 budget is 250ms [D-7f3a]
KEEP: p99 login < 250ms [D-7f3a]
NEVER: argon2id [D-7f3a]
Keep decisions current#
When an anchored symbol changes, its decisions become needs_review; when every anchor is lost, stale.
weave decision review # follow moved / renamed anchors, mark drift, list the queue (--dry-run)
weave decision review D-7f3a --accept # it still holds
weave decision supersede D-7f3a -t "Use argon2id" -w "new hardware budget"
weave decision retire D-7f3a --reason "auth moved to the identity service"
weave enrich can find unconfirmed why-candidates with an LLM (your key, on your machine); weave decision review --candidates lists them and weave decision confirm <n> turns one into a decision.
MCP: decisions_for, decision_search, decision_get, impact, decision_propose, decision_review. Server API: GET|POST /api/weave/{repoId}/decisions, GET …/decisions/{id}, POST …/decisions/{id}/supersede, POST …/decisions/{id}/retire, POST …/decisions/review (see API reference). Server writes are stitches too, so a write to a record someone else owns becomes a suggestion.
Threads#
Threads are the lighter companion: short behaviour notes per symbol, written directly to sidecars under .weave/threads/ without drafts or stitches.
weave thread add src/auth.rs::login "token refresh is lazy"
weave thread show login --depth 1
weave thread search "refresh"
weave index && weave thread heal # after renames
Timeline and the operation log#
weave timeline # weaved stitches of the active workstream, newest first
weave timeline main --limit 20 # author, agent, intent, why, promoted / inherited / revert
weave log # the operation log: every action, newest first (default 30)
weave log --actor alice --workstream main --limit 50
weave log --by-agent builder-1
weave log --symbol src/auth.rs::login # everything that touched a symbol
weave log --verify # check the log's hash chain first
The operation log records every action — claims, releases, lease expiries, stitches, weaves, rejections, suggestions, change requests, promotions, reverts, undos, workstream removals, tags, attestations, purges — with the person and agent. It is append-only and hash-chained: each entry's id is the BLAKE3 hash of its content and the previous entry's id. In the web UI it is the repository's Log tab, with filters for person, agent, workstream and symbol.
Blame and symbol history#
Which weave last changed each symbol of a file (server API, read access):
curl -s "https://api.weave.directory/api/weave/$REPO_ID/workstreams/main/blame?path=src/auth.rs" \
-H "Authorization: Bearer $WEAVE_TOKEN"
{ "type": "blame", "workstream": "main", "path": "src/auth.rs", "head": "…", "total": 3, "next_offset": null,
"items": [{ "symbol": "src/auth.rs::login", "kind": "function", "changeset": "…", "label": "stitch",
"author": "alice", "agent": null, "at": "…", "intent": "MFA login", "why": "SOC2", "entry_id": "…" }] }
- Paged with
offsetandlimit(default 200, max 1000). A symbol unchanged since its workstream was created is attributed in the parent. GET …/workstreams/{ws}/symbol-history?symbol=src/auth.rs::loginlists every weave that changed one symbol.GET …/workstreams/{ws}/historypages weaved stitches newest first (before,limit≤ 500) and filters bykind,agent,author,sourceandsymbol. Items carryreverted_by/revertslinks.GET /api/weave/{repoId}/diff?from=<head|workstream>&to=<head|workstream>&level=file|symbol&path=diffs two heads, by file or by symbol.
Revert and undo#
weave revert 9c1e --why "broke MFA on mobile" # a new stitch with the inverse operations
weave undo # reverse your own most recent action
weave undo <log entry id prefix> # or a chosen entry of yours
- Revert takes back a weaved stitch with a new stitch. Symbols unchanged since are reverted; a symbol changed again since is not overwritten but becomes a change request.
--whyis required. - Undo reverses your own action: a weaved stitch is reverted, a claim released, a suggestion withdrawn, a rejection reopened, a settings change restored, a removed workstream restored. Someone else's action is taken back with a revert or a suggestion instead. Undo is logged and never deletes entries.
- Several stitches as one revert, all or nothing (server API):
POST /api/weave/{repoId}/workstreams/{ws}/revertwith{"changesets": ["<id>", "<id>"], "why": "…"}. If a later weave changed one of the symbols, it answers409 revert_conflictwith theblockingsymbols and nothing is weaved. - Restore paths or symbols to an older head as a new stitch:
POST /api/weave/{repoId}/restorewith{"workstream", "head", "paths"?, "symbols"?, "intent"?, "why"?}. - Web UI: Weaved → Revert on a stitch; Log → undo on your own entries.
Tags#
Tags are immutable names for heads (server API):
curl -s https://api.weave.directory/api/weave/$REPO_ID/tags \
-H "Authorization: Bearer $WEAVE_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "v1.2.0", "workstream": "main", "message": "spring release"}'
workstreamalone tags its current head; or passhead(a state of the repository). Write access.- Names: letters, digits,
.,_,-,/, ≤ 128 characters, no leading-./, no trailing/, no..or//. - The same name for the same head answers
200 created: false; for another head,409. GET …/tags[?head=]lists them newest first;GET …/tags/{name}(encode/as%2F);DELETE …/tags/{name}?why=(repository admin).- Tags aren't accepted as refs by
diff,archiveorrestoreyet: pass the tag'shead.
Attestations#
An attestation is a signed statement about one exact head — tests passed, security reviewed, approved — that a protected workstream can require before a promotion.
-
Register a key (Ed25519). Repository keys:
POST /api/weave/{repoId}/attestation-keys{"publicKey": "<base64 of the raw 32-byte key>", "label"?, "types"?: ["approval"]}(repository admin). Organization keys, trusted in every repository of the org:POST https://weave.directory/api/v1/orgs/{slug}/attestation-keys(scopeorg:admin). A key's id iswak_+ the first 32 hex of sha256(raw public key). -
Sign this text (UTF-8,
\nbetween lines, no trailing newline):textweave-attestation/v1 repo:<repo id> head:<head, 64 lowercase hex> type:<type> payload-sha256:<lowercase hex sha256 of the canonical payload bytes>A string payload is its UTF-8 text as is. Any other JSON is compact, with object keys sorted, recursively.
jsimport crypto from "node:crypto"; const canonical = (v) => typeof v === "string" ? v : Array.isArray(v) ? `[${v.map(canonical).join(",")}]` : v && typeof v === "object" ? `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${canonical(v[k])}`).join(",")}}` : JSON.stringify(v); function attest(privateKey, repo, head, type, payload) { const text = typeof payload === "string" ? payload : canonical(payload); const digest = crypto.createHash("sha256").update(text, "utf8").digest("hex"); const msg = `weave-attestation/v1\nrepo:${repo}\nhead:${head}\ntype:${type}\npayload-sha256:${digest}`; return crypto.sign(null, Buffer.from(msg, "utf8"), privateKey).toString("base64"); } -
Post it:
POST /api/weave/{repoId}/heads/{head}/attestations{"type", "payload", "signature", "keyId"}(write access; any principal).headmust be a 64-hex state id, so you attest exactly what was checked. The signature is verified on the way in. -
Read them:
GET …/heads/{head}/attestations(a workstream name works here). Anyone can fetch a public key without a token:GET /api/weave/attestation-keys/{keyId}.
A revoked key verifies no attestation recorded after its revocation; ones it signed before stay valid.
Verified audit trail#
The server verifies every repository's hash-chained log every hour and writes checkpoints to write-once storage, chained to each other. Read the latest with GET /api/weave/{repoId}/audit/verification (read access; ?deep=true for admins re-checks the stored checkpoint) and export the log with GET …/audit/export?from=&to=&format=json|ndjson (admin). GET …/log/verify checks the chain on demand. See Security & access.