Goal ledger
A project-local, git-tracked execution record for coding agents: crash recovery, handoff, branch isolation, and safe squash — portable across Codex, Claude Code, Antigravity, Gemini CLI, and Cline
npx -y skills add jpbaking/goal-ledger --skill goal-ledgerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Create and execute a durable, git-tracked Goal Ledger for multi-phase or long-running work: .goal-ledger/GOAL.md plus phase-NNNN.md files, plan and execution approval gates, an isolated goal branch recommendation, committed recovery markers, inter-agent handoff state, and optional safe squashing on acceptance. Use when work needs several distinct phases, may span sessions, needs crash recovery or handoff, or the user asks for a persistent goal, execution ledger, or durable plan. Sections 1-3 are the shared contract used by the goal-ledger-resume, goal-ledger-status, and goal-ledger-abandon skills.
SKILL.md
14.2 KB, as published. Nobody here has run it
Goal Ledger — prepare and execute a durable goal
Goal Ledger is a git-tracked execution record for one goal. It survives crashes, context compaction, session changes, and handoff to another agent. The files and Git state are authoritative; memory and conversation summaries are not.
Sections 1–3 are the shared contract used by every Goal Ledger skill.
1. Ledger location and lifecycle
- Location:
<project root>/.goal-ledger/. The project root owns the task's files and has its own repository or project manifest; never place the ledger at a multi-project workspace root. - Tracked state: never add
.goal-ledger/to.gitignore. Verify withgit check-ignore -v .goal-ledger/GOAL.md. Remove an exact Goal Ledger ignore entry; if a broader user-owned pattern is responsible, explain it and obtain approval before adding a narrow negation or changing that pattern. - Contents: exactly one
GOAL.mdplus onephase-NNNN.mdper phase. Keep phase files besideGOAL.md; another directory level adds no useful information. - One current ledger: never overwrite a goal whose status is not
completedorabandoned. Resume it or usegoal-ledger-abandon. - Completed history: keep the completed ledger in the final committed snapshot. A later goal may replace
.goal-ledger/only after its own plan is approved; the previous ledger remains recoverable from Git history. - Single writer: only the primary session updates ledger files. Subagents may perform bounded phase work, but the primary session records their findings and changes statuses.
- Delegation boundary: every subagent prompt must say:
Ignore .goal-ledger and all Goal Ledger skills. Follow only the task in this prompt; do not create, resume, update, or abandon the ledger.Include all task-local context the subagent needs. Do not delegate ledger bookkeeping, branch management, or framework commits. If you are a subagent, ignore the ledger and continue only the assigned prompt; an unfinished ledger is not a blocker for that delegated task.
2. File format and invariants
Use a stable Goal ID: YYYYMMDD-<short-kebab-slug>. If that ID already appears in repository history, append -2, -3, and so on. The recommended branch is goal/<goal-id>.
The GOAL.md mirror and sub-task vocabulary is exactly: [todo], [ongoing], [done], [skipped] — reason: <why>, and [needs-human] — reason: <question/error>. A phase file uses the same value without brackets on its Status: line. At most one phase and one sub-task may be ongoing.
GOAL.md:
# GOAL — <short title>
## Goal
- Goal ID: <stable ID>
- Outcome: <one sentence>
- Done when: <observable completion check>
- Goal status: drafting
- Goal status meaning: drafting | approved | executing | blocked-on-human | awaiting-acceptance | completed | abandoned
- Last completed phase: none
## Git
- Repository: yes | no
- Strategy: isolated-branch | current-branch | none
- Starting branch: <branch | "-">
- Work branch: <branch | "-">
- Baseline commit: <full immutable SHA | "-">
- Starting upstream at start: <ref>@<full SHA> | none | "-"
- Work upstream at start: <ref>@<full SHA> | none | "-"
## Phases
- [todo] phase-0001 — <title>
## Handoff
- Current position: planning
- Next action: approve the goal
- Last verified evidence: none
- Blockers: none
## Log
- created ledger with <N> phases
phase-NNNN.md:
# phase-NNNN — <title>
- Status: todo
- Depends on: none
- Goal: <one line>
- Done when: <runnable or observable check>
## Sub-tasks
1. [todo] <action> — done when: <check>
## Log
- (append-only, one line per event)
Invariants:
- The phase file's
Status:is authoritative; the matching bracketed line inGOAL.mdmirrors it. Repair mismatches in favor of the phase file. Last completed phaseidentifies the phase most recently completed in execution order, which may differ from numeric phase order; it must name a phase whose status isdone, ornonewhen no phase is done.- Every phase and sub-task has an observable "done when" check.
- Use 2–7 phases with 2–7 sub-tasks each. Add new numbered phases or sub-tasks; never renumber existing ones.
- A skipped phase satisfies dependencies only after verifying that its outputs are unnecessary or updating future todo phases accordingly. Record the reason in both the phase status and logs. Skip a whole phase only with explicit user approval or when verified evidence makes it unnecessary.
- Update
Handoffwhenever execution changes position, evidence, next action, or blockers. It must let a new agent continue without the conversation. - Append important events and decisions to logs. Never rewrite history to make a failed attempt disappear.
- Do not store a moving
HEADhash inGOAL.md. The immutable baseline and Git history are authoritative; a commit cannot reliably record its own hash. - During drafting, set only
Repository; useStrategy: noneand-for every other Git field. Gate B replaces those placeholders from live Git state immediately before the first ledger commit.
3. Git contract
If Repository: no, use Strategy: none, keep Git fields as -, skip every Git operation, and never initialize a repository automatically.
For a repository:
- Clean start: before preparing Git, classify
git status --porcelain. Changes inside.goal-ledger/are expected planning state. Any other pre-existing change must be resolved by the user: commit it, explicitly authorize a baseline snapshot commit, stash it, or stop. Never absorb unrelated work into the goal. - Immutable baseline: record the full
HEADbefore the first Goal Ledger commit. Every goal commit lives strictly after this baseline. - Unborn repository: if the repository has no
HEADcommit, stop at Gate B. Ask the user to create an initial commit or explicitly authorize a baseline snapshot commit; never invent a zero SHA, silently initialize history, or continue without an immutable baseline. - Recommended isolated branch: recommend
goal/<goal-id>. Ask before creating or switching branches. Record the original branch asStarting branchand the goal branch asWork branch. From a detachedHEAD, require creation of a named goal branch or stop for user direction;current-branchis not valid without a branch. - Existing goal branch: if the proposed work branch already exists, inspect it before switching. Reuse it only when it belongs to the same unfinished Goal ID and its history is consistent with the baseline. Otherwise ask the user to choose it deliberately or select a new suffixed Goal ID and branch; never reset or overwrite it.
- Current-branch fallback: if the user declines a goal branch, warn that shared or interleaved history can make automatic squashing unavailable. Record both branch fields as the current branch and use
Strategy: current-branch. - Upstream snapshots: before switching, record the starting branch's upstream ref and full SHA without fetching, or
none. After choosing the work branch, record its upstream the same way. Forcurrent-branch, the two snapshots are identical; for a new isolated branch, the work upstream is normallynone. - Commit identity: every framework-created commit after the baseline has a
Goal-ID: <goal-id>trailer. Phase commits also haveGoal-Phase: phase-NNNN. Git history, not hashes copied into the ledger, is the commit ledger. - Committed recovery marker: before doing phase work, set the phase file to
Status: ongoing, set itsGOAL.mdmirror to[ongoing], update Handoff, and commit the ledger asgoal-ledger(begin): phase-NNNN — <title>. A clean tree after that commit means no work started; later dirty files identify interrupted work. - Phase close: update the phase, mirror,
Last completed phase, Handoff, and logs; inspect the worktree; stage only goal-owned changes; then commit asgoal-ledger(done): phase-NNNN — <title>orgoal-ledger(blocked): phase-NNNN — <title>. - Never automatically: push, force-push, delete a branch, amend, rebase, hard-reset, or touch commits at or before the baseline.
Optional squash on acceptance
Offer squashing only after the user accepts the finished result. Before offering, require all of these:
- The worktree is clean.
- The current branch equals
Work branch. - Every commit in
<baseline>..HEADcarries the matching Goal ID. - The range has no merge commit or foreign/interleaved commit.
- No goal commit is reachable from either recorded upstream or any locally known remote-tracking ref. If the goal branch was published for handoff, keep its commits and recommend a squash merge at integration time instead of rewriting the branch. If publication is uncertain, do not automate the squash.
- For
current-branch, its upstream ref still points to the SHA recorded at Gate B. If that ref advanced, rewound, or diverged, do not automate the squash even when the local goal range itself contains no foreign commit.
If any check fails, keep the commits and explain why. If all pass and the user explicitly chooses squash: soft-reset to the baseline, set the goal status to completed, update Handoff to completed with no next action, append the acceptance/squash event, retain the entire .goal-ledger/, stage the accepted snapshot, and create one meaningful commit with the Goal ID trailer. If the user declines squash: make the same terminal ledger updates and create a final goal-ledger(complete): <title> commit. The completed ledger must remain in either result.
4. Draft the ledger
- Inspect the project and establish the outcome, overall "done when", approach, phases, dependencies, and checks.
- Inspect Git state before writing so pre-existing changes can be distinguished from ledger files later.
- If no ledger exists, create
.goal-ledger/GOAL.mdwith statusdraftingand every phase file. Do not change application code. - If an older ledger is
completedorabandoned, preserve it until the new plan is approved. Draft the proposed replacement in the conversation or a temporary location outside the project, then write it into.goal-ledger/only after Gate A. The new goal's first commit records the replacement, leaving the previous ledger in Git history.
Run the bundled scripts/validate_goal_ledger.py --root <project root> --no-git after drafting. If Python 3 is unavailable, check every invariant in section 2 manually and report that deterministic validation was unavailable.
5. Approval and Git preparation gates
Gate A — approve the goal: show Outcome, Done when, and the one-line phase list. Ask for approval. Apply feedback to the ledger and repeat until approved, then set status approved and update Handoff.
Gate B — choose and prepare the Git strategy: resolve non-ledger dirty changes first and verify the ledger is not ignored. Strongly recommend the isolated goal branch and explain that it makes recovery, handoff, abandonment, and optional squashing deterministic. Ask permission to create/switch to it. If declined, show the current-branch warning and obtain explicit confirmation. Record all Git metadata, then commit the approved ledger as goal-ledger(approve): <title> with the Goal ID trailer.
Gate C — execute: ask whether to start execution. On yes, enter the loop. A single clear response such as "approved, create the branch, and go" may satisfy all gates. The original task request never pre-approves an unseen ledger or a branch change.
6. Execution loop
- Select the first
[todo]phase whose dependencies are all[done]or safely[skipped]under section 2. - Set Goal status
executing; set the phase file toStatus: ongoingand itsGOAL.mdmirror to[ongoing]; update Handoff and logs; create the committed recovery marker from section 3. - For each sub-task: mark
[ongoing]before work; perform it; run its check; immediately mark[done],[skipped] — reason:, or after two failed attempts[needs-human] — reason:; update the phase Log and Handoff. - Run the phase-level check. If it fails, add a fix-up sub-task. After two failed fix-up rounds, mark the phase
needs-human. - Review the overall Goal and remaining phases. Amend only future
[todo]phases, logging why. Skip an entire phase only under the skip rule in section 2. - Close and commit the phase under section 3. If nothing actionable remains, include Goal status
blocked-on-humanin that close commit (or create a blocked-state commit if no phase was closed), then stop. - At a phase boundary, compact context if useful, then re-anchor from
GOAL.md, the next phase file, and Git. After uncertain or interrupted state, usegoal-ledger-resume. - Continue without asking between phases. When every phase is terminal and none needs human, set Goal status
awaiting-acceptance, update Handoff, include that state in the final phase commit, report, and ask the user to review the result. - After acceptance, apply the optional squash procedure or create the completion commit. Do not delete the ledger.
Run the bundled validator without --no-git after reconciliation, before each phase close, and before acceptance. Treat errors as blockers; record warnings that affect handoff or squash safety. If Python 3 is unavailable, perform the same checks manually and say so in the report.
7. Report when execution stops
Goal: <title> — <awaiting-acceptance | blocked-on-human>
Goal ID: <id>
Strategy: <isolated-branch | current-branch | none> on <work branch>
Phases: <X> done, <Y> skipped, <Z> needs-human, <W> todo
Commits: <N> matching goal commits since <baseline> (omit without Git)
Needs you:
- phase-NNNN sub-task N: <exact question or error> (omit if none)