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, blocker, 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 <id>
python3 skills/wheypoint/scripts/wheypoint.pyz validate < intent.json
python3 skills/wheypoint/scripts/wheypoint.pyz checkpoint [--compacted <proof.json>] < intent.json
python3 skills/wheypoint/scripts/wheypoint.pyz schema checkpoint-intent
python3 skills/wheypoint/scripts/wheypoint.pyz resolve --ref <absolute-path | work-id | slug>
python3 skills/wheypoint/scripts/wheypoint.pyz lint <projection-path>
python3 skills/wheypoint/scripts/wheypoint.pyz list
python3 skills/wheypoint/scripts/wheypoint.pyz log --work-id <id>

resolve, lint, 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. The parent delegates persistence as one structured checkpoint task to this capability. Run validate before checkpoint; workers never invoke either command at a hard limit. Phase skills use their own wheypoint-resolve --ref <slug> command for resolution. The command returns authoritative, not-found, legacy, gated, ambiguous, or error. Use authoritative working_context as the first batched tilth_read; follow references/delta-contract.md for all outcomes and findings. phase-artifact is fallback context, and the handoff parser exposes its phase_slug.

  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 for the work id; a first checkpoint binds the genesis sentinel itself.
  4. After a compaction, rehydrate first and pass a proof with --compacted.
  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 or blocker entry.
  9. Record a parked fork in decision_dossier with its options, evidence, and 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 and fix every named problem.
  13. Checkpoint. Run checkpoint.
  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 or next: cut 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 dossier fork for each gating entry.
  • It derives every identifier, digest, and revision.

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 | cut | 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, the dossier, and tasks. The projection is never the authority; never edit it and never resume from it by hand.

  • mold, cut, 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 references/parallel-handoffs.md.
  • hold: restore orientation and wait for instructions.
  • done: the work is complete; the checkpoint is a record, not a baton.
  • A missing next: makes the handoff malformed; use hold when no action follows. Derive next: and status: from the open questions and blockers, 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>). From the repository run /cheese --continue <slug>; from elsewhere run /cheese --continue <absolute-repo-path>/.cheese/notes/<slug>.md.

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
handoff Render, parse, and dispatch-split handoff preambles render, parse, dispatch
lint Lint a generated projection against the record
list List every work item under the corpus root
log Walk the revisions of one work id, oldest first
resolve Resolve a slug, 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 by the shared CLI as ERROR: <message> instead. A successful write prints wheypoint: revision work_id=<id> revision_id=<id> revision_number=<n> retried=<bool>. A stale-parent retry prints one wheypoint: retry ... line and one wheypoint: retry outcome=... line. An unexpected failure always prints a traceback to stderr; set EASY_CHEESE_DEBUG or CHEESE_DEBUG to add one to deliberate refusals as well.

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.

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 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},
{"kind": "blocker", "summary": "Staging is down.", "blocks_continuation": true}
],
"decision_dossier": [
{"fork": "Ceiling or jitter first",
"options": [{"option": "ceiling", "evidence": ["src/auth/retry.py:88"], "breaks": "burst callers"}],
"prior_leaning": "ceiling"}
],
"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.
  • next accepts mold, cut, 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 or cut need a path.
  • entries holds ProposedEntry values of kind decision, question, blocker, or directive.
  • Each entry has {kind, summary, rationale?, quote?, blocks_continuation}.
  • Only a question or a blocker 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.
  • decision_dossier holds forks {fork, options: [{option, evidence, breaks}], prior_leaning}.
  • A fork may describe any active question; every gating entry needs a covering fork.
  • artifact_links holds {path, covers_entry_ids?}; the runtime computes the digest and pins the revision.
  • A link replaces the carried link with the same path; links are a set keyed by path.
  • remove_artifact_links names carried paths to drop; an unknown path is refused.
  • An empty artifact_links or remove_artifact_links list is refused.
  • 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 pins the revision the intent was written against; omit it to bind the current revision.
  • session holds optional {harness, session_id, captured_at}.
  • Omission carries data forward; null means unchanged.
  • An explicit empty working_context or decision_dossier replaces the carried value.
  • Identifiers match [a-z0-9][a-z0-9._-]{0,63}.
  • Text fields contain at most 2000 characters; lists at most 64 items.
  • 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 changed intent against a superseded parent is refused as stale.

After a context compaction, rehydrate with show, then pass --compacted <proof.json>.

The proof is a CompactionRecord: {rehydrated_from_revision_id, rehydrated_record_digest, reconciled_entry_ids}.

rehydrated_from_revision_id must equal the current revision and rehydrated_record_digest its record digest.

reconciled_entry_ids must include every protected entry in the record.

The runtime derives prior_compaction_revision_id from stored receipts and refuses a supplied value.

Every command prints exactly one JSON object, on one line, to stdout. A success reply is {"ok": true, "command": "<name>", ...fields}. A failure reply is {"ok": false, "command": "<name>", "error": {"code": "...", "message": "...", ...extra}}.

  • checkpoint returns note_path, replayed, work_id, revision_id, revision_number, parent_revision_id, status, durability, projection_path, record, revision, markdown.
  • 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, detail.
  • show returns work_id, status, revision_id, revision_number, record.
  • lint returns path, clean, findings, projection.
  • list returns corpus_root, items, and lines.
  • 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.

Exit 0 means the command succeeded; the reply carries the command’s own fields. Exit 1 means the command refused the request; the reply carries error.code and error.message. Exit 2 means the command-line usage was wrong, before any command ran. Exit 3 means an unexpected internal error; error.code is internal-error and a Python traceback goes to stderr, never into the JSON.

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.
  • invalid-intent: the intent payload failed schema or delta validation.
  • secret-pattern: a field looked like a credential.
  • record-unreadable: the work’s record exists but could not be parsed.
  • compaction-proof-unreadable: the --compacted proof file could not be read or parsed as JSON.
  • invalid-compaction-proof: the --compacted proof failed schema validation.
  • genesis-conflict: a genesis commit collided with an existing record.
  • stale-parent: the intent’s parent revision has moved on.
  • 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.
  • internal-error: an unexpected exception, not a refusal, reached main.

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.

Press corrective work remains continue: press-corrective-cook, not a global Press-to-Cook dispatch.

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.

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.