ship-log
Skill1 starsChanged 28 days agoMITView on GitHub
Use when work is finished and should be logged — append a completed-work entry to the private project ledger (.trust/progress.txt) after any file change, task, or fix, before starting the next item.
In this repository37 other files it gives its agents.
- AGENTS.mdAGENTS.md
- plugin/AGENTS.mdAGENTS.md
- breakpointSkill
- expect-failSkill
- fork-itSkill
- make-it-soSkill
- no-thanksSkill
- receiptsSkill
- roast-my-codeSkill
- root-causeSkill
- save-asSkill
- scribeSkill
- setup-tnaSkill
- ship-logSkill
- breakpointSkill
- expect-failSkill
- fork-itSkill
- make-it-soSkill
- no-thanksSkill
- receiptsSkill
- roast-my-codeSkill
- root-causeSkill
- save-asSkill
- scribeSkill
- setup-tnaSkill
- ship-logSkill
- no-thanksSkill
- receiptsSkill
- breakpointSkill
- expect-failSkill
- fork-itSkill
- make-it-soSkill
- roast-my-codeSkill
- root-causeSkill
- save-asSkill
- scribeSkill
- setup-tnaSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 6 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Every completed unit of work gets a ledger entry — before starting the next one.
- Distinctive: line 16
After finishing a file change, refactor, task, or bug fix
- Distinctive: line 17
After every code change — no exceptions
- Distinctive: line 18
Never for work that is still pending approval or waiting on user decisions
- Distinctive: line 24
Never overwrite or delete old logs — this is the project's work history.
- Distinctive: line 82
Rotation trims it in lockstep: when ledger entries rotate to the archive, their index lines rotate with them (the archive keeps full text.
- Very specific: line 90
When the live ledger passes ~100 KB or holds entries older than ~30 days, rotate: append the older completed entries — anything with an …
- Very specific: line 108
Before a worktree's ticket closes, append a bounded handoff to the canonical ledger: ticket ID + branch/commit, files changed, verification …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Ship Log
Every completed unit of work gets a ledger entry — before starting the next one. A log that dies with the conversation was a decision made in secret: conversation memory does not survive compaction, but the ledger does.
What it does
- Append a log of completed work to the project ledger at the private, gitignored path (default
.trust/progress.txt).
When to use it
- After finishing a file change, refactor, task, or bug fix
- After every code change — no exceptions
- Never for work that is still pending approval or waiting on user decisions
How it works
- Resolve the ledger path:
<project>/.trust/progress.txtby default (create the.trust/dir and file on first use). Read it to see existing logs. - Append a new entry at the bottom of the file.
- Never overwrite or delete old logs — this is the project's work history.
- Confirm the ledger path is gitignored before relying on it as private.
- Append the entry's one-line summary to the recovery index at
.trust/index.md(see Recovery index).
Log Format
## <YYYY-MM-DD>
### Session Summary - <short title>
- <Modified/Created/Fixed> '<path/file>' - <short description of the change>
- Loaded: <MANDATORY skill used, e.g. "expect-fail"; omit only for work outside all three domains>
- Context confirmed: <required for fixes driven by owner visual feedback — restate display context (desktop/mobile), the exact block, and the symptom before the fix; audited by scripts/ledger-audit.mjs M3>
- Verification: <evidence, e.g. tsc EXIT 0; vitest 42/42 pass>
- Next: <the single open action, or "none">
- Lesson: <required when the entry closes a repair — root_cause = <the specific broken feature> | correction = <one imperative sentence>; written here AND dated as the entry is, so the corrective tier can be matched to the repair (audited by scripts/ledger-audit.mjs M8)>
- Recipe: task_type = <type of task, e.g. "add-validation"> | steps = <2-8 generalizable steps, no task-specific entities>
- Tags: <2-5 short tags, comma-separated, e.g. "evals, harness, fail-first">
### Self-Review (4 Dimensions)
- [x] **Readability**: descriptive names, comments explain "why" not "what", no unexplained magic numbers
- [x] **Maintainability**: clear boundaries, no hardcoded values that belong in config, module structure contained
- [x] **Performance**: no N+1 in loops, no heavy synchronous work in render path
- [x] **Security**: no secrets in source, user input validated, no sensitive data in logsThe Loaded: and Next: lines are mandatory, and their absence is a finding. Both were prose contracts with mechanical readers before the template taught them: a domain-relevant entry with no Loaded: line is the silent-drop signal (scripts/ledger-audit.mjs M1, AGENTS.md §2), and an entry with no Next: line strands the next session (scripts/ledger-audit.mjs M7, docs/chat-receipt.md rule 4). The template is the writer's surface — when the template dropped these lines, entries written from it inherited the omission and the audit reported gaps for a format no one was taught. The ledger audit (scripts/ledger-audit.mjs) reports the template's missing lines, so the omission cannot silently return.
A repair entry carries its lesson inline, in the documented dated form. When the entry closes a repair (root-cause / done-claim work), the Lesson: line belongs in the entry, dated as the entry is — the corrective tier's writer (.trust/lessons.md) and its reader (scripts/ledger-audit.mjs M8) are matched by that date. The tier itself has a REQUIRED shape: one Lesson: root_cause = … | correction = … [YYYY-MM-DD] line per lesson. A tier of undated prose bullets holds the knowledge and loses the link — the audit reports it once as a lesson-format finding, because a tier that cannot be matched to the repair it taught cannot be fetched by the session that needs it (measured on a real adopter ledger, 2026-09-29: 66 lessons, 0 dated, 0 in the documented form). A repair whose lesson was never recorded is a finding, not a style choice.
Exit codes are not progress evidence. The writer contract says every unit closes with what changed; a repair unit closes with what was LEARNED and is therefore complete only when its Lesson: line is written together with the fix — not in a later session, where the context that made the lesson writable is gone (2026-09-29: a run's own output showed hook exit 1, i.e. no usable evidence, and the ledger entry had to be withdrawn and rewritten).
The date header is mandatory and load-bearing. Every entry opens with a ## <YYYY-MM-DD> date header — same date as the entry's index line. The ledger audit (scripts/ledger-audit.mjs) and the corrective-tier grace check (scripts/corrective-tier.mjs) attach a date to each entry from that header; an entry without one is reported as an unprovable coverage gap, not audited. The date lives in the ledger (self-contained), the .trust/index.md one-liner stays the recovery shortcut — the index is not the date authority. The invariant is enforced mechanically by the ledger audit (scripts/ledger-audit.mjs), so it cannot regress to a blind "clean" silently.
Mark [x] when checked, or [ ] + a one-line reason when skipped. Never skip silently. The four checkboxes compose into the verdict: the entry is loggable only when every dimension is answered — all [x], or a [ ] that carries its one-line reason. A self-review with any unanswered dimension is a claim, not a record.
Recipes (workflow memory)
The Recipe: line mines the completed chain into a reusable prior: task_type (a category like "add-validation" — no project entities) + 2-8 generalizable steps that would apply to the same task type in any project (no task-specific names). Append each recipe to the project's private .trust/recipes.md (create on first entry, one ## <task_type> section per recipe). Recipes accumulate the process data the ledger can't: the ledger is chronological, recipes are retrievable by task type. The lookup is grep on the task type — the markdown-native recall (AGENTS.md §8 lookup ladder).
The entry carries the smallest set of information required to continue correctly — the next session inherits the state of the work, not a retelling of the conversation.
Rulings
Any architecture/scope decision the agent made on its own (not a user order) is recorded. To keep this alive instead of silently dead, the lightweight form is the default: a Ruling: fragment on the entry's own lines — Ruling: <decision> — <why> — is enough when the cost of being wrong is obvious or small. Use the full three-part form below only for weighty calls, and record it at the time it's made, inside the entry:
Ruling: <decision> — <why> — <cost if wrong>A ruling recorded in conversation but absent from the ledger was made in secret — the ledger line is what makes it count. When a ruling must outlive one developer (a team repo, a shared decision), it is promoted explicitly — with the user's sign-off — to a tracked artifact: an ADR, a glossary term, a tracker ticket, per the memory-modes doctrine in docs/design.md. Never publish the private ledger itself.
Recovery index
Recovery after compaction or a fresh session must not require reading every full entry. The ledger keeps a companion index at .trust/index.md (gitignored like the ledger, created on first entry):
- One line per entry:
- <YYYY-MM-DD> <open|closed> - <short title>— the same title as the ledger entry's### Session Summaryheading, dated, with its status (an entry whoseNext:is not "none" is open). - Index-first recovery: on resume, read the index first to see what was done and what is still open, then read only the specific ledger entries that matter. The index answers "where are we?"; the ledger answers "how exactly?".
- Rotation trims it in lockstep: when ledger entries rotate to the archive, their index lines rotate with them (the archive keeps full text; the index keeps only live entries).
The index is redundant by design — it can be rebuilt from the ledger at any time — but redundancy is what makes recovery cheap: a one-line scan instead of a full-ledger read. The ledger audit (scripts/ledger-audit.mjs) mechanically guards this contract's markers.
Rotation (keeping recovery cheap)
The recovery rule ("re-read the ledger") reads the whole live ledger — so the live ledger must stay small enough that the read is cheap. Append-only means never delete history, not keep it all in one hot file:
- When the live ledger passes ~100 KB or holds entries older than ~30 days, rotate: append the older completed entries — anything with an open
Next:stays live — to.trust/archive/YYYY-MM.txt, and replace them in the live file with a one-line pointer:### Archive - <month>: N entries, see .trust/archive/2026-08.txt. - The pointer section keeps one line per rotated entry (title + Verification + commit ref, oldest first); full text lives in the archive.
- Archives are append-only too and are read only on demand ("when did we fix X?") — routine recovery reads the live file only.
- Log the rotation itself as an entry (
Recipe: task_type = ledger-rotation) so the act is part of the history it reshaped.
Reflection at rotation
Rotation is the one moment the whole ledger gets read — so it is where reflection belongs. While moving entries to the archive, scan the older entries for recurring patterns: the same lesson hit twice, the same kind of verification skipped, the same tool failing the same way. yith-archive calls this a reflection pass (mem::patterns); here it is a bounded scan, not a pipeline:
- For each recurring pattern found (2+ independent entries, not the same bug retold), prepare a candidate rule line: what recurred, the evidence (entry dates + tags), and the proposed 1-3 line rule for the router.
- Candidates go to the user — recurring findings are rule-inheritance candidates (
docs/rule-inheritance.md), and rule entry is gated and user-decided. The agent never auto-lands a router rule from its own reflection. - Record the pass itself in the rotation entry (
Tags: rotation, reflection), listing candidates surfaced and the user's decision on each. A pass that finds nothing says so — silence is not a scan.
Canonical ledger & worktree handoff
Gitignored files are per-worktree: a ledger written inside a git worktree dies with git worktree remove (proven empirically — a fresh worktree contains no .trust/ at all). Since fork-it gives every parallel writer its own worktree, a worktree-local ledger is provisional, never "the project ledger":
- The canonical ledger is the coordinating checkout's
.trust/progress.txt— the same directory as its lessons and recipes companions. Serial work is unchanged — there, the project path IS canonical. - Before a worktree's ticket closes, append a bounded handoff to the canonical ledger: ticket ID + branch/commit, files changed, verification receipts (commands + exit results), rulings, self-review verdict, and the open
Next:line. Handoff first, then worktree removal — that order is the contract. - Canonical path unreachable ⇒ the ticket is not closed: keep the provisional ledger alive and report the blocked handoff. A memory that dies with its worktree is the decision made in secret this skill exists to prevent.
- Shared research notes (
fork-it) follow the same rule: write to the canonical.trust/, outside every worktree, so all writers read one copy.
Provisional logs remain useful mid-ticket (crash recovery inside the worktree); they are simply not durable. Durable = canonical. The ledger audit (scripts/ledger-audit.mjs) mechanically guards this contract's markers.
Why append-only
The ledger is the anti-compaction mechanism: after a long session is compacted or a fresh session starts, reading the ledger restores the full picture. Deleting old entries destroys the only memory that survives. Keeping it under a gitignored path (.trust/) means the work history stays private even as the repository is shared. Rotation serves the same invariant — it moves entries between files, it never drops one.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

