Skip to content

/wheypoint

When to invoke: Mark the current conversation as a durable handoff so a new agent can resume the work. Use when the user wants to preserve state for a later or parallel session. Triggers include “hand this off”, “write a handoff”, “drop a wheypoint”, “checkpoint this”, “compact the conversation”, and “/wheypoint”. Also use for “wrap up” or “I need to clear context” during a task. Do NOT use for phase handoffs from /cook, /press, /age, or /cure.


/wheypoint records the state a new agent needs to resume the work.

Use it for culture sessions, for work without a phase slug, and for a phase’s Checkpoint & stop option. A phase checkpoint is a standalone, non-terminal Wheypoint record, not a terminal phase artifact. Workers at a hard limit return observations; the parent, not the worker, runs checkpoint persistence.

  • The conversation is the primary input.
  • The optional argument shapes only the orientation line; the focus never removes a decision, question, or directive.

Run every command through this skill’s archive by its resolved installed bundle path; see ../cheese/references/harness-portability.md. When the consumer repository lacks skills/, resolve the installed bundle path before execution; never assume the easy-cheese checkout or current working directory.

Terminal window
python3 skills/wheypoint/scripts/wheypoint.pyz turns [--session <id> | --transcript <path>]
python3 skills/wheypoint/scripts/wheypoint.pyz show <work-id> [--project <key>]
python3 skills/wheypoint/scripts/wheypoint.pyz validate [intent.json] [--base <revision_id>]
python3 skills/wheypoint/scripts/wheypoint.pyz checkpoint [intent.json] [--base <revision_id>]
python3 skills/wheypoint/scripts/wheypoint.pyz checkpoint <work-id> [--base <revision_id>] --question "<q>" --gates --rationale "<why>" --decision "<d>" --directive "<d>" --quote "<words>" --operator-directive "<style>" --operator-quote "<words>" [--owner <who> --when <trigger>] --link <ref> --kind <edge-kind> [--covers <id>]...
python3 skills/wheypoint/scripts/wheypoint.pyz schema checkpoint-intent
python3 skills/wheypoint/scripts/wheypoint.pyz resolve <absolute-path | work-id | slug> [--project <key>] [--workspace-root <checkout>]
python3 skills/wheypoint/scripts/wheypoint.pyz list [--scope project | machine] [--grep <text>]... [--status <s>]... [--next <move>]... [--project <key>]... [--entry-kind <k>]... [--entry-state <s>]... [--gated | --no-gated] [--edge-kind <k>]... [--linked-to <ref>]... [--forked-from <work-id>]... [--owner <who>]...
python3 skills/wheypoint/scripts/wheypoint.pyz log <work-id> [--project <key>]
python3 skills/wheypoint/scripts/wheypoint.pyz fork <parent> <child> --orientation "<child title>" [--next <move> [--artifact <a>]]
python3 skills/wheypoint/scripts/wheypoint.pyz export <slug | work-id | path> [--out <file>] [--include-operator] [--include-local]
python3 skills/wheypoint/scripts/wheypoint.pyz import <bundle.json> [--as <slug>] [--note-dir <dir> | --no-note]
python3 skills/wheypoint/scripts/wheypoint.pyz handoff render | parse | dispatch

Repeat --grep, --status, --next, or --project to search several values in one list call; a hit matching any value of one flag is kept, and distinct flags combine with AND; never loop over list once per term; outside a Git checkout, list with no --scope searches machine scope and reports scope-fallback: machine, while an explicit --scope keeps its meaning. fork writes only a child genesis record with one forked_from edge; import writes only an imported record, and bundle_digest covers the canonical bundle with no field of its own; references/work-graph.md gives refs, edge kinds, the bundle, and the list graph filters. Create a link with checkpoint --link; resolve validates artifact links, grounded paths, Git objects, and coverage; a slug with no exact match resolves by unique prefix, then unique substring, and several matches return ambiguous with every candidate. resolve, list, log, show, schema, and turns only read; direct invocations return output, and STOP before checkpoint writing. /cheese --continue uses resolve and never invokes another archive; slash commands are host renderings, not the control model; foreign machine hits require the owning checkout; follow the continuation protocol. The parent delegates persistence to this capability as one structured checkpoint task and runs validate before checkpoint; workers never invoke either command at a hard limit. Phase skills resolve with their own wheypoint-resolve --ref <slug> command; follow references/delta-contract.md for its outcomes, working_context, and findings.

  1. Read the user’s words. Run turns and keep every user turn in view.
  2. Map each turn to an entry, or write one line that says why the turn is not captured.
  3. Rehydrate. Run show or resolve for the work id and note its revision_id; a first checkpoint needs no base.
  4. Every write to an existing record needs that revision_id as --base (or base_revision_id). After a compaction, read again before you write.
  5. Write the intent. Follow references/intent-contract.md.
  6. Put each user-stated constraint or preference in a directive entry with its verbatim quote.
  7. Put each choice in a decision entry with a rationale.
  8. Put each open item in a question entry; give a blocking question a rationale.
  9. Record a parked fork as a question with --gates and a --rationale that names the options and your prior leaning.
  10. Put the report a cold reader needs in notes.
  11. Put paths and URLs in artifact_links and working_context, not their contents.
  12. Validate. Run validate --base <revision_id> and fix every named problem.
  13. Checkpoint. Run checkpoint --base <revision_id>. A base-revision-required or stale-parent refusal means: read again, apply your change again, then write.
  14. Report. State the durability the result reports and the resume commands.

The runtime refuses an intent instead of dropping data.

  • It refuses an unknown key and names its path.
  • It refuses a first checkpoint that carries no entry and no notes.
  • It refuses next: affinage without a PR reference in artifact.
  • It refuses next: cook without an artifact.
  • It refuses text that matches a credential pattern and names the field.
  • It refuses an empty artifact_links or remove_artifact_links list.
  • It derives status: from the gating entries per the handback contract; no author sets it.
  • It refuses a baseline key rather than drop it; a Cook baseline stays in the Cook handoff.
  • It requires a rationale for each blocking question a delta adds.
  • It derives every identifier, digest, and revision.
  • It refuses an agent-authored fork transition and a forked_from edge in a delta.
  • It refuses notes over 6000 characters.
  • It pins a bare path:line in working_context or an artifact link to path:line@<short HEAD sha> when HEAD holds the file, and otherwise warns with unpinned-line-ref (no checkout or commit, or an untracked, ignored, or absent file).
  • It lists each local reference (an xdg: ref, an absolute path outside the checkout, or a Git-ignored path) under ## Local references.
  • It warns with stale-notes when a decision changes and notes stay as they were, marks that drift at the top of ## Notes, and lists an entry that checkpoint --supersede <old> [--by <new>] --rationale <why> replaced under ## Superseded.

Fix a refused intent and run checkpoint again.

The checkpoint command writes the shared preamble at the top of the generated projection; every consumer reads it with parse_handoff_slug().

status: <canonical status field>
next: mold | cook | press | age | cure | affinage | briesearch | culture | hold | tasks | done
artifact: <path, or PR#<n> / URL when next is affinage, else empty>
<one-line orientation: where the session is and what is mid-flight>

For next: tasks the projection adds a mode: parallel keyed line after artifact:; the keyed block after the orientation holds the Wheypoint pins. The projection body shows gates, open entries, decisions, directives, notes, context, artifacts, tasks, and a final ## Identifiers section. The projection title is # Wheypoint handoff. The projection is never the authority; never edit it and never resume from it by hand.

The meaning of each next: value is in references/intent-contract.md; briesearch and culture are read-only kickoffs, and tasks follows references/parallel-handoffs.md. A missing next: makes the handoff malformed; use hold when no action follows. Derive next: and status: from the open questions, not from expected success. Use status: gated: for every human decision; the resumed agent asks through the shared handoff gate before it dispatches. Handwritten notes, their legacy values, and their provenance fields are in references/legacy-notes.md and references/provenance-fields.md.

  • Never run a Git commit, push, or publication to raise durability.
  • Never write a note by hand, never edit a generated projection, and never include a secret value.
  • Reference each artifact by path or URL; do not copy its contents.
  • Use complete sentences; write one sentence per line.

End with the orientation and this link: Wheypoint dropped: [.cheese/notes/<slug>.md](<absolute-note-path>).

scripts/render_generated_regions.py generates this file from the static COMMANDS manifest in src/easy_cheese/skills/wheypoint/commands.py. Do not edit this file. Run each command as python3 skills/wheypoint/scripts/wheypoint.pyz <command> [args...]. Each command returns an integer exit status. Pass --help to a command for its arguments and output format. Keep worked examples in the skill instructions.

Command Purpose Subcommands
checkpoint Checkpoint a semantic intent onto the current record
export Write a canonical JSON bundle of a record for another person
fork Fork a child record from a parent; only the child is written
handoff Render, parse, and dispatch-split handoff preambles render, parse, dispatch
import Verify a bundle and write it as a fork child record
list List and search work items and notes across worktrees; outside a Git checkout the default scope falls back to machine
log Walk the revisions of one work id, oldest first
resolve Resolve a slug (exact, unique prefix, or unique substring), work id, or path to the current record
schema Print the JSON Schema for a registered contract slug
show Print the current record for a work id
turns Print the user’s own turns from a session transcript
validate Validate an intent against its schema without opening the store

This contract covers the durable revision written at the end of the Cook, Press, Age, or Cure phase. The record is keyed by the phase slug and work id. A terminal phase handoff writes its phase artifact and then commits one revision for that phase. Mold publication and Plate publication do not call this writer and do not create a wheypoint revision. No plugin hook is part of this contract. Issue #654 ask 4 (a /compact hook that emits the grounded manifest) is deferred follow-up work until a host-neutral compaction trigger exists; the compaction hook itself is host-specific and out of scope here.

Each phase uses its own archive for entry resolution: python3 skills/<phase>/scripts/<phase>.pyz wheypoint-resolve --ref <slug>. Pass --corpus-root <dir> to read this project’s corpus from another location; the writer accepts the same flag. A corpus belonging to another project resolves but gates on project-mismatch, so the flag relocates a corpus rather than borrowing one. --corpus-root is not accepted with --legacy, which reads a note beside the repository rather than any corpus; the pair exits 2. Plate also runs this command on entry, but only to resolve; it creates no revision. The six outcomes are authoritative, not-found, legacy, gated, ambiguous, and error. An authoritative record is the primary input. Its working_context is authoritative and supplies the first batched tilth_read. A not-found result proceeds cold. A legacy result shows its source and slug before the phase proceeds. A gated, ambiguous, or error result stops the phase and shows its payload. Advisory findings display with any outcome.

A result with source: phase-artifact came from the first readable matching file in this order: .cheese/cure/<slug>.md, .cheese/age/<slug>.md, .cheese/press/<slug>.md, then .cheese/cook/<slug>.md. The handoff preamble parser supplies phase_slug from that file. The result has outcome legacy and is not dispatchable as an authoritative record. Show the source and parsed phase slug before using the artifact as context.

A phase writer accepts one or more --grounded path[#start-end] arguments. Paths are repository-relative files with optional one-based inclusive line ranges. A first revision requires at least one grounded entry. The writer accepts at most 16 grounded entries. Supplying a grounded list replaces working_context; omitting it carries the existing context. A # inside a file name is legal; the range is anchored on the last #. PR#<n> and URL entries in working_context are pointers, not grounded paths; lint skips them. The writer anchors relative paths and .cheese/ at the git toplevel (or --root), never at the current directory.

Exit 2 is caller usage: a bad --grounded entry or a first revision without one; nothing is written. Exit 4 is a kernel failure before the artifact write; nothing is written. Exit 5 means the artifact was written but the revision failed; stderr carries wheypoint: artifact-orphaned <path> and the next resolve gates on stale-artifact-link. Every wheypoint:-tagged line on stderr is one plain-ASCII line, identical on every host. A refusal, exit 2 or exit 4, is reported as one stderr JSON line, {"error": <message>, "exit_code": <n>}, instead. A successful write prints wheypoint: revision work_id=<id> revision_id=<id> revision_number=<n>. A phase writer over an existing record needs --base <revision_id>, the revision from the phase-entry wheypoint-resolve. A missing base is refused as base-revision-required and names the current revision; a superseded base is refused as stale-parent; both refuse before any file is written. The writer accepts an identical write that a caller retries with its original base after a lost response. The retry exits 0, prints the original revision with replayed=true, and writes nothing. The retry must repeat the orientation, next move, grounded entries, session, and artifact bytes. The record must still pin those bytes, and the file must still hold them; otherwise the retry is stale-parent. A lost genesis response cannot replay, because a genesis write names no base. A first write for a work id needs no base. The writer never retries a conflict; a conflict at commit time exits 5 and orphans the artifact. An unexpected failure always prints a traceback to stderr; set EASY_CHEESE_DEBUG or CHEESE_DEBUG to add one to deliberate refusals as well.

resolve validates the record and its links; there is no separate lint command.

stale-artifact-link is a gating finding. It means a digest-bearing phase-artifact link is missing or no longer matches its recorded digest. Stop instead of dispatching when this finding is present.

schema-version-future is a gating finding. It means a record carries a schema stamp newer than this archive reads. Stop and report that the archive is older than the record.

stale-commit is advisory. It means the recorded repository commit exists but is not an ancestor of the current HEAD. Display the code and detail with the resolved payload, but do not stop solely for this finding.

grounded-path-missing is advisory. It means a path named in working_context is absolute, escapes the repository root, or is no longer a file; the detail names which. Display the code and detail with the resolved payload, but do not stop solely for this finding.

Advisory findings never hide the outcome. A gating finding remains a stop even when advisory findings are also present.

A checkpoint result carries a warnings list. stale-notes means a decision was added or transitioned and notes stayed as they were. The commit stamps notes_revision_number when it replaces notes and decisions_revision_number when it adds or transitions a decision, so a later projection shows the drift as a marker line at the top of ## Notes. A supersede transition names its successor in target_entry_id; that entry may be one the same delta adds. The projection omits a superseded entry from its kind section and lists - <id> -> <successor id> under ## Superseded, before ## Identifiers. Rewrite notes and checkpoint again when the notes now contradict the decision. unpinned-line-ref means a context item or artifact link held a bare path:line that the checkpoint could not pin, because no checkout or no commit exists, or because the file is untracked, ignored, or absent. The reference stays as written. When HEAD holds the file, the checkpoint stores path:line@<short HEAD sha> instead and gives no warning. A path#symbol ref and an already pinned ref are stored unchanged. A digest for a repo: or xdg: link covers the whole file; its locator does not change the digest. The projection lists each local reference under ## Local references, before ## Identifiers, and only when one exists. A local reference is an xdg: ref, an absolute path or a .. or symlink path that leaves the checkout, or a repository path that git check-ignore reports, such as .cheese/. When git check-ignore fails, every repository path counts as local. Outside a checkout only xdg: refs and absolute paths count. The reader sees which references need the author’s machine.

The resolve payload carries bridge beside the outcome.

  • bridge is {state, node_ref, wheypoint_ref}, or null when no record resolved.
  • bridge.state is bound, bridge-inactive, or unbound, and it never changes dispatchable.
  • matched_by is exact, prefix, or substring, or null when nothing matched. A unique prefix or substring match still dispatches; callers read matched_by to see the guess.

A schema-3 link that holds only path reads as repo:<path> without changing stored bytes. The resolve payload does not carry a receipt for this read.

checkpoint accepts one intent and derives everything else.

Run schema checkpoint-intent for the generated JSON Schema.

Run validate for a schema-only dry run that never opens the store.

{
"work_id": "auth-retry-backoff",
"orientation": "One or more lines; the first line becomes the record title at genesis.",
"working_context": ["src/auth/retry.py", "PR#412"],
"notes": "The report a cold reader needs, as Markdown.",
"next": "cook",
"artifact": ".cheese/specs/auth-retry-backoff.md",
"entries": [
{"kind": "decision", "summary": "Cap the backoff at 30s.", "rationale": "Burst callers saturate the pool."},
{"kind": "directive", "summary": "Prose stays STE100.", "quote": "is it all in STE100?"},
{"kind": "question", "summary": "Do we jitter?", "blocks_continuation": true, "rationale": "Options: ceiling first or jitter first; leaning ceiling (src/auth/retry.py:88)."}
],
"artifact_links": [{"path": ".cheese/specs/auth-retry-backoff.md", "covers_entry_ids": []}],
"remove_artifact_links": [".cheese/cook/stale.md"],
"transitions": [{"entry_id": "q-0f1e2d3c4b5a", "action": "resolve", "rationale": "Answered in the spec.", "target_entry_id": null}],
"tasks": null,
"parallel": null,
"base_revision_id": null,
"session": {"harness": "claude", "session_id": "abc123", "captured_at": "2026-09-05T12:00:00Z"}
}
  • work_id is required and becomes one path segment under the corpus.
  • orientation is free text; its first line becomes the title at genesis.
  • working_context is a list of pointers, not a paragraph.
  • notes is the Markdown body the projection renders under ## Notes; omission carries it forward.
  • The record stamps notes_revision_number when a checkpoint replaces notes, and decisions_revision_number when it adds or transitions a decision. When the decision stamp is newer, or only the decision stamp exists, the projection prints one > notes may be stale: ... line at the top of ## Notes that names both revisions. A record without stamps prints no marker.
  • notes holds at most 6000 characters.
  • next accepts mold, cook, press, age, cure, affinage, briesearch, culture, hold, tasks, or done.
  • artifact rides beside next; affinage needs PR#<n> or a PR URL, and cook needs a path.
  • entries holds ProposedEntry values of kind decision, question, or directive.
  • Each entry has {kind, summary, rationale?, quote?, blocks_continuation}.
  • Only a question can set blocks_continuation: true.
  • A directive carries the user’s words verbatim in quote.
  • The runtime derives each entry_id from the parent and the proposal.
  • A question with blocks_continuation: true needs a rationale; the rationale states the options, the evidence, and your prior leaning.
  • A blocker entry no longer exists; a pre-v5 blocker loads as a blocking question.
  • artifact_links holds {path, ref?, covers_entry_ids?}; the runtime computes the digest and pins the revision.
  • ref is a typed ref; see the scheme table in work-graph.md.
  • A link without ref reads as repo:<path>.
  • A link replaces the carried link with the same normalized ref; links are a set keyed by that ref.
  • A milknado: or https: link carries no digest; a covers_entry_ids on it is refused as unpinnable-scheme.
  • An unpinned wheypoint: link is pinned to the target’s current revision at commit.
  • remove_artifact_links names carried paths to drop; an unknown path is refused.
  • An empty artifact_links or remove_artifact_links list is refused.
  • add_edges holds {to, kind, rationale?}; the host stamps revision_id at commit and refuses a supplied value.
  • remove_edges holds {to, kind} keys of carried edges to drop.
  • Edges are a set keyed by (to, kind); work-graph.md lists each kind.
  • An intent never adds or removes a forked_from edge; fork and the host own it.
  • transitions holds {entry_id, action, rationale, target_entry_id}; action is resolve, supersede, or withdraw.
  • Only a transition changes a protected entry’s state; no operation removes one.
  • tasks and parallel carry independent moves when next is tasks; see parallel-handoffs.md.
  • base_revision_id names the revision the writer read. It is required for every write to an existing record; a genesis write and a fork child need none.
  • session holds optional {harness, session_id, captured_at}.
  • Omission carries data forward; null means unchanged.
  • An explicit empty working_context replaces the carried value with nothing.
  • Identifiers match [a-z0-9][a-z0-9._-]{0,63}.
  • Text fields contain at most 2000 characters, notes at most 6000; lists at most 64 items.
  • References (to, ref) are absolute URIs of at most 2000 characters.
  • A first checkpoint must carry at least one entry or a notes body.
  • An unknown key at any depth is refused and named by path.
  • Text that matches a credential pattern is refused and named by field.
  • An identical intent against the same parent replays the existing receipt.
  • A write to an existing record with no base is refused as base-revision-required.
  • A base that is not the current revision is refused as stale-parent.

The runtime is always ready for a compaction: every write names the revision the writer read. After a context compaction, read with show or resolve again and write with that revision_id as --base. There is no compaction proof; --compacted is removed.

checkpoint and validate build or overlay the intent from flags. With an intent file, each flag extends or replaces the matching key of that file. Without an intent file, the flags build the whole intent. With flags, a positional that names no existing path is a work id. Flags ignore stdin unless the intent argument is -.

  • --work-id, --orientation, --next, --artifact, and --notes-file set one scalar each.
  • --base sets base_revision_id to the revision you read; an existing record requires it.
  • --question adds a question entry; --gates makes every question in the call block continuation.
  • A blocking question needs a --rationale; the rationale pairs by order, see below.
  • --decision adds a decision, and --directive adds a directive with the paired --quote.
  • --operator-directive adds a directive with scope: operator: how the user wants to be worked with, not an instruction for this work. Pair each with an --operator-quote; --quote pairs only with --directive. The projection lists it under ## Operator preferences, apart from ## Directives.
  • --owner and --when store free-text owner and when on a question. Give none, or one per --question; they pair by order. A different count refuses with flag-pairing and writes nothing. The projection groups open questions under one ### subheading per owner (matched case-insensitively), puts unowned ones under unassigned, and prints (when: <trigger>) after the summary. A blocking question’s gate line also shows (owner: <who>) and (when: <trigger>). With no owner on any question the list stays flat.
  • A checkpoint pins each bare path:line (or path:line-line) in --context items, in intent working_context, and in artifact links to path:line@<short HEAD sha>, when HEAD holds the file. It never pins on read. The text stays unpinned and the result warns unpinned-line-ref when there is no checkout or commit, or the file is untracked, ignored, or absent. path#symbol and already pinned refs stay as written. A pin changes the intent, so the same intent at a later HEAD is a new revision.
  • --resolve and --withdraw add transitions for carried entry ids.
  • --supersede <old> adds a supersede transition that sets superseded_by on <old>. --by <new> names the successor entry id; give one --by per --supersede. Without --by, the successor is the one entry of the same kind that the same checkpoint adds, and that needs the revision you read (--base). If no successor resolves, the checkpoint refuses with flag-pairing and writes nothing.
  • --rationale values pair in order with each blocking question, then each --decision, then each --resolve, then each --withdraw, then each --supersede.
  • --context adds a working_context path.
  • --link adds an edge with the paired --kind; a pinnable ref also adds an artifact link.
  • --covers applies to every pinnable --link in the call.
  • --covers omitted keeps the stored coverage of a flag-built link; a link from the intent file keeps the coverage it states.

The flag form refuses with these codes:

  • flag-pairing: the --rationale count differs from the blocking questions, decisions, resolves, withdraws, and supersedes (so a --supersede with no --rationale refuses), a --by count differs from the --supersede count, a --supersede without --by has no resolvable successor (its id prefix names no entry kind, the checkpoint does not add exactly one entry of that kind, or the work id or --base is missing), an --owner or --when count differs from the --question count, a --quote, --operator-quote, or --kind count differs from its pair, --gates has no question, or --covers has no pinnable --link.
  • flag-kind: a --kind names no edge kind.
  • flag-link: a --link is not a valid typed ref.
  • flag-conflict: the intent file holds a non-list value at a key a flag extends.
  • notes-unreadable: the --notes-file could not be read.
  • intent-ambiguous: the positional work id differs from --work-id.
  • intent-unreadable: the positional is neither an intent file nor a work id, names a missing .json file or a path, or names a directory.
  • mold, cook, press, age, cure: the next pipeline phase. next: cook on a standalone checkpoint names the phase to resume; it does not publish a Cook→Cook phase artifact.
  • affinage: PR review comments or failing CI; artifact names the PR.
  • briesearch, culture: a read-only next move that /cheese --continue dispatches.
  • tasks: independent moves; see parallel-handoffs.md.
  • hold: restore orientation and wait for instructions.
  • done: the work is complete; the checkpoint is a record, not a baton.

A success reply prints one indented JSON document to stdout: {"ok": true, "command": "<name>", ...fields}. A refusal writes one JSON line to stderr and prints nothing to stdout: {"error": "<code>: <message>", "exit_code": 2}.

  • checkpoint returns note_path, replayed, work_id, revision_id, revision_number, parent_revision_id, status, durability, projection_path, record, revision, markdown, derived_entry_ids, applied_transitions, applied_edges, removed_edges, and warnings.
  • validate returns valid and work_id.
  • schema returns slug and schema.
  • resolve returns ref, outcome, dispatchable, source, work_id, record, projection, findings, matches, searched, legacy_note, legacy_slug, phase_slug, detail, matched_by, bridge. matched_by is exact, prefix, or substring, or null when nothing matched. A prefix or substring match still dispatches.
  • show returns work_id, status, revision_id, revision_number, record, bridge.
  • fork replies are in work-graph.md.
  • list returns corpus_root, items, and lines, plus scope-fallback only when the scope fell back.
  • log returns work_id, revisions, lines, and unreadable.
  • turns returns transcript, count, skipped_lines, turns, and lines.

lines is a list of strings, one per row, for a shell caller to read line by line. Each lines entry is tab-separated columns, in a fixed order per command. list columns are work_id, revision_number, status, next, detail. log columns are revision_number, revision_id, captured_at, additions, transitions, compacted. turns columns are timestamp, text. A column value escapes a backslash as \\. A column value escapes a newline as \n. A column value escapes a tab as \t. This escaping keeps one line one record.

items (from list) is one untyped JSON object per work item, carrying work_id plus either unreadable, no_record, or the record’s summary fields. revisions (from log) is one untyped JSON object per revision, carrying revision_number, revision_id, captured_at, additions, transitions, compacted. turns (from turns) is one untyped JSON object per user turn, carrying timestamp and text. unreadable (from log) lists {path, reason} for revision files the scan could not parse. skipped_lines (from turns) counts transcript lines that could not be parsed as a turn. count (from turns) is the number of turns returned. corpus_root (from list) is the resolved root directory the listing scanned. scope-fallback (from list) is machine when list ran with no --scope, --project, --corpus-root, or $EASY_CHEESE_PROJECT outside a Git checkout, and so searched machine scope. Under that fallback, corpus_root is the project corpus root that would apply, not the root scanned; the scan covered every project corpus.

Exit 0 means the command succeeded; the reply carries the command’s own fields. Exit 2 means the command refused the request or the command-line usage was wrong; a refusal stderr line carries error and exit_code. Exit 3 means the reply violated its own schema contract. An unexpected crash also exits 1, but the stderr line names the exception class and points to a traceback file; it carries no refusal code.

Each refusal names a code:

  • invalid-json: stdin was not one JSON value.
  • storage-error: the work store could not be opened or read.
  • commit-only-field: checkpoint was asked to author compacted, compaction, or expected_revision_id directly.
  • base-revision-required: the record exists and the write named no --base; the message names the current revision.
  • invalid-intent: the intent payload failed schema or delta validation, such as a blocking question without a rationale.
  • secret-pattern: a field looked like a credential.
  • record-unreadable: the work’s record exists but could not be parsed.
  • genesis-conflict: a genesis commit collided with an existing record.
  • stale-parent: the named base is not the current revision; read again and re-apply.
  • commit-refused: the commit kernel refused the delta for another reason.
  • note-unwritable: the note directory or mirror file could not be written.
  • pending-corrupt: a pending-mirror ledger entry named a different request than its revision.
  • unknown-contract: schema was asked for a slug with no registered contract.
  • record-missing: show or log found no record for the work id.
  • store-inconsistent: log found a record but every revision file was dropped as unreadable.
  • session-required: turns was given neither --session nor --transcript.
  • invalid-session: the given --session id was not a safe file-name segment.
  • transcript-missing: no transcript file exists at the resolved path.
  • invalid-reference: resolve could not interpret the given reference.
  • flag-pairing, flag-kind, flag-link, flag-conflict, notes-unreadable: the flag form refused; see Flag form.
  • unpinnable-scheme, unknown-edge: the commit kernel refused a ref or an edge.
  • A host-only edge kind on add_edges or remove_edges is refused at intent validation as invalid-intent, before the commit kernel runs.
  • A record stamped with a newer schema than this archive reads is refused as schema-version-future.

A handwritten note under .cheese/notes/ predates the continuity kernel.

The resolve command still reads it, and a legacy result is never authoritative.

A legacy result gates a resume for a human decision.

A legacy note accepts mode:, order:, session:, git:, created:, parents:, and baseline: between artifact: and the orientation.

mode: is optional; an omitted mode means mode: single.

In mode: single, next: names the skill that the new agent runs.

For multiple read-only moves, use a next: list with order: parallel | sequential.

Use only briesearch or culture in an inline next: list.

See provenance-fields.md for session:, git:, created:, and parents:.

  • halt: <one-line reason> is valid only in a handwritten note.
  • The runtime never derives halt; derived status has only ok and gated:.
  • resolve gates every legacy status whose disposition is not proceed.
  • A legacy halt therefore stops: the reader shows the reason and dispatches nothing.

A handwritten note can record a one-line baseline: value.

The baseline is settled state; do not re-ask, re-flag, or re-halt on identical baseline entries.

The canonical record carries no baseline field, so keep a Cook baseline mapping in the Cook handoff.

See ../../cook/references/quality-gates.md.

/cheese --continue <slug> resolves the slug through resolve and dispatches next: only from a validated current revision.

An absolute note path resolves as an explicit path first.

Resume preserves mode:, --hard, --open-pr, --safe, and an explicit --auto.

A Press finding hands off as a Cook correction (next: cook).

Use this contract when one checkpoint starts multiple moves.

tasks and parallel are CheckpointIntent fields; see intent-contract.md.

Set next: tasks and give at least one task.

The projection renders mode: parallel between next: and artifact:, plus a ## Tasks section. This position keeps mode metadata separate from free-text orientation. A legacy orientation that starts with mode: remains text.

A single move does not need this contract.

Give each task its exact command; commands can name different skills.

Never run parallel write tasks in one checkout.

Select one isolation strategy:

worktree_strategy Use when Required fields
existing The user has durable bench checkouts each write task has distinct worktree, branch, and branch_from
create No checkouts exist worktree_root, plus each write task has branch and branch_from
harness The host creates isolated worktrees each write task has branch and branch_from; the host creates the checkout

Intent example:

{
"work_id": "kip-ai",
"orientation": "KIP-76 and KIP-77 are ready to run as independent PR efforts.",
"next": "tasks",
"parallel": {"isolation": "git-worktree", "worktree_strategy": "existing"},
"tasks": [
{"slug": "kip-77-ai-test-server", "intent": "cook", "repo": "/path/to/repository",
"worktree": "/path/to/worktree-01", "branch": "user/kip-77-ai-test-server",
"branch_from": "origin/main", "command": "/cook .cheese/specs/kip-77-ai-test-server.md"},
{"slug": "kip-76-ai-service-spin-up", "intent": "cook", "repo": "/path/to/repository",
"worktree": "/path/to/worktree-02", "branch": "user/kip-76-ai-service-spin-up",
"branch_from": "origin/main", "command": "/cook .cheese/specs/kip-76-ai-service-spin-up.md"}
]
}

Rendered projection preamble and tasks block:

status: ok
next: tasks
mode: parallel
artifact:
KIP-76 and KIP-77 are ready to run as independent PR efforts.
## Tasks
parallel:
isolation: git-worktree
worktree_strategy: existing
tasks:
- slug: kip-77-ai-test-server
intent: cook
repo: /path/to/repository
worktree: /path/to/worktree-01
branch: user/kip-77-ai-test-server
branch_from: origin/main
command: /cook .cheese/specs/kip-77-ai-test-server.md
- slug: kip-76-ai-service-spin-up
intent: cook
repo: /path/to/repository
worktree: /path/to/worktree-02
branch: user/kip-76-ai-service-spin-up
branch_from: origin/main
command: /cook .cheese/specs/kip-76-ai-service-spin-up.md

For a new setup, use worktree_strategy: create and add worktree_root.

/cheese --continue derives one checkout from each task slug.

A handwritten legacy note may list read-only moves with next: [briesearch "slug1", culture "slug2"].

With order: parallel, /cheese --continue starts one read agent per item in the same turn; with order: sequential, it runs them in listed order.

See legacy-notes.md.

A live session can fill four optional header fields.

Two lineage commands remain outside the continuity contract.

Put these optional fields before the orientation line.

Only the live session supplies them.

Pre-provenance notes remain valid.

  • session: <harness>:<session-id> identifies an active Claude, Codex, or OpenCode session.
  • Omit the field when it is unavailable.
  • Claude’s newest-file heuristic is <speculative>.
  • git: <branch>@<short-sha> identifies the branch and short commit.
  • Use a callable, read-only git inspection capability.
  • Run git status --short --branch and git rev-parse --short HEAD.
  • Omit the field when git inspection is unavailable.
  • Omit the field outside a git repository.
  • created: <UTC ISO-8601> gives the UTC capture time.
  • parents: [<slug>, ...] gives the lineage that the commands below write.

The runtime writes these fields; an intent never sets them.

  • edges on the record holds its typed edges, keyed by (to, kind); see work-graph.md.
  • A fork child holds one forked_from edge that names the parent revision.
  • A pre-v5 origin, successor, or copies field loads as data and stays unchanged on disk.

Legacy --join writes parents: [<slugA>, <slugB>].

Each --split child writes parents: [<current-slug>].

These commands remain outside this continuity contract.

They rewrite .cheese/notes/ Markdown and commit no delta.

A record names other work and documents through typed refs and typed edges. fork, import, and checkpoint --link write edges; the list filters read them. Each write changes only the record that starts it.

A ref is an absolute URI string. The runtime parses, normalizes, resolves, and digests it by scheme.

Scheme Form Resolves to Digest pin
repo: repo:<repo-relative path> a file in the bound checkout sha256 of the bytes
xdg: xdg:<project_key>/<path> a document under the corpus home of that project sha256 of the bytes
wheypoint: wheypoint:<project_key>/<work_id>[@<revision_id>][#<entry_id>] a record, one revision, or one entry the target record digest at the pinned revision
milknado: milknado:<project_key>/<node_key> a Mikado node by stable key none
https: a PR, issue, or other URL an external page none
  • A wiki page is a repo: ref; no wiki: scheme exists.
  • milknado: and https: refs carry no digest, and the runtime does not check that the target exists.
  • A --covers or covers_entry_ids on a milknado: or https: ref is refused as unpinnable-scheme.
  • An unpinned wheypoint: link is pinned to the target’s current revision at commit.
  • A schema-3 link that holds only path reads as repo:<path> without changing stored bytes.
  • A pre-v5 record loads as it is and normalizes on read; the runtime rewrites nothing.

An edge is {to, kind, rationale?, revision_id}, held by the record it starts from. A record holds its edges as a set keyed by (to, kind). The host stamps revision_id at commit.

Kind Meaning
forked_from this record is a fork child of the target
supersedes this record replaces the target
checkpoints this record checkpoints a Mikado goal or task
  • forked_from is host-only; only fork and import write it.
  • An intent or checkpoint --link that names forked_from is refused at intent validation as invalid-intent.
  • No edge has a reciprocal; a read of the target record never shows the edge.
  • Use list --linked-to <ref> or list --forked-from <work-id> to find the records on the other side.

Create a link with checkpoint <work-id> --link <ref> --kind <edge-kind> [--covers <id>].... An intent does the same with add_edges. For a pinnable ref, the checkpoint also adds or refreshes the artifact link with the current digest and revision pin. --covers names entry ids that the pinned link covers. Omitting --covers keeps the stored coverage; --covers replaces it. An intent removes an edge with remove_edges.

Terminal window
python3 skills/wheypoint/scripts/wheypoint.pyz fork <parent> <child> --orientation "<child title>" [--link <ref>]... [--context <path>]... [--notes-file <file>] [--next <move>] [--artifact <artifact>] [--project <key>]
  • fork writes exactly one revision: the child genesis, with one forked_from edge.
  • The edge is pinned to the parent’s current revision.
  • The parent record is never written by fork.
  • The child carries no entry from the parent; copy a decision into the child notes or a link instead.
  • The first line of --orientation becomes the child title.
  • --next follows the same artifact rule as checkpoint; a missing --artifact for cook or affinage is refused as invalid-intent.
  • fork mirrors the child projection to .cheese/notes and reports repo-snapshot, like checkpoint; under --project it writes no mirror and reports canonical-local.
  • fork-exists: the child work id already has a record or history.
  • unknown-parent: the parent has no record.
  • record-unreadable: the parent record could not be read.
  • invalid-intent: an empty --orientation, a bad --next, or an --artifact that --next cannot use.
  • note-unwritable: the child projection mirror could not be written.
Terminal window
python3 skills/wheypoint/scripts/wheypoint.pyz export <slug | work-id | path> [--out <file>] [--include-operator] [--include-local] [--workspace-root <dir>]
python3 skills/wheypoint/scripts/wheypoint.pyz import <bundle.json> [--as <slug>] [--note-dir <dir> | --no-note] [--workspace-root <dir>]

A bundle is one canonical JSON file with these fields: bundle_version, origin, included, record, record_digest, projection, projection_digest, and bundle_digest. Without --out, export returns the bundle in the JSON reply. A digest proves integrity, not authorship; anyone can build a bundle with matching digests.

  • record_digest covers the exported, filtered record.
  • origin carries the source revision_id and the record_digest of the unfiltered record.
  • bundle_digest covers the canonical bundle without its own field.
  • export omits operator directives and local refs by default; --include-operator and --include-local keep them, and included records the choice.
  • export replaces a local path in free text (notes, orientation, next_action, entry summary, rationale, and quote) with <local reference omitted>; --include-local keeps it.
  • An absolute path under a machine root such as /home or /Users is local when it is outside the checkout, whether or not it exists.
  • export drops next_action.tasks and next_action.parallel by default and changes a tasks move to hold; --include-local keeps them.
  • When git check-ignore fails, export treats every candidate path as local and omits it.
  • A path is local by the checkout named by --workspace-root, else the Git toplevel, never by the working directory.
  • export refuses with export-checkout-required when no checkout exists and the record links a repository path.
  • export accepts an authoritative or gated record.
  • import checks in this order: bundle digest, record structure, record digest, projection digest, projection identifiers, origin against record.
  • Any digest mismatch, including an origin that does not name the record, is refused as bundle-digest-mismatch, and nothing is written.
  • import also checks that bundle_version, included, and origin have the right types and agree with the record.
  • import bounds the bundle at 4 MiB and validates every key and value strictly.
  • import refuses a record that matches a credential pattern with secret-pattern, and nothing is written.
  • import writes one genesis revision with one forked_from edge to the origin record.
  • --as names the new work id; the default is the origin work id.
  • Only active entries import, as fresh derived entry ids; artifact-link digests and covers are derived again.
  • A local artifact link is skipped and reported as skipped-local-link; on import any absolute path is local.
  • A link this machine cannot digest, such as a wheypoint: record or a repository path it lacks, is skipped and reported as skipped-unresolvable-link.
  • A source with notes drift imports with decisions stamped at revision 1 and notes unstamped, so the drift marker renders again on import with the importer’s revision numbers.
  • export-unresolved: the ref did not resolve to one current record.
  • bundle-unwritable: the --out file could not be written.
  • bundle-unreadable: the bundle file could not be read.
  • export-checkout-required: the record links a repository path and no Git checkout is known.
  • bundle-invalid: the bundle is oversized, malformed, too deeply nested, or fails schema validation.
  • bundle-digest-mismatch: a digest or the origin does not match the record.
  • invalid-slug: the --as value is not a lower-case identifier.
  • import-exists: the target work id already has a record.
  • note-unwritable: the projection mirror could not be written.

list adds these repeatable filters:

  • --entry-kind and --entry-state keep records with a matching entry; one entry must match both.
  • --gated keeps only gated records, and --no-gated keeps only ungated records.
  • --edge-kind keeps records that hold an edge of that kind.
  • --linked-to <ref> keeps records whose edges or links name the ref.
  • --forked-from <work-id> keeps the fork children of that parent.
  • --owner <who> keeps records with an active question owned by that person; the match ignores case.

Each list item adds edges_out, edges_in, forked_from, and gates. edges_out items are {kind, to}, and edges_in items are {kind, source}. A bad --edge-kind refuses flag-kind, and a bad --entry-kind or --entry-state refuses flag-entry.

show and resolve add bridge to their replies. bridge is {state, node_ref, wheypoint_ref}. resolve reports bridge: null when no record resolved.

A checkpoints edge to a milknado: ref binds the record to a Mikado goal or task. The address a record gives milknado is wheypoint:<project_key>/<work_id>, never a projection path. The bridge is data only: it reads the edge, checks for .milknado/ at the repo root, and reports the state.

  • bound: the record holds a checkpoints edge to a milknado: ref, and .milknado/ exists at the repo root.
  • bridge-inactive: the record holds that edge, but .milknado/ is absent; the edge is inert.
  • unbound: the record holds no checkpoints edge to a milknado: ref.

The bridge never changes dispatchable. The gate mapping is data for a future milknado call:

Wheypoint event Milknado state
gated question pending goal review
resolve accepted review
checkpoint snapshot receipt
  • The list filters scan record.json files; no index by decision or by ref exists.
  • An xdg: document digest changes when the document is edited, so coverage fails at the next resolve.