/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.
Runtime commands
Section titled âRuntime commandsâ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.
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-intentpython3 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 | dispatchRepeat --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.
- Read the userâs words. Run
turnsand keep every user turn in view. - Map each turn to an entry, or write one line that says why the turn is not captured.
- Rehydrate. Run
showorresolvefor the work id and note itsrevision_id; a first checkpoint needs no base. - Every write to an existing record needs that
revision_idas--base(orbase_revision_id). After a compaction, read again before you write. - Write the intent. Follow
references/intent-contract.md. - Put each user-stated constraint or preference in a
directiveentry with its verbatimquote. - Put each choice in a
decisionentry with arationale. - Put each open item in a
questionentry; give a blocking question arationale. - Record a parked fork as a
questionwith--gatesand a--rationalethat names the options and your prior leaning. - Put the report a cold reader needs in
notes. - Put paths and URLs in
artifact_linksandworking_context, not their contents. - Validate. Run
validate --base <revision_id>and fix every named problem. - Checkpoint. Run
checkpoint --base <revision_id>. Abase-revision-requiredorstale-parentrefusal means: read again, apply your change again, then write. - Report. State the durability the result reports and the resume commands.
What the runtime enforces
Section titled âWhat the runtime enforcesâ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: affinagewithout a PR reference inartifact. - It refuses
next: cookwithout anartifact. - It refuses text that matches a credential pattern and names the field.
- It refuses an empty
artifact_linksorremove_artifact_linkslist. - It derives
status:from the gating entries per the handback contract; no author sets it. - It refuses a
baselinekey 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
forktransition and aforked_fromedge in a delta. - It refuses
notesover 6000 characters. - It pins a bare
path:lineinworking_contextor an artifact link topath:line@<short HEAD sha>whenHEADholds the file, and otherwise warns withunpinned-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-noteswhen a decision changes andnotesstay as they were, marks that drift at the top of## Notes, and lists an entry thatcheckpoint --supersede <old> [--by <new>] --rationale <why>replaced under## Superseded.
Fix a refused intent and run checkpoint again.
Handoff slug
Section titled âHandoff slugâ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 | doneartifact: <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.
next: values
Section titled ânext: valuesâ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.
Handoff
Section titled âHandoffâEnd with the orientation and this link: Wheypoint dropped: [.cheese/notes/<slug>.md](<absolute-note-path>).
/wheypoint bundle commands
Section titled â/wheypoint bundle commandsâ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 |
Wheypoint phase delta contract
Section titled âWheypoint phase delta contractâ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.
Entry resolution
Section titled âEntry resolutionâ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.
Grounded context
Section titled âGrounded 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.
Writer exit codes
Section titled âWriter exit codesâ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 findings
Section titled âResolve findingsâ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.
Checkpoint warnings
Section titled âCheckpoint warningsâ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.
Work-graph key in the resolve payload
Section titled âWork-graph key in the resolve payloadâThe resolve payload carries bridge beside the outcome.
bridgeis{state, node_ref, wheypoint_ref}, ornullwhen no record resolved.bridge.stateisbound,bridge-inactive, orunbound, and it never changesdispatchable.matched_byisexact,prefix, orsubstring, ornullwhen nothing matched. A unique prefix or substring match still dispatches; callers readmatched_byto 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.
The CheckpointIntent contract
Section titled âThe CheckpointIntent contractâ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_idis required and becomes one path segment under the corpus.orientationis free text; its first line becomes the title at genesis.working_contextis a list of pointers, not a paragraph.notesis the Markdown body the projection renders under## Notes; omission carries it forward.- The record stamps
notes_revision_numberwhen a checkpoint replacesnotes, anddecisions_revision_numberwhen 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## Notesthat names both revisions. A record without stamps prints no marker. notesholds at most 6000 characters.nextacceptsmold,cook,press,age,cure,affinage,briesearch,culture,hold,tasks, ordone.artifactrides besidenext;affinageneedsPR#<n>or a PR URL, andcookneeds a path.entriesholdsProposedEntryvalues of kinddecision,question, ordirective.- Each entry has
{kind, summary, rationale?, quote?, blocks_continuation}. - Only a question can set
blocks_continuation: true. - A
directivecarries the userâs words verbatim inquote. - The runtime derives each
entry_idfrom the parent and the proposal. - A
questionwithblocks_continuation: trueneeds arationale; the rationale states the options, the evidence, and your prior leaning. - A
blockerentry no longer exists; a pre-v5 blocker loads as a blocking question. artifact_linksholds{path, ref?, covers_entry_ids?}; the runtime computes the digest and pins the revision.refis a typed ref; see the scheme table inwork-graph.md.- A link without
refreads asrepo:<path>. - A link replaces the carried link with the same normalized ref; links are a set keyed by that ref.
- A
milknado:orhttps:link carries no digest; acovers_entry_idson it is refused asunpinnable-scheme. - An unpinned
wheypoint:link is pinned to the targetâs current revision at commit. remove_artifact_linksnames carried paths to drop; an unknown path is refused.- An empty
artifact_linksorremove_artifact_linkslist is refused. add_edgesholds{to, kind, rationale?}; the host stampsrevision_idat commit and refuses a supplied value.remove_edgesholds{to, kind}keys of carried edges to drop.- Edges are a set keyed by
(to, kind);work-graph.mdlists eachkind. - An intent never adds or removes a
forked_fromedge;forkand the host own it. transitionsholds{entry_id, action, rationale, target_entry_id};actionisresolve,supersede, orwithdraw.- Only a transition changes a protected entryâs state; no operation removes one.
tasksandparallelcarry independent moves whennextistasks; seeparallel-handoffs.md.base_revision_idnames the revision the writer read. It is required for every write to an existing record; a genesis write and aforkchild need none.sessionholds optional{harness, session_id, captured_at}.
- Omission carries data forward;
nullmeans unchanged. - An explicit empty
working_contextreplaces the carried value with nothing. - Identifiers match
[a-z0-9][a-z0-9._-]{0,63}. - Text fields contain at most 2000 characters,
notesat 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
notesbody. - 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.
Compaction
Section titled âCompactionâ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.
Flag form
Section titled âFlag formâ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-fileset one scalar each.--basesetsbase_revision_idto the revision you read; an existing record requires it.--questionadds a question entry;--gatesmakes every question in the call block continuation.- A blocking question needs a
--rationale; the rationale pairs by order, see below. --decisionadds a decision, and--directiveadds a directive with the paired--quote.--operator-directiveadds a directive withscope: operator: how the user wants to be worked with, not an instruction for this work. Pair each with an--operator-quote;--quotepairs only with--directive. The projection lists it under## Operator preferences, apart from## Directives.--ownerand--whenstore free-textownerandwhenon a question. Give none, or one per--question; they pair by order. A different count refuses withflag-pairingand writes nothing. The projection groups open questions under one###subheading per owner (matched case-insensitively), puts unowned ones underunassigned, 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(orpath:line-line) in--contextitems, in intentworking_context, and in artifact links topath:line@<short HEAD sha>, whenHEADholds the file. It never pins on read. The text stays unpinned and the result warnsunpinned-line-refwhen there is no checkout or commit, or the file is untracked, ignored, or absent.path#symboland already pinned refs stay as written. A pin changes the intent, so the same intent at a later HEAD is a new revision. --resolveand--withdrawadd transitions for carried entry ids.--supersede <old>adds asupersedetransition that setssuperseded_byon<old>.--by <new>names the successor entry id; give one--byper--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 withflag-pairingand writes nothing.--rationalevalues pair in order with each blocking question, then each--decision, then each--resolve, then each--withdraw, then each--supersede.--contextadds aworking_contextpath.--linkadds an edge with the paired--kind; a pinnable ref also adds an artifact link.--coversapplies to every pinnable--linkin the call.--coversomitted 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--rationalecount differs from the blocking questions, decisions, resolves, withdraws, and supersedes (so a--supersedewith no--rationalerefuses), a--bycount differs from the--supersedecount, a--supersedewithout--byhas 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--baseis missing), an--owneror--whencount differs from the--questioncount, a--quote,--operator-quote, or--kindcount differs from its pair,--gateshas no question, or--covershas no pinnable--link.flag-kind: a--kindnames no edge kind.flag-link: a--linkis 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-filecould 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.jsonfile or a path, or names a directory.
next: values
Section titled ânext: valuesâmold,cook,press,age,cure: the next pipeline phase.next: cookon a standalone checkpoint names the phase to resume; it does not publish a CookâCook phase artifact.affinage: PR review comments or failing CI;artifactnames the PR.briesearch,culture: a read-only next move that/cheese --continuedispatches.tasks: independent moves; seeparallel-handoffs.md.hold: restore orientation and wait for instructions.done: the work is complete; the checkpoint is a record, not a baton.
Reply envelope
Section titled âReply envelopeâ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}.
checkpointreturnsnote_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, andwarnings.validatereturnsvalidandwork_id.schemareturnsslugandschema.resolvereturnsref,outcome,dispatchable,source,work_id,record,projection,findings,matches,searched,legacy_note,legacy_slug,phase_slug,detail,matched_by,bridge.matched_byisexact,prefix, orsubstring, ornullwhen nothing matched. A prefix or substring match still dispatches.showreturnswork_id,status,revision_id,revision_number,record,bridge.forkreplies are inwork-graph.md.listreturnscorpus_root,items, andlines, plusscope-fallbackonly when the scope fell back.logreturnswork_id,revisions,lines, andunreadable.turnsreturnstranscript,count,skipped_lines,turns, andlines.
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:checkpointwas asked to authorcompacted,compaction, orexpected_revision_iddirectly.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 arationale.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:schemawas asked for a slug with no registered contract.record-missing:showorlogfound no record for the work id.store-inconsistent:logfound a record but every revision file was dropped as unreadable.session-required:turnswas given neither--sessionnor--transcript.invalid-session: the given--sessionid was not a safe file-name segment.transcript-missing: no transcript file exists at the resolved path.invalid-reference:resolvecould 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_edgesorremove_edgesis refused at intent validation asinvalid-intent, before the commit kernel runs. - A record stamped with a newer schema than this archive reads is refused as
schema-version-future.
Legacy notes
Section titled âLegacy notesâHandwritten legacy notes
Section titled âHandwritten legacy notesâ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.
Header keys
Section titled âHeader keysâ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:.
Legacy status values
Section titled âLegacy status valuesâhalt: <one-line reason>is valid only in a handwritten note.- The runtime never derives
halt; derived status has onlyokandgated:. resolvegates every legacy status whose disposition is notproceed.- A legacy
halttherefore stops: the reader shows the reason and dispatches nothing.
Baseline
Section titled âBaselineâ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.
Resume semantics
Section titled âResume semanticsâ/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).
Multi-move handoffs
Section titled âMulti-move handoffsâ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.
parallel and tasks
Section titled âparallel and tasksâ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: oknext: tasksmode: parallelartifact:KIP-76 and KIP-77 are ready to run as independent PR efforts.
## Tasks
parallel: isolation: git-worktree worktree_strategy: existingtasks: - 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.mdFor a new setup, use worktree_strategy: create and add worktree_root.
/cheese --continue derives one checkout from each task slug.
Read-only moves in a legacy note
Section titled âRead-only moves in a legacy noteâ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.
Provenance and lineage
Section titled âProvenance and lineageâA live session can fill four optional header fields.
Two lineage commands remain outside the continuity contract.
Provenance fields
Section titled âProvenance fieldsâ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 --branchandgit 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.
Record provenance
Section titled âRecord provenanceâThe runtime writes these fields; an intent never sets them.
edgeson the record holds its typed edges, keyed by(to, kind); seework-graph.md.- A fork child holds one
forked_fromedge that names the parent revision. - A pre-v5
origin,successor, orcopiesfield loads as data and stays unchanged on disk.
Lineage commands
Section titled âLineage commandsâ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.
The Wheypoint work graph
Section titled âThe Wheypoint work graphâ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; nowiki:scheme exists. milknado:andhttps:refs carry no digest, and the runtime does not check that the target exists.- A
--coversorcovers_entry_idson amilknado:orhttps:ref is refused asunpinnable-scheme. - An unpinned
wheypoint:link is pinned to the targetâs current revision at commit. - A schema-3 link that holds only
pathreads asrepo:<path>without changing stored bytes. - A pre-v5 record loads as it is and normalizes on read; the runtime rewrites nothing.
Edge kinds
Section titled âEdge kindsâ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_fromis host-only; onlyforkandimportwrite it.- An intent or
checkpoint --linkthat namesforked_fromis refused at intent validation asinvalid-intent. - No edge has a reciprocal; a read of the target record never shows the edge.
- Use
list --linked-to <ref>orlist --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.
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>]forkwrites exactly one revision: the child genesis, with oneforked_fromedge.- 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
--orientationbecomes the child title. --nextfollows the same artifact rule ascheckpoint; a missing--artifactforcookoraffinageis refused asinvalid-intent.forkmirrors the child projection to.cheese/notesand reportsrepo-snapshot, likecheckpoint; under--projectit writes no mirror and reportscanonical-local.
fork refusal codes
Section titled âfork refusal codesâ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--artifactthat--nextcannot use.note-unwritable: the child projection mirror could not be written.
export and import
Section titled âexport and importâ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_digestcovers the exported, filtered record.origincarries the sourcerevision_idand therecord_digestof the unfiltered record.bundle_digestcovers the canonical bundle without its own field.exportomits operator directives and local refs by default;--include-operatorand--include-localkeep them, andincludedrecords the choice.exportreplaces a local path in free text (notes,orientation,next_action, entry summary, rationale, and quote) with<local reference omitted>;--include-localkeeps it.- An absolute path under a machine root such as
/homeor/Usersis local when it is outside the checkout, whether or not it exists. exportdropsnext_action.tasksandnext_action.parallelby default and changes atasksmove tohold;--include-localkeeps them.- When
git check-ignorefails,exporttreats 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. exportrefuses withexport-checkout-requiredwhen no checkout exists and the record links a repository path.exportaccepts an authoritative or gated record.importchecks 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. importalso checks thatbundle_version,included, andoriginhave the right types and agree with the record.importbounds the bundle at 4 MiB and validates every key and value strictly.importrefuses a record that matches a credential pattern withsecret-pattern, and nothing is written.importwrites one genesis revision with oneforked_fromedge to the origin record.--asnames the new work id; the default is the origin work id.- Only active entries import, as fresh derived entry ids; artifact-link digests and
coversare 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 asskipped-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 and import refusal codes
Section titled âexport and import refusal codesâexport-unresolved: the ref did not resolve to one current record.bundle-unwritable: the--outfile 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--asvalue 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 filters
Section titled âlist filtersâlist adds these repeatable filters:
--entry-kindand--entry-statekeep records with a matching entry; one entry must match both.--gatedkeeps only gated records, and--no-gatedkeeps only ungated records.--edge-kindkeeps 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.
The bridge payload
Section titled âThe bridge payloadâshow and resolve add bridge to their replies.
bridge is {state, node_ref, wheypoint_ref}.
resolve reports bridge: null when no record resolved.
The milknado bridge
Section titled âThe milknado bridgeâ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 acheckpointsedge to amilknado: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 nocheckpointsedge to amilknado: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 |
Known costs
Section titled âKnown costsâ- The
listfilters scanrecord.jsonfiles; no index by decision or by ref exists. - An
xdg:document digest changes when the document is edited, so coverage fails at the nextresolve.