Skip to content

feat!: replace SESSION.md + session skills with automatic SessionStart recap hook (v3.0.0)#97

Merged
agaete merged 16 commits into
developfrom
feature/session-recap-hook
Jun 10, 2026
Merged

feat!: replace SESSION.md + session skills with automatic SessionStart recap hook (v3.0.0)#97
agaete merged 16 commits into
developfrom
feature/session-recap-hook

Conversation

@agaete

@agaete agaete commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces Guild's ephemeral session layer (SESSION.md + the /session-start and /session-end skills) with a single deterministic SessionStart hook that injects a brief recap of the previous session automatically — no manual ritual, no file to go stale.

This removes the clearest remaining "reimplement the platform" violation: SESSION.md duplicated continuity that /resume and claude --continue now provide natively, and it only stayed current if the user remembered to run /session-end. The durable-memory layer (Claude Code native memory/*.md) is unchanged — only the ephemeral layer is removed.

⚠️ BREAKING (v3.0.0) — removes the /session-start and /session-end slash commands and the SESSION.md file. Skills count 10 → 8.

How it works

On source == "startup", the hook finds the previous session's transcript .jsonl (most-recent mtime, excluding the current session id) and injects:

Previous session (<title>, branch <branch>, ~2 hours ago):
  Last request: "<last real user prompt>"
  • Stable signal is primary — last real user prompt + gitBranch + relative time, all from documented-shape transcript lines. The auto-generated session title is enhancement-only.
  • Undocumented format is quarantined — all field-name knowledge lives in transcript-recap.mjs. (We found the title field already drifted ai-titlecustom-title within one week, so it must never be load-bearing.)
  • Never disrupts startup — any error / missing dir / malformed JSON / no-previous-session → exit 0, emit nothing. Read-only, plain stdout, transcript read bounded to the last 256 KB so cost is independent of file size.

Changes

Added

  • src/hooks/transcript-recap.mjs (pure parser), src/hooks/session-recap.mjs (IO shell)
  • hooks/hooks.json — plugin SessionStart hook manifest (matcher: "startup", timeout: 10)
  • 62 tests (incl. spawned end-to-end + all the never-disrupt edge cases)

Removed

  • SESSION.md, the /session-start + /session-end skills, generateSessionMd()
  • All SESSION.md references across commands, agent templates, skill bodies, docs

Docs / release

  • Version 2.1.1 → 3.0.0 (package.json, plugin.json, lock)
  • CHANGELOG [3.0.0] entry with migration note; README / CONTRIBUTING / landing pages updated

Migration

  1. Delete SESSION.md from your project root — it is no longer used or created.
  2. Durable learnings in Claude Code memory are preserved — no action needed.
  3. For deep recovery of a specific past session, use Claude Code's native /resume.

Testing

npm test 302 passed · npm run lint 0 errors · guild eval 29/29.

Provenance: built through Guild's own /build-feature pipeline (advisor → tech-lead → developer → reviewer → QA). Review caught and fixed a cardinal-rule bug — a non-functional self-abort timer that could OOM-crash on a huge transcript (now bounded-read).

Not yet validated: live plugin install (confirming ${CLAUDE_PLUGIN_ROOT} resolves and the hook fires on a real startup). Recommended before tagging v3.0.0.

🤖 Generated with Claude Code

agaete and others added 16 commits June 3, 2026 23:33
Pure JSONL transcript parser that extracts stable session signals
(branch, timestamp, last real user prompt) and optional enhancement
fields (title). buildRecap returns useful output even when undocumented
fields are absent (C2 floor). All undocumented field names quarantined
in this file only (C1). 37 tests covering all AC1.* criteria.
Thin IO shell that reads stdin JSON from Claude Code SessionStart hook,
finds the previous transcript via max-mtime selection, and prints a
recap to stdout. Entire main() body wrapped in try/catch — exits 0 on
any error, emits nothing. 20 tests covering malformed JSON, empty dirs,
only-current-session, permission errors, source!=="startup", and happy
path (AC2.1-2.4).
Manifest file at repo root hooks/ that registers a SessionStart hook
with startup matcher, command via CLAUDE_PLUGIN_ROOT env var, and
10s timeout. Tests assert valid JSON structure, correct matcher/type/
timeout values, and that the referenced session-recap.mjs exists (AC3.1,
AC3.2).
…(Task 4)

- Remove generateSessionMd export entirely
- generateClaudeMd: drop "Read SESSION.md..." framework line, remove
  "Update SESSION.md" global rule, change "CLAUDE.md and SESSION.md
  changes" → "CLAUDE.md changes", remove /session-start + /session-end
  from Available skills
- Update generators.test.js: remove generateSessionMd import, remove
  all generateSessionMd describe block (5 tests), update session-skills
  and framework assertions
Remove generateSessionMd import, spinner message, and call from init.js.
Update success message to drop SESSION.md. Update init.test.js to
reflect that SESSION.md is no longer generated, adjust skill count
lower bound, and rewrite session-start assertion.
- status.js: remove "Active session" block that read SESSION.md
- doctor.js: remove SESSION.md existence check
- files.js: remove readSessionMd() (now unused)
- workspace.js: remove sibling SESSION.md read from collectMemberContext
- doctor.test.js: update fixtures to not create SESSION.md
- workspace.test.js: update test to not expect **Current task:** from SESSION.md
…(Task 7)

- Remove src/templates/skills/session-start/ and session-end/ entirely
- Remove .claude/skills/session-start/ and session-end/ (active copies)
- files.test.js: update skill count 10→8, remove session-start/end from
  expected skills, assert they are NOT present
- trigger-matcher/trigger-runner tests: rewrite 'Saves current state to
  SESSION.md' fixture description to neutral text
Agent templates (6): "Read CLAUDE.md and SESSION.md" → "Read CLAUDE.md"
build-feature SKILL.md: remove 3 SESSION.md write-points, keep wip:
  checkpoints; update completion step intent
council SKILL.md: remove SESSION.md reads, decision logging, replace
  "SESSION.md-only logging" with "summarize in chat"
qa-cycle SKILL.md: remove "Read SESSION.md" and "Update SESSION.md"
guild-specialize SKILL.md: remove SESSION.md from read step, replace
  /session-start → /resume hints
new-agent.js: drop SESSION.md from scaffold behavioral rule
Sync active .claude/skills/ for affected skills
Ensures hook files are included in npm package distribution.
The !src/**/__tests__/ glob already excludes test files from hooks.
BREAKING CHANGE: /session-start, /session-end, and SESSION.md removed.
Documents migration path and explains the improvement over manual skill
invocations. Skills count updated 10→8.
…Task 11)

README: skills table 10→8 (remove session-start/end rows), replace
  Session Continuity section with automatic hook description, update
  "All 10" → "All 8", add automatic recap note in How Guild Solves It
CONTRIBUTING.md: "10 skills" → "8 skills", remove session-start/end
plugin.json: update description per C5 — mention "automatic
  previous-session recap on startup", keep "session" keyword
…tests

- eslint.config.js: add setTimeout/clearTimeout to globals (Node.js builtins
  not explicitly declared in flat config)
- session-recap.test.js: remove unused mkdirSync/chmodSync imports and
  stale tempDir variable declaration
…uard (W1/W2/S1)

W1: replace full-file readFileSync with bounded tail read (MAX_TAIL_BYTES=256KB)
using openSync/readSync/closeSync so cost is O(constant) regardless of file size.
Adds large-file test asserting correct recap from tail + sub-second completion.
Also adds Buffer to ESLint globals (required by the new Buffer.allocUnsafe call).

W2: remove misleading process.cwd() fallback when transcript_path is absent.
Without transcript_path the real ~/.claude/projects/<encoded>/ dir is unknowable;
now exits 0 immediately. Adds a spawned-process test for this path.

S1 (optional): replace name/path-coupled run-guard with realpathSync comparison,
with a catch-fallback to preserve existing behavior if realpath fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…est (W3)

The session-end skill no longer exists. Replace the fixture entry with 'debug'
so no deleted skill name lingers in the test suite. Test intent is unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Companion to the session-recap-hook feature: removes the now-deleted
SESSION.md from framework note, project structure, global rules, subagent
rules, and the skills list (10 -> 8). Committed separately per the
project's own subagent rule.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Bump version 2.1.1 -> 3.0.0 (package.json, plugin.json, lock) — breaking:
  removes /session-start, /session-end, and SESSION.md
- Finalize CHANGELOG: promote Unreleased -> [3.0.0] - 2026-06-03, open fresh Unreleased
- Update landing pages (index.html, index-fantasy.html): automatic recap hook
  framing + skills count 10 -> 8

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@agaete agaete merged commit 1e2d83f into develop Jun 10, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant