Repository navigation
feat(session-handoffs): opt-in hooks for one current note and a no-note nudge - #14
Merged
Merged
Conversation
…te nudge - scripts/handoff_guard.py runs on UserPromptSubmit, PostToolUse (Write) and Stop. It only reads this session's transcript, the notes and the memory files, and never writes a file. - SESSION_HANDOFFS_GUARD=1: a prompt asking for a handoff (any spelling; not a path, a file name, pasted text or a /command) and a Write that creates a note get this session's other current notes, snapshots of it included, and the memory lines that name them, as context. At the end of that turn, a note named on a Supersedes or Replaces line of the new note that still has no banner comes back once as Stop hook feedback. Snapshots of the session are left to /session-handoffs, which banners them once the session's own note covers them. - SESSION_HANDOFFS_NUDGE=1: for sessions that don't write notes. The first time a session has made 30 tool calls over 2 hours without a note, the user sees one systemMessage. Nothing is stored: it fires at the Stop where that holds and didn't at the previous Stop. - A turn is everything since the previous Stop's stop_hook_summary entry, so a prompt, peer message or task notification queued mid-turn doesn't split it. - Silent in subagents, plan and dontAsk modes, and `claude -p`/SDK runs the session registry doesn't list as interactive. Any error, SystemExit included, means exit 0 and no output; each hooks.json command ends in `|| true` (exit 2 on UserPromptSubmit erases the prompt) and runs `python3 -B`, so nothing is cached. - Context is written as facts, not instructions; titles are shown only for notes this session wrote and that nobody changed since. - About 20-40 ms per event on a 21 MB transcript: a turn end reads back only to the previous Stop. - hooks/hooks.json wires it for plugin users, off unless a variable is set; SKILL.md gains "Optional: hooks" with a pinned-copy install for settings.json. Plugin version 1.0.0 -> 1.1.0, so installs pick it up. - Tests: one per rule and per silent case, each failing with its rule removed, plus two that run the real script and parse its stdout as JSON. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
|
Claude finished @lhoupert's task in 18s —— View job ❌ Changes requested — see findings below. Blocking
Non-blocking notes
Simplify (ponytail)
I didn't run the tests. 💰 Estimated review cost: $0.15 · 0m17s · 6 turns |
dannybauman
self-requested a review
October 1, 2026 20:37
dannybauman
approved these changes
Oct 1, 2026
dannybauman
left a comment
Member
There was a problem hiding this comment.
@lhoupert I don't think the Claude bot's blocking issue is real. it says the Stop hook can't hand Claude that extra turn the way you wrote it, but the Claude Code hooks docs say it can: https://code.claude.com/docs/en/hooks#stop-decision-control
that lines up with what you saw when you tried it live, and the tests pass for me too
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two opt-in Claude Code hooks to
session-handoffs. Each is off unless its environment variable is set:SESSION_HANDOFFS_GUARD=1: when a session is asked for a handoff or writes a new note, it is told which of its notes and snapshots are still current, and which memory lines name them. If the new note supersedes one that still has no banner, Claude gets one more turn to add it.SESSION_HANDOFFS_NUDGE=1: for sessions that never write notes. The first time a session has made 30 tool calls over 2 hours without one, the user sees one line; it costs no model tokens.Stacked on #13. Tested with 54 unit tests, a replay of a real duplicate-note incident, and timings on a 21 MB transcript (about 20–40 ms per event).
For reviewers: tried in a live Claude Code 2.1.285 session loaded with
--plugin-dir. The prompt, Write and Stop hooks each gave the expected context, and the Stop feedback came once, with no loop. The nudge, which needs 2 hours, was checked only in tests. It reads the same undocumented transcript format as #13 and stays silent (exit 0, no output) on anything unexpected.Author attestation
AI-assisted: Claude Code wrote the hook, tests and docs, after checking the hook contract against the Claude Code docs and real transcripts. It went through a
/code-review maxand two rounds of independent verification. Every rule has a test that fails without it.🤖 Generated with Claude Code