From 11aebd581627a89062ce71d71e75b69501b3cd7c Mon Sep 17 00:00:00 2001 From: Jason Irish Date: Mon, 6 Jul 2026 14:22:04 -0500 Subject: [PATCH 1/3] docs: v0.6.1 - session-log fidelity, housekeeping, and polish (#8, #10, #11) Doc/skill batch from the v0.4.0 audit (docs/AUDIT-v0.4.0.md, P2). No hook behavior change. Issue #8: the session-log template gains a "What we tried (including what failed)" section (record the real evidence, not a summary - a failed approach is the most expensive thing for a future session to rediscover) and a Follows chain-link so a log can name its predecessor in the same work stream. Issue #10: a new README "Housekeeping" section documents what's safe to delete (old archived buffers, a resolved .capture-errors) vs. what isn't (logs/, HANDOFF.md, unarchived buffers) - documented convention, not automated tooling, matching the plugin's zero-infrastructure identity. The handoff skill now clears .capture-errors once its contents are surfaced in a session log. Issue #11 polish batch: handoff Phase 4.4 drops "(or delete)" for consumed buffers (archive-only removes an unguarded data-loss affordance); Phase 4.3 cites the actual native auto-memory layout with an inline frontmatter example; plugin.json keywords gain git-state/cross-harness/resume/onboarding; tests/run.sh's header now states it is the single source of truth for the assertion count, after prose counts drifted across releases before. Verified: unchanged 154-assertion suite plus shellcheck under both Homebrew and an apt-get install shellcheck Ubuntu container. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Q4iokjvAbBLgrRJYwCVtqb --- .claude-plugin/plugin.json | 4 +-- CHANGELOG.md | 37 ++++++++++++++++++++++++ README.md | 30 ++++++++++++++++++++ skills/throughline-handoff/SKILL.md | 44 +++++++++++++++++++++++++---- tests/run.sh | 7 +++++ 5 files changed, 115 insertions(+), 7 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index a6f75bf..09d072e 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "throughline", "description": "Continuous, state-aware session memory for Claude Code. Captures what you did and what is (commands, file changes, decisions, and live git/PR state), then hands it off with judgment at session wrap-up. Readable, committable artifacts; binds to Claude's native memory.", - "version": "0.6.0", + "version": "0.6.1", "author": { "name": "Dynamic Agency", "email": "support@dynamicagency.com" @@ -9,5 +9,5 @@ "homepage": "https://github.com/dynamic/throughline", "repository": "https://github.com/dynamic/throughline", "license": "MIT", - "keywords": ["memory", "handoff", "session", "context", "continuity", "compaction"] + "keywords": ["memory", "handoff", "session", "context", "continuity", "compaction", "git-state", "cross-harness", "resume", "onboarding"] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 6414c84..c7b16f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,43 @@ All notable changes to throughline are documented here. Format loosely follows [Keep a Changelog](https://keepachangelog.com/); this project uses semantic versioning. +## [0.6.1] + +Docs/skill polish batch from the v0.4.0 audit (docs/AUDIT-v0.4.0.md, P2, items +#8/#10/#11). No hook behavior change - verified by the unchanged +154-assertion suite plus shellcheck under both Homebrew and an +`apt-get install shellcheck` Ubuntu container. + +### Added +- **Issue #8** - the session-log template (`throughline-handoff` Phase 3) gains + a "What we tried (including what failed)" section, with guidance to record + real evidence (the actual command/error/number), not a summary - a failed + approach is the most expensive thing for a future session to rediscover from + scratch. A **Follows** line lets a log name its predecessor in the same work + stream, so a reader can walk the decision history log-to-log without + HANDOFF.md having to carry it. +- **Issue #10** - a new README "Housekeeping" section documents what's safe to + delete (old archived buffers, a resolved `.capture-errors`) versus what + isn't (`logs/`, `HANDOFF.md`, unarchived buffers) - deliberately a + documented convention, not automated tooling, matching the plugin's + zero-infrastructure identity. The handoff skill (Phase 4) now also clears + `.capture-errors` once its contents have been surfaced in a session log, + instead of leaving it to nag on every future onboard indefinitely. + +### Changed +- **Issue #11 polish batch**: the handoff skill's Phase 4.4 no longer offers + "(or delete)" for consumed buffers - archive-only removes an unguarded + data-loss affordance. Phase 4.3's memory-binding step now cites the actual + native auto-memory layout (`MEMORY.md` as a 200-line-truncated index, one + topic file per entry under `~/.claude/projects//memory/`) and inlines + a one-line frontmatter example, so an executing model can't produce a + malformed entry. `plugin.json` keywords gained `git-state`, + `cross-harness`, `resume`, `onboarding` - the prior list under-sold the + differentiators. `tests/run.sh`'s header now states it is the single + source of truth for the current assertion count (it prints its own total), + after prose counts drifted across releases before (71/83/88/95 at + different points). + ## [0.6.0] Issue #9 from the v0.4.0 audit (docs/AUDIT-v0.4.0.md, P2): inline post-compaction diff --git a/README.md b/README.md index ed327a7..c7ad905 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,36 @@ Gitignore both for whichever data dir you use: > `!/.claude/throughline/logs/`) or set `THROUGHLINE_DATA_DIR=.agent/handoff` so the > committed artifacts sit outside the ignored tree. +## Housekeeping + +Everything throughline writes grows without automatic bound — there is no +background cleanup process, deliberately, to keep the plugin's footprint at +"pure POSIX sh + jq, zero infrastructure." What's safe to clean up by hand, +and what isn't: + +**Safe to delete:** +- `buffer/archive/*.md` older than your last `throughline-consolidate` pass — + once a consolidation has mined a log for recurring lessons, an archived raw + buffer behind it has nothing left to give. As a simple rule of thumb, an + archived buffer older than ~90 days with no open question against it is safe + to remove. +- `.capture-errors`, once its contents have been surfaced in a session log and + cleared by the handoff skill (Phase 4) — it's a breadcrumb meant to be read + once, not a running log. + +**Not safe to delete:** +- `logs/` — these are the evidence trail. `throughline-consolidate` explicitly + never prunes them, and HANDOFF.md's own "Recent Session Logs" list only ever + points at the last 5, so older logs are already off the beaten path without + needing to be deleted. +- `HANDOFF.md` itself, obviously — it's the durable record. +- Any buffer still in `buffer/` (not yet archived) — it may be an in-progress or + unconsumed session; run a handoff first, which moves it to `archive/` once + distilled. + +There's no automated retention policy beyond this — clean up by hand on the +cadence above, or leave it; a growing `archive/` costs disk, not correctness. + ## Auto-handoff at wrap-up (optional reinforcement) The handoff skill is written to run proactively when the agent detects the session diff --git a/skills/throughline-handoff/SKILL.md b/skills/throughline-handoff/SKILL.md index a5e2a24..1a0f1e2 100644 --- a/skills/throughline-handoff/SKILL.md +++ b/skills/throughline-handoff/SKILL.md @@ -71,6 +71,7 @@ Create `DATA/logs/handoff-YYYY-MM-DD-HHMM.md` (local time; create `logs/` if nee ```markdown # Handoff: **Date:** **Session:** +**Follows:** [](handoff-YYYY-MM-DD-HHMM.md) ## Objective The big-picture goal of the session. @@ -79,6 +80,14 @@ The big-picture goal of the session. Distilled from the capture buffer + conversation: commands run, files changed, decisions made — with the *why*. +## What we tried (including what failed) +Approaches attempted and abandoned, with the REAL evidence — the actual command, +error text, or number that killed the approach, not a summary of it. A failed +approach is the most expensive thing for a future session to rediscover from +scratch; a summary like "tried caching, didn't work" gives a future session +nothing to avoid re-trying. Omit this section only if nothing was actually tried +and abandoned this session. + ## Progress ### Completed ### In progress ### Not started @@ -96,6 +105,11 @@ Ordered, specific — exact commands, paths, expected outcomes. Key paths, URLs, credential locations (names only). ``` +**Chain link:** if this session continues work a prior log already started (same +work stream, not just the same project), name that predecessor in the **Follows** +line above so a reader can walk the decision history log-to-log without HANDOFF.md +having to carry it. Omit the line entirely for a session that starts something new. + --- ## Phase 4: Update durable HANDOFF.md + memory binding @@ -107,12 +121,32 @@ Key paths, URLs, credential locations (names only). 3. **Memory binding (native system):** ask "did this session surface a durable fact worth pinning?" Types: a confirmed preference (`feedback`), a fact about the user/context (`user`), a project constraint/decision (`project`), a resource - pointer (`reference`). If yes, write it to the native memory dir - (`~/.claude/projects//memory/`) using the established frontmatter and - update `MEMORY.md`. This promotion is **curated** — never auto-dump the buffer - into memory. One entry per genuine insight; skip if nothing new. + pointer (`reference`). Native memory is two layers: `MEMORY.md` is an + always-loaded index (truncated past 200 lines, so every entry there must stay a + single short line), and each entry's full content lives in its own topic file + under `~/.claude/projects//memory/`, read on demand. If yes, write the + topic file with frontmatter shaped like this, then add its one-line pointer to + `MEMORY.md`: + ```markdown + --- + name: short-kebab-case-slug + description: one-line summary used to judge relevance in a future session + metadata: + type: feedback # or: user, project, reference + --- + ``` + This promotion is **curated** — never auto-dump the buffer into memory. One entry + per genuine insight; skip if nothing new. 4. **Consume the buffers:** move distilled `DATA/buffer/session-*.md` into - `DATA/buffer/archive/` (or delete) so they aren't re-processed next session. + `DATA/buffer/archive/` so they aren't re-processed next session. Archive only — + never delete; an archived buffer is the recovery path if a distillation later + turns out to have missed something. See "Housekeeping" in the README for when an + archived buffer is old enough to actually delete. +5. **Clear resolved breadcrumbs:** if `DATA/.capture-errors` exists and its contents + were surfaced above (as a Phase 2 "Resolved Issues" entry or in the session log), + clear the file now that it has been distilled — it exists to make a swallowed + capture failure visible exactly once, not to keep nagging on every future onboard + after it's already been read and acted on. --- diff --git a/tests/run.sh b/tests/run.sh index da14c1f..3255972 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -5,6 +5,13 @@ # and asserts on the resulting buffer / stdout. No network, no model, no deps # beyond jq + coreutils + git. Run: sh tests/run.sh (exit 0 = all passed). # +# This file is the single source of truth for the current assertion count - +# it prints its own total ("passed: N") on every run. Historical assertion +# counts have drifted in prose before (CHANGELOG/HANDOFF entries citing 71, +# 83, 88, 95... at different points, issue #11): if you cite a count in +# prose, anchor it to a specific version ("143 assertions as of v0.5.2") or +# just point here instead of hardcoding a number that will go stale. +# # Test fixtures legitimately contain literal markdown backticks and $ inside # single quotes, so SC2016 (no-expansion-in-single-quotes) is expected here. # shellcheck disable=SC2016 From c19e5b7a2c2cc84dfc9cd9a2d786a9fe32d88aaf Mon Sep 17 00:00:00 2001 From: Jason Irish Date: Mon, 6 Jul 2026 14:31:47 -0500 Subject: [PATCH 2/3] fix: address code review findings on v0.6.1 (frontmatter, em-dashes) Three findings from an independent review pass on the v0.6.1 diff: 1. CONFIRMED: the new memory-binding frontmatter example omitted node_type and originSessionId, both present in 100% of real memory topic files under ~/.claude/projects//memory/ (verified directly against every file in the harness). An agent following the template verbatim would have produced the exact schema-inconsistent entry the change claimed to prevent. Template now matches the observed real shape. 2/3. CONFIRMED: the new README Housekeeping section and SKILL.md additions used em-dashes, violating this user's global no-em-dash writing-style rule - in handoffs, a category the rule names explicitly. Replaced with commas, colons, periods, or spaced hyphens. Pre-existing em-dashes in SKILL.md content this PR didn't touch are left alone (out of scope). Verified: unchanged 154-assertion suite plus shellcheck under both Homebrew and an apt-get install shellcheck Ubuntu container. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Q4iokjvAbBLgrRJYwCVtqb --- CHANGELOG.md | 14 ++++++++++++++ README.md | 16 ++++++++-------- skills/throughline-handoff/SKILL.md | 12 +++++++----- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b16f7..6a51cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,20 @@ Docs/skill polish batch from the v0.4.0 audit (docs/AUDIT-v0.4.0.md, P2, items after prose counts drifted across releases before (71/83/88/95 at different points). +### Fixed (found during review, before merge) +- **The memory-binding frontmatter example didn't match reality**: every + actual memory topic file (`~/.claude/projects//memory/*.md`) carries + `node_type: memory` and `originSessionId` under `metadata`, both omitted + from the template this release added - so an agent following it verbatim + would have written a schema-inconsistent entry, the exact failure the + change claimed to prevent. Verified against every real memory file in the + harness (100% carried both fields); the template now matches. +- **Em-dashes in new content**: the new Housekeeping section (README) and + session-log/Phase-4 additions (`throughline-handoff` SKILL.md) used + em-dashes, violating this user's global no-em-dash writing-style rule - + in `handoffs`, a category the rule names explicitly. Replaced with commas, + colons, periods, or spaced hyphens per the rule. + ## [0.6.0] Issue #9 from the v0.4.0 audit (docs/AUDIT-v0.4.0.md, P2): inline post-compaction diff --git a/README.md b/README.md index c7ad905..6c200b7 100644 --- a/README.md +++ b/README.md @@ -186,33 +186,33 @@ Gitignore both for whichever data dir you use: ## Housekeeping -Everything throughline writes grows without automatic bound — there is no +Everything throughline writes grows without automatic bound: there is no background cleanup process, deliberately, to keep the plugin's footprint at "pure POSIX sh + jq, zero infrastructure." What's safe to clean up by hand, and what isn't: **Safe to delete:** -- `buffer/archive/*.md` older than your last `throughline-consolidate` pass — +- `buffer/archive/*.md` older than your last `throughline-consolidate` pass - once a consolidation has mined a log for recurring lessons, an archived raw buffer behind it has nothing left to give. As a simple rule of thumb, an archived buffer older than ~90 days with no open question against it is safe to remove. - `.capture-errors`, once its contents have been surfaced in a session log and - cleared by the handoff skill (Phase 4) — it's a breadcrumb meant to be read + cleared by the handoff skill (Phase 4): it's a breadcrumb meant to be read once, not a running log. **Not safe to delete:** -- `logs/` — these are the evidence trail. `throughline-consolidate` explicitly +- `logs/`: these are the evidence trail. `throughline-consolidate` explicitly never prunes them, and HANDOFF.md's own "Recent Session Logs" list only ever points at the last 5, so older logs are already off the beaten path without needing to be deleted. -- `HANDOFF.md` itself, obviously — it's the durable record. -- Any buffer still in `buffer/` (not yet archived) — it may be an in-progress or +- `HANDOFF.md` itself, obviously - it's the durable record. +- Any buffer still in `buffer/` (not yet archived) - it may be an in-progress or unconsumed session; run a handoff first, which moves it to `archive/` once distilled. -There's no automated retention policy beyond this — clean up by hand on the -cadence above, or leave it; a growing `archive/` costs disk, not correctness. +There's no automated retention policy beyond this: clean up by hand on the +cadence above, or leave it, a growing `archive/` costs disk, not correctness. ## Auto-handoff at wrap-up (optional reinforcement) diff --git a/skills/throughline-handoff/SKILL.md b/skills/throughline-handoff/SKILL.md index 1a0f1e2..8b5c8d0 100644 --- a/skills/throughline-handoff/SKILL.md +++ b/skills/throughline-handoff/SKILL.md @@ -81,7 +81,7 @@ Distilled from the capture buffer + conversation: commands run, files changed, decisions made — with the *why*. ## What we tried (including what failed) -Approaches attempted and abandoned, with the REAL evidence — the actual command, +Approaches attempted and abandoned, with the REAL evidence: the actual command, error text, or number that killed the approach, not a summary of it. A failed approach is the most expensive thing for a future session to rediscover from scratch; a summary like "tried caching, didn't work" gives a future session @@ -132,19 +132,21 @@ having to carry it. Omit the line entirely for a session that starts something n name: short-kebab-case-slug description: one-line summary used to judge relevance in a future session metadata: + node_type: memory type: feedback # or: user, project, reference + originSessionId: --- ``` - This promotion is **curated** — never auto-dump the buffer into memory. One entry + This promotion is **curated**: never auto-dump the buffer into memory. One entry per genuine insight; skip if nothing new. 4. **Consume the buffers:** move distilled `DATA/buffer/session-*.md` into - `DATA/buffer/archive/` so they aren't re-processed next session. Archive only — - never delete; an archived buffer is the recovery path if a distillation later + `DATA/buffer/archive/` so they aren't re-processed next session. Archive only, + never delete: an archived buffer is the recovery path if a distillation later turns out to have missed something. See "Housekeeping" in the README for when an archived buffer is old enough to actually delete. 5. **Clear resolved breadcrumbs:** if `DATA/.capture-errors` exists and its contents were surfaced above (as a Phase 2 "Resolved Issues" entry or in the session log), - clear the file now that it has been distilled — it exists to make a swallowed + clear the file now that it has been distilled - it exists to make a swallowed capture failure visible exactly once, not to keep nagging on every future onboard after it's already been read and acted on. From e85c19cc2d90daa626cffbf0a31930e328ef09e9 Mon Sep 17 00:00:00 2001 From: Jason Irish Date: Mon, 6 Jul 2026 14:33:33 -0500 Subject: [PATCH 3/3] chore: retrigger CI (prior push to this branch did not fire a workflow run)