Repository navigation
Conversation
…n (1.0.0) New Claude Code plugin. It checks which running sessions already left a handoff note today (read-only, from the local session registry and transcripts), asks only the others to write one once they are idle, and lists every note under the daily note's "For Tomorrow" heading. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ph9PzkBrREkNY1v4C8GWM7
From the first live run: - the check drops notes that open with a SUPERSEDED banner (after any frontmatter), so a replaced note is no longer listed next to its successor - it prints each note's title (first heading, else file name); the skill shortens it and writes one plain line per note - notes named for a later day count, older compact dates (20260903) don't - a stale session that never replies still gets its notes listed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ph9PzkBrREkNY1v4C8GWM7
…cript - `handoff_status.py --digest NAME` prints the session's latest note and a compact log of its day (prompts, Claude's messages, one line per tool call, no tool output, secrets masked, capped at the most recent 25k chars) - SKILL step 5 / `--from-transcript`: on request, write a labelled snapshot note for a session that stays busy Fixes from a max-effort review of the whole skill: - `--date` is the start of the window, so a run after midnight sees the evening - notes in any `git worktree add` checkout are not durable, not just .claude/worktrees - a date in a note's name counts only up to 3 days ahead (deadlines don't) - frontmatter is read to its closing `---` - digest skips skill bodies and compaction summaries, labels peer messages - one shared transcript reader; tests pass with the temp dir under $HOME Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ph9PzkBrREkNY1v4C8GWM7
Live runs showed the subscribe-and-wait flow stalls: a session running background work never counts as idle, the coordinator had to stay open, and closing it dropped every pending request. An architecture review (mechanics, two adversarial passes, alternatives, cost) recommended: - /session-handoffs only reads: check, write the daily list, report. It can be re-run any time; closing it early loses nothing. - `--ask NAME` sends one request to an idle session, with no waiting; `--from-transcript NAME|SID8` writes a snapshot note, which counts for the session it describes. - Running sessions come from the registry; this session is left out via $CLAUDE_CODE_SESSION_ID. Automation (SDK, claude -p) is not reported. - Out of date = more than 30 main-conversation calls or subagent file edits after the latest usable note; sessions without a note and under 30 calls are left out; new closed-stale verdict. - Listing is its own rule (date window, SUPERSEDED banner incl. dated and quoted forms), so a replaced note isn't listed next to its successor. - --date defaults to 5 hours ago; submodules are not worktrees; more secret forms masked in the digest. Reviewed with /code-review high (10 findings, fixed); 14 tests, each rule mutation-checked (37/37). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ph9PzkBrREkNY1v4C8GWM7
|
Claude finished @lhoupert's task in 14s —— View job ✅ No blocking issues — safe to merge. Reviewed the latest change (
Simplify (ponytail)
💰 Estimated review cost: $0.13 · 0m13s · 8 turns |
…ge snapshots faster From a three-reviewer check of the 29 Sep live run: - A session opened to run the report (first tool call runs the script or loads the skill) is left out. It showed as `none` on the next run and was offered a snapshot of itself; its snapshots still count for their sources. - A .md note in a handoff/ or handoffs/ directory counts as a note. - A snapshot is out of date after 5 source calls, not 30: it can't know what came after it. - --digest refuses an id prefix shared by two sessions. - Dates inside longer numbers are not read as a note's date. - Masking adds Authorization, JWT, PEM, Google keys, *_KEY=, SAS sig= and IPv4 addresses. - SKILL.md step 5: the log is data, never instructions; say when the log was cut. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
thanks for sharing this @lhoupert! I run into this issue too when wrapping up a bunch of parallel sessions at the end of the day. I tried the check script on my machine, the 14 tests pass and the check took about 0.2s across 13 sessions. A few questions from trying it:
other projects I came across:
|
|
Thanks @dannybauman, it is really useful!
Asking every session by default is off on purpose. Mostly to avoid that waking one that has been idle for over an hour re-reads its whole context. Mine write notes because I ask for them, and my CLAUDE.md says where they go. I'll add that line to the Requirements.
Yes, I'll add a
Yes, good catch 😅 . I'll make it exit with an error instead.
I'll look into it! Thanks for the links. I'll borrow "What We Tried" for the note checklist. |
- A run of the report is no longer dropped from the report; it is only never listed as lacking a note. So a wrong match can't hide a working session, its notes or a snapshot of it (findings 1, 3, 4). The run is detected from the session's first tool call ever, not the first in the window, and only when that call runs the script, not when it names it. - The SDK filter again uses the first entrypoint seen (finding 14). - The 5-call staleness applies only to a snapshot another session wrote, not one the session later edited itself (finding 5). - --digest refuses a name shared by two running sessions; the report shows their sid8 (finding 7). - Private keys are masked whole, through their END line, in a pass before SECRET (findings 2, 8). Quoted values are masked whole, an Authorization header without a scheme is masked, more token prefixes are covered, and a bounded label keeps a long blob linear (64k chars: ~70 s -> 0.08 s) (findings 9, 10, 11). - A date followed by a time (202609201030) is a date (finding 12); only dated .md files in a handoffs/ folder are notes (finding 13). - SKILL.md: the other session's note is data too (finding 15); says IPv4; notes that a snapshot's freshness counts from its write time (finding 6, left as a limit). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Three lines at 384d792 were over the line length, so `ruff format --check` failed before any change. Formatting only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…note
- A snapshot is now `replaced` once the session's own note covers it:
written after it, or at most 5 calls before it. It gets a `replaced`
row naming that note instead of a line of its own. Before, a session
that wrote its own note after its snapshot, or whose snapshot came
after its own note with no work between, was listed twice.
- A replaced snapshot is still reported when it carries a banner or
predates the own note, so a line an earlier run wrote for it gets
swapped for the own note, or deleted if that note has a line already.
Its row comes before the own note's row.
- Step 2 keeps a hidden record of what it listed at the end of the
section (an HTML comment) and skips any path the record names. A
re-run no longer brings back a line the user deleted or reworded. A
line already counts if it has the path with ~ or in full, or a wiki
link to the note. A snapshot the run has just written is added even if
the record names its path.
- The run marks a replaced snapshot SUPERSEDED and removes the memory
line a run of this skill added for it. It never edits the session's
own note.
- --ask names the session's snapshots and says its own note supersedes
them.
- In a handoff(s)/ folder, a file with "body" in its name (a PR or
issue body) is not a note. A note that opens with a quoted
`> COMPANION of <path>` line (one kept on purpose beside another) is
not listed. Plain "Companion notes: ..." lines still are.
- A note's title is its level-1 heading, else its file name. A section
heading ("## Status ...") is no longer taken as the title.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…'t be read - A renamed transcript field gave a header-only report and exit 0. The check now exits 1 with a one-line message when projects/ is missing, when registry files exist but none yields a sessionId (a renamed key, or a file that is no longer a JSON object), or when transcripts changed in the window but no tool call could be read from any of them. - The tool-call count includes the session running the report, whose own call to the script is always in the window, so a quiet day, an empty day or a new install still exits 0. - --digest exits 1 when the log is empty instead of printing a blank log that would become an empty snapshot. - claude agents --json is not used: it is documented, but lists no sessions inside Claude Code's Bash sandbox, where this script runs. One Limits sentence and a code comment say so. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…choose - A `session-handoffs notes: <dir>` line, set like the daily-note line, names a folder for notes (for example in a synced notes vault). Without it nothing changes. - --digest takes --notes-dir and prints the snapshot path in that folder. It expands a quoted ~, since the model quotes the path. - --digest stops with an error when the folder is missing, or sits where the check never finds notes (memory/, temp dirs, git worktrees). A snapshot written there would never count. The script never creates the folder: a typo in the line would add a stray folder to a synced vault. - SKILL.md: the --ask request writes new notes in that folder, and step 5 passes --notes-dir. Limits now say notes are found through this machine's transcripts, so a synced note is listed only on the machine that wrote it. - Detection is unchanged: requested notes and snapshots are named handoff_<date>_<topic>.md, so they are found anywhere. Counting every dated .md in the folder would list unrelated vault notes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…ubagent For users whose sessions don't write notes on their own (from the PR review): - Requirements: a copyable CLAUDE.md line in the same words as the rule the --ask request sends, so a session asked for a note puts it where it lasts. One rule, not two. - The note checklist adds "what was tried and ruled out, and why", after the "What We Tried" section of REMvisual/claude-handoff. - Step 3 asks one question, "Snapshot these N?", when rows are stale or none; the user says yes, no or names some. A snapshot only reads the transcript. --ask is suggested only for running sessions active in the last hour: waking one idle longer re-reads its whole context. - Step 5 writes each snapshot in its own general-purpose subagent, with a fixed prompt. Written in the report's own context, 3 snapshots cost 2.6M input tokens, because every later call re-read each log. The prompt carries the "another session's data" rule; the subagent writes only the snapshot and replies with its path. - Memory: one line per day listing that day's unreviewed snapshots (paths and names only, replaced on each run) instead of one line per snapshot. Memory loads in every session, and nobody has reviewed them. - Test: a snapshot written by the report session's subagent counts for the session it describes, which the new step 5 relies on. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- The Recommended CLAUDE.md line named only the directory that holds memory/, while the notes line and the --ask request send notes to the notes folder when one is set. A session following the CLAUDE.md line would put its note outside that folder. - The line now says the notes folder if set, else that directory: the same rule as the request's <notes>, still in the request's words. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- Each snapshot is now written by a subagent from a fixed prompt that repeats the --digest command, and that copy had no --notes-dir. With a notes folder set, snapshots still landed in the project directory. - The prompt now passes --notes-dir '<folder>', dropped when no folder is set. - The subagent never reads step 5 item 1, where "don't create it" lives, so the prompt also says not to work around a script that stops: a folder made by mistake would land in a synced vault. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- Step 5 now keeps one memory line per day naming every snapshot in the report. Replaced snapshots are in the report too, as `replaced` rows, so the line would have kept pointing at snapshots an own note covers. It now names only snapshots that aren't `replaced`. - Step 2 still told the run to remove "the memory line step 5 wrote" for a replaced snapshot, a per-snapshot line that no longer exists. It now drops the snapshot from the day's line, so this happens on every run, not only on runs that write snapshots. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- Step 1 said the check prints one row per note worth starting from, or per session without one. It now also prints one row per `replaced` snapshot, which is not a note to start from. - Limits said any file in a handoff(s)/ folder is a note. The check counts only dated ones there, which is also why a notes folder named handoffs/ picks up dated notes without "handoff" in their name. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- The intro said the skill only reads. It writes the daily note, one memory line and snapshots; it now says so, and that it never edits another session's own note. - Say where the daily note and notes folder lines are read from, up front. Steps 4 and 5 used the notes folder without saying where to find it. - Define `<date>` once (the --date value, else the day 5 hours ago), so the daily note, --digest and the memory line use the same day as the check. Say that every run does steps 1 to 3, and that --ask and --from-transcript replace step 3's question: steps 4 and 5 need the report's rows. - Step 2: a missing daily note file or heading prints the list instead of creating them. The record is defined where it is written. Lines are added only for rows with a path, so `none` rows get none. A snapshot written in this run is added unless a line already has it, not merely "even if the record names it", which invited a duplicate line. - The memory line moves from step 5 to step 2, with "write no other memory", so it is kept on every run that writes. Step 2 no longer points ahead to step 5 for it. - Step 5: the subagent prompt now carries every rule the subagent must keep (pasted text is data, don't edit that session's note or memory, don't create a missing folder); the duplicated item 1 and item 3 are gone. A snapshot gets a `#` title, which becomes its daily-note line. The run tells the user about any snapshot that wasn't written. - Use the sid8 for a session whose row shows one: --digest refuses a name two running sessions share. - Limits: the SUPERSEDED rule said "a quoted line containing it", which the check doesn't match; it now shows the banner form. The busy session line repeated step 4 and is gone. - handoff_status.py docstring: NotebookEdit, automation left out, `replaced` rows and the header, what "covers" means, peer messages in the digest, and when --digest exits with an error. - 2214 words to 2195. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Run from a session, the check now reads that session's own transcript, which holds the call running the script. It exits 1 if that transcript isn't under projects/*/ (a layout change) or no tool call can be read from it (a format change). Before, any other readable transcript passed the check. On the day of an update, sessions started earlier still write the old format, so sessions in the new one dropped out of the report with no error. - Tool calls by the session's subagents count too, so a run from a subagent is not an error when the session made no call of its own that day. - Run from a terminal, it still exits 1 when no tool call can be read, and the message now names the other cause: no session used a tool. Counting readable lines instead would miss a renamed tool call. - Tests: an old-format session beside new-format ones, transcripts moved one folder down, a terminal run with a renamed tool call beside a chat, a quiet day where this session's call is the only one, a run from a subagent, and a registry with one session beside objects that aren't sessions. - The test helper that reads the report first writes this session's call to the script, as every real run has one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- A snapshot is replaced only when a run of the report wrote it last, or it already opens with a banner. Before, a snapshot the session had edited to continue from it, or one another session had edited, could be replaced, and step 2 would then put a SUPERSEDED line on a note someone works from. - The own note that replaces a snapshot is the newest one named for the day, if there is one. Before, touching a note named for an earlier day could hide a snapshot that held the only record of the work since the day's own note. - Tests pin which own note replaces a snapshot: the newest, not the oldest, and only one that exists, not a Write that never landed. They also pin the limits of the COMPANION banner: a quoted "Companion notes:" list, an unquoted "Companion of" and "companion of" inside a quoted line are not banners. - A comment and the Limits say that "body" matches anywhere in a name in handoffs/, and that other drafts kept there count as notes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- The check's first line now gives the day it covers and the time now, and SKILL.md takes <date> from it. The model knows today's date but not the clock. After midnight it could write to the wrong daily note and pass the wrong --date to each snapshot subagent, whose --digest then fails for a session last active before midnight. - Step 3 checks "active in the last hour" against the time on that line instead of guessing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…3 and 5 - Step 2: a replaced snapshot's line is deleted only while it is still as the skill wrote it. A line the user ticked or edited gets the note's path instead, and keeps their text. - Step 2: drop "(out of date)" from a line whose row is now fresh or closed. A note updated in place kept that marker for good. - Step 2: read only the first 5 lines of a replaced snapshot before marking it. The rest is another session's data, and no rule in the running session said so. - Step 2: the memory line is one rolling line, replaced whatever date it names. A run sees only its own day's snapshots, so one line per day piled up in memory and was never pruned. - Step 3: a row without a title shows its project and last_active, so the user can tell sessions apart when asked "Snapshot these N?". - Step 5: the subagent covers the step 4 request's "Make it self-contained" bullet, not "the checklist": the request's other bullets say to edit that session's note and memory. - Limits: the daily note keeps a hidden record of every path it listed, deleted lines too. - SKILL.md goes from 2195 to 2338 words over the four commits. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- A snapshot an earlier run of the report wrote is replaced once the session's own note covers it. This is the case on real data: the snapshots come from a previous run, not from the session running now. - A snapshot another session edited after the run wrote it is not replaced: someone works from it. - Each test fails when its branch of the rule is removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…dian-mind - The note checklist asks for the user's corrections and preferences, next to what was tried and ruled out (claude-handoff's "User Feedback" and "What We Tried" sections). A log's user lines are where they live, and a summary tends to drop them. - A snapshot says what changed since the session's last note. - Step 2 banners a replaced snapshot only while it still opens with this skill's own "Snapshot written by" line, and only by inserting one line: a file someone else rewrote is left alone (obsidian-mind edits only files it wrote, and only by adding). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…check - Finding 1: a snapshot counts for the session it describes only when a run of the report, or the session running it, wrote it. Another session's Write or Edit of it stays that session's own note. Before, that edit moved to the described session: the editor showed as `none`, and the described session went on the 5-call rule. - Finding 1: --digest exits with a message instead of printing a snapshot path that someone else wrote last, the described session included. Step 5 replaced that file and lost the edits of whoever works from it. SKILL.md says a session that edits a snapshot makes it its own note. - Finding 8: a snapshot marked SUPERSEDED is `replaced` by the session's newest own note, however many calls separate them. The banner edit is the snapshot's last write, so a banner added more than 5 calls after the own note dropped its row, and step 2 never swapped its line. - Finding 9: --notes-dir must be absolute after ~ expansion. An empty or relative folder printed a relative snapshot path, which landed under the subagent's working directory, where the check never finds it. - Finding 14: the registry check stops only the report. --digest finds a session by its id and doesn't need the registry. Limits says a registry that moves isn't noticed. - A session opened to run the report and then put to work still owns its edits of its own snapshot. - Each new test fails with its change reverted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- Finding 7: step 2 repoints, or deletes, only a line that holds a replaced snapshot. The note in its title is otherwise listed like any other row. "If its snapshot is listed, so is the note in its title" counted the title note as listed when no line held the snapshot any more, so a later own note never got a line. If the user deleted the snapshot's line, the own note's line is added once, and a deletion sticks after that. - Step 2 no longer banners a snapshot marked "> COMPANION of": someone kept it on purpose beside another note. - Finding 11: Limits says a banner opens the note after any frontmatter, as v1.0.0 did. A banner on line 1 turns YAML frontmatter into body text. - SKILL.md goes from 2362 to 2389 words over the two commits. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…ck as the run's - Finding 1's fix (V1-1, V3-R5): a snapshot counted for the session it describes only when the session that wrote it was opened for the report. A /session-handoffs run from a working session (its first call was other work) then kept its step-5 snapshots as its own notes: the snapshotted session showed as `none` again and was offered once more, and --digest refused to rewrite the snapshot on every run. - A write counts as the run's once its session has run the check, in its main conversation or in a subagent (step 5's subagent runs --digest first). Its writes before that stay its own. --digest uses the same rule when it decides who wrote the snapshot last. - V1-2: --digest no longer refuses a snapshot that opens with a SUPERSEDED banner, whoever wrote it last: the banner says nobody works from it. Before, the snapshotted session stayed `none` or `stale`, step 3 kept offering it, and step 5 failed all day. A COMPANION line still keeps it. - Once a run writes over a snapshot, an earlier edit by another session no longer lists it as that session's note: the edit is gone from the file. Without this, the V1-2 change listed the rewritten snapshot under both sessions. - SKILL.md says step 5 replaces a snapshot marked SUPERSEDED (2389 to 2394 words). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…rote it
- The rule from 4d8877a ("the session ran the check before the write")
still let step 5 overwrite a note: a session that ran the check at 11:00
and then edited another session's snapshot at 13:00 had that edit
counted as the run's, so --digest replaced it.
- Step 5 writes every snapshot from a subagent, so a write from a
subagent transcript is a run's; a session's own conversation works from
what it writes, before or after running the check. A session opened for
the report, and the session running it, still count as runs.
- The mid-day run case behind 4d8877a still holds: its subagent's snapshot
counts for the session it describes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
- A `claude --bg` session is registered with kind "bg" (entrypoint cli, a name and an idle/busy status), and ListAgents lists it, so SendMessage reaches it. The check counted only kind "interactive" as running, so such a session was reported closed, closed-stale or closed-none, and the report offered --from-transcript instead of --ask. - LIVE_KINDS names both kinds; SKILL.md step 4 asks idle `bg` sessions too. Other kinds still aren't a working session. - Reported by the /session-kickoff session, which starts one --bg session per focus item. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T8PczU1B2Y9DCWAV36fnH3
…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
There was a problem hiding this comment.
thanks @lhoupert. I pulled the branch, the tests pass and the check ran cleanly across my sessions today. the notes line is what I was hoping for, I'll point mine at my vault.
on claude agents --json, it did return my sessions from a Bash call, though some of my sessions run with permissions bypassed so it may not be sandboxed. could the check try it first and fall back to the session files when it comes back empty? fine as a follow up too
feat(session-handoffs): opt-in hooks for one current note and a no-note nudge
… session `claude agents --json` is the documented list of running sessions, but inside Claude Code's Bash sandbox it lists only some of them (2 of 12 on 2.1.287, both `blocked` background jobs), so falling back only when it is empty would drop sessions without an error. Trust it only when it lists $CLAUDE_CODE_SESSION_ID, the session running the check; otherwise read sessions/*.json as before. It calls `claude --bg` sessions "background", so that kind counts as running too. CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 keeps it from calling api.anthropic.com, which the sandbox blocks with a warning. Suggested in review of #13. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks @dannybauman, and for checking the Stop hook docs on #14! I added one small change. Inside the sandbox, It came after your approval, so a quick look would be great if you have time! |
|
thanks @lhoupert, the change looks good to me. I ran one question: the check now trusts |
Inside Claude Code's Bash sandbox `claude agents --json` can list only some sessions, and nothing stops the session running the check from being one of them. Trusting the list whenever it names that session would then show the others as closed. Read sessions/*.json every time and add what the CLI lists, so a short list can add sessions but never hide them. Whether the registry changed format is judged from the registry alone, so a CLI list can't hide that either. Raised in review of #13. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks @dannybauman and good catch! Yes, you are right to ask, t could. a22b91a reads both now. |
Adds
session-handoffs, a Claude Code plugin for people who run several sessions at once. At the end of the day it reads each session's transcript to see which ones left a current handoff note and lists them under a "For Tomorrow" heading of a daily note. For busy sessions with no note, it asks once whether to write a snapshot from each transcript, in a subagent each, or to ask sessions idle for under an hour to write their own. It never waits on another session, and a re-run doesn't bring back lines you deleted. Tested withpython3 -m unittest discover -s skills/session-handoffs/scripts(89 tests, in four time zones and on Python 3.9),claude plugin validate, and read-only replays of ten days of real sessions.For reviewers: Claude Code only. The check reads Claude Code's transcripts (
.jsonl), which are not a documented interface, and exits with an error when it can't read them instead of printing an empty report. A session counts as running ifclaude agents --jsonor~/.claude/sessions/*.json(also undocumented) lists it. The files are always read, because inside Claude Code's Bash sandbox the CLI lists only some sessions. The opt-in hooks from #14 are merged into this branch.Author attestation
AI-assisted: Claude Code wrote the skill, script and tests. Since the first review, it addressed the review comments and the duplicate lines a live run left in the daily note. It then went through a
/code-review max(15 findings) and two rounds of independent verification. Every script rule has a test that fails without it, and a ponytail pass was applied. Theclaude agents --jsonchange (995fbdb) had a/code-review lowand a live run with and without the sandbox. Its follow-up (a22b91a), which reads both lists after review, had a/code-review medium, a mutation check, and the same live run, with matching rows.🤖 Generated with Claude Code