You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: handoff / inbox / ack subcommands for structured cross-session work transfer
Adds three new subcommands and a SQLite handoffs table for tracking
work passed between sessions (or future-you).
New commands:
- handoff: write a brief with optional structured notes
(--done / --pending / --blocked), log to handoffs table,
optionally launch the target session immediately. Supports
--target-cli, --target-cwd, --target-session, --require-ack.
- inbox: show pending handoffs whose target_cli, target_cwd
prefix, or target_session_id matches the current context
(defaults to env-detected source, $PWD, and CLAUDE_CODE_SESSION_ID).
- ack <id>: mark a handoff as absorbed; records ack_at,
ack_session_id, optional --note.
Brief writer: gained an optional notes parameter that prepends
a "## Handoff Notes" section (What's done / What's pending /
What's blocked) before the existing transcript-derived content.
Backward compatible - existing brief callers pass nothing.
Schema: new handoffs table with indexes on target_cwd,
target_session_id, and status. Idempotent CREATE IF NOT EXISTS
so existing installs pick up the table on next invocation.
UX: /absorb action menu surfaces handoff via the More submenu;
all three commands are pass-through subcommands for /absorb.
Tests: 10 new pytest smoke tests covering help, dry-run,
empty-inbox, env-aware session resolution, and error paths.
All 18 tests passing on Python 3.12+.
Docs: README, reference, use-cases, CHANGELOG, and all three
SKILL.md files updated with command listings, examples, and
two new use-case scenarios (end-of-day async handoff,
cross-CLI handoff with require-ack).
Copy file name to clipboardExpand all lines: CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
8
8
## [Unreleased]
9
9
10
+
### Added
11
+
12
+
-`handoff` subcommand for structured cross-session work transfer with optional note fields (`--done`, `--pending`, `--blocked`) and acknowledgment tracking.
13
+
-`inbox` subcommand to show pending handoffs targeted at the current cwd, CLI, or session id.
14
+
-`ack` subcommand to mark a handoff as absorbed by the receiving session.
15
+
- New `handoffs` SQLite table at `~/.local/share/session-absorb/sessions.db` for handoff state tracking.
16
+
- Brief writer now prepends a `## Handoff Notes` section (What's done / What's pending / What's blocked) when handoff notes are supplied.
Copy file name to clipboardExpand all lines: README.md
+12-1Lines changed: 12 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -40,6 +40,15 @@ In the picker, choose the Codex session. Then "Handoff to other CLI". A brief ge
40
40
41
41
New Terminal window, new Claude session, same context. The session you're in now keeps going untouched.
42
42
43
+
**End of the day, hand off to tomorrow.** You shipped half a PR. You won't remember the state by morning. Write a handoff for the next session that opens in this directory.
The shared CLI exposes twelve subcommands. The ones you'll touch directly:
105
+
The shared CLI exposes the subcommands you'll touch directly:
97
106
98
107
**Find a session:**`list` (interactive picker or table), `init` (assign or override an alias code), `pick` (select by number from the last chat menu).
99
108
100
109
**Do something with it:**`digest`, `ask --question`, `brief`, `launch` (native fork or cross-platform handoff).
101
110
102
111
**Shortcuts:**`here [action]` for the cwd default, `last [action]` for anywhere, `fork-myself` for the current session.
103
112
113
+
**Handoff:**`handoff` (write a brief and log it for the next session), `inbox` (list pending handoffs aimed at you), `ack` (mark one absorbed).
114
+
104
115
**Plumbing:**`db` to inspect the SQLite catalog, `web` to serve a local live dashboard, `install` to (re)install the runtime and skills.
105
116
106
117
Visual cues distinguish the two CLIs everywhere: `🟠` for Claude and `🟢` for Codex in the in-chat picker, `◆C` and `◇X` in plain text, ANSI 214 (orange) and 51 (cyan) in real terminals. Honors `NO_COLOR` and `FORCE_COLOR`.
Copy file name to clipboardExpand all lines: docs/reference.md
+82Lines changed: 82 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -249,6 +249,83 @@ session-absorb last brief --question "Absorb everything from this morning"
249
249
session-absorb last show
250
250
```
251
251
252
+
## `session-absorb handoff`
253
+
254
+
_Reach for this when: you're done with this work and someone else (or future-you, in another session) needs to pick it up._
255
+
256
+
Writes a bridge brief, optionally launches the target CLI, and logs a row to the inbox so the receiving session can find it. When any of `--done`, `--pending`, or `--blocked` is supplied, the brief gets a `## Handoff Notes` section at the top with those fields.
_Reach for this when: you're starting a session and want to know if anything was handed off to you._
291
+
292
+
Lists pending handoffs targeted at the current session. By default, matches against your CLI, your cwd (prefix), and your session id. A handoff matches when each of `target_cli`, `target_cwd`, and `target_session_id` is either null or matches you. Acked or expired handoffs are excluded unless `--show-all` is set.
-`--cwd <path>` - cwd to match against (default: `$PWD`)
298
+
-`--show-all` - include acked and expired handoffs
299
+
-`--json` - print JSON instead of a table
300
+
-`--limit <n>` - max rows to display
301
+
302
+
Examples:
303
+
304
+
```bash
305
+
session-absorb inbox
306
+
session-absorb inbox --json
307
+
session-absorb inbox --show-all
308
+
session-absorb inbox --cwd ~/proj/api
309
+
```
310
+
311
+
## `session-absorb ack <handoff-id>`
312
+
313
+
_Reach for this when: you've absorbed a handoff and want the source session to know it landed._
314
+
315
+
Marks a handoff as acknowledged. The source session can then see the ack via `session-absorb inbox --show-all`.
316
+
317
+
Flags:
318
+
319
+
- positional `<handoff-id>` - row id from `inbox` output (required)
320
+
-`--note <text>` - optional note attached to the ack
321
+
322
+
Examples:
323
+
324
+
```bash
325
+
session-absorb ack 3
326
+
session-absorb ack 3 --note "picked it up, continuing now"
327
+
```
328
+
252
329
## `session-absorb fork-myself`
253
330
254
331
_Reach for this when: you're about to try something risky and want a parallel session that inherits everything._
@@ -330,6 +407,8 @@ Source differentiation stays consistent across every output surface:
330
407
|`/absorb` AskUserQuestion picker |`🟠` orange circle |`🟢` green circle | Plus `📋` for the manual-pick escape option |
331
408
| Self marker |`*self*` suffix in plain output, `is_current: true` in JSON | same | Matched against `CLAUDE_CODE_SESSION_ID` / `CODEX_SESSION_ID` env vars |
332
409
410
+
`inbox` output uses the same source-color encoding as `list`: orange for Claude, cyan for Codex in TTY, `🟠` / `🟢` in chat menus, `◆C` / `◇X` in plain text.
411
+
333
412
## Environment variables
334
413
335
414
-`CLAUDE_CODE_SESSION_ID` - exported by Claude Code into subprocess env. When present and matching a session's `session_id`, that record is flagged `is_current: true` in JSON output and annotated `*self*` in plain output.
@@ -348,6 +427,9 @@ Lives at `skills/claude/absorb/SKILL.md` (alias of `/session-absorb`). Routes by
348
427
|`/absorb last [action]`| B | Pass-through to `session-absorb last`. Default action `digest`. |
349
428
|`/absorb pick`| B | Forces the multi-step click picker. |
350
429
|`/absorb fork-myself`| B | Pass-through to `session-absorb fork-myself`. Forks your current active session. |
430
+
|`/absorb handoff [args]`| C | Pass-through to `session-absorb handoff`. Writes a brief, logs to inbox, optionally launches target. |
431
+
|`/absorb inbox [args]`| C | Pass-through to `session-absorb inbox`. Shows pending handoffs targeted at this session. |
432
+
|`/absorb ack <id> [--note <text>]`| C | Pass-through to `session-absorb ack`. Marks a handoff absorbed. |
351
433
|`/absorb <subcommand> [args]`| C | Direct pass-through to `session-absorb`. |
352
434
|`/absorb <free text>`| D | Haiku subagent resolves intent (session match + verb) and runs the command in one shot. |
Copy file name to clipboardExpand all lines: docs/use-cases.md
+25-5Lines changed: 25 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -36,7 +36,27 @@ You used Codex CLI to scaffold a new module because its planner felt right for t
36
36
37
37
Pick the Codex session (it's the green circle in the picker), choose `🤝 Handoff to other CLI`. A bridge brief gets written to `.session-absorb/briefs/`. A fresh Claude Code window opens in a new Terminal, primed with the brief as its first user message. The receiving session knows what tools were used, what files were touched, and what the previous CLI was trying to accomplish. Codex has no non-interactive fork API, so brief-driven handoff is the right road for cross-CLI work, not a fallback.
38
38
39
-
**4. One question, not a whole digest**
39
+
**4. Hand work to your future self in 8 hours**
40
+
41
+
End of the day, you've got one PR half-done. You won't remember the state by morning. You write a structured handoff to whichever Claude session opens in this cwd next.
42
+
43
+
```
44
+
session-absorb handoff --no-launch --target-cwd "$(pwd)" --done "API routes wired" --pending "frontend integration" --blocked "waiting on Stripe API key"
45
+
```
46
+
47
+
Tomorrow you start a Claude session in the same directory and run `/absorb inbox`. The pending handoff shows up. You read the brief and pick up exactly where you stopped.
48
+
49
+
**5. Cross-CLI handoff with explicit ack**
50
+
51
+
You ran a heavy refactor in Codex. You want Claude to take over. You also want to know whether Claude actually started.
52
+
53
+
```
54
+
session-absorb handoff --target-cli claude --require-ack --done "refactor complete, all tests passing" --pending "performance benchmarks"
55
+
```
56
+
57
+
Claude session opens. After it absorbs the brief, it runs `session-absorb ack <id>`. Your Codex session can check `session-absorb inbox --show-all` to confirm the handoff was acknowledged.
58
+
59
+
**6. One question, not a whole digest**
40
60
41
61
You remember a session figured out a specific thing. Whether you wired up Stripe webhooks, what port the mock server ran on, why the migration kept failing. You don't want a 600-line digest, you want one answer.
42
62
@@ -52,7 +72,7 @@ Pick the session, choose `🎯 More`, then `🔎 Ask question`. Or skip the menu
52
72
53
73
For Claude sessions, `--live auto` tries a real forked query first. If that fails (sometimes resumed sessions choke on stale tool markers), you fall back to a ranked transcript-backed answer pack. Either way you get something usable.
54
74
55
-
**5. Try something risky without losing your place**
75
+
**7. Try something risky without losing your place**
56
76
57
77
You're 40 messages deep in a session that's working. You want to try a refactor that might blow it up. You don't want to stash, branch, and lose your seat in the chat.
58
78
@@ -62,7 +82,7 @@ You're 40 messages deep in a session that's working. You want to try a refactor
62
82
63
83
A new Terminal window opens with a parallel Claude Code session that inherits everything up to right now. The original keeps running in your current window, untouched. Use the fork to experiment with the refactor. If it works, merge the diffs back manually. If it doesn't, close the window and pretend it never happened. Same-CLI native fork only, no brief involved. Reads `CLAUDE_CODE_SESSION_ID` from your env to know who "myself" is.
64
84
65
-
**6. Hand the work to a teammate**
85
+
**8. Hand the work to a teammate**
66
86
67
87
Sometimes a teammate needs to pick up where you left off and they don't have your terminal. You need a written artifact, not a fork.
68
88
@@ -72,7 +92,7 @@ Sometimes a teammate needs to pick up where you left off and they don't have you
72
92
73
93
Pick the session, choose `🎯 More`, then `📝 Brief only`. The brief lands at `.session-absorb/briefs/<timestamp>-<source>-<sessionid>.md` (e.g. `20260508T143022Z-claude-abc123.md`). Plain Markdown: metadata, dominant tools, recent turns, ranked excerpts, instructions for the receiving session. Slack it, paste it into a PR description, attach it to a Linear ticket. It's just a file.
74
94
75
-
**7. You're juggling six sessions and need to see them all**
95
+
**9. You're juggling six sessions and need to see them all**
76
96
77
97
It's late, you've been hopping between four repos, and you've lost track of which sessions are still warm and which ones you can let go.
78
98
@@ -82,7 +102,7 @@ It's late, you've been hopping between four repos, and you've lost track of whic
82
102
83
103
A flat table of every session updated in the last 240 minutes. Claude rows render in orange (ANSI 214), Codex rows in cyan (ANSI 51). Your current session gets a `*self*` annotation in plain output so you don't waste a beat trying to digest yourself. `--active-only` clamps the list to live work, not yesterday's archaeological record. Honors `NO_COLOR` and `FORCE_COLOR` if you pipe it.
84
104
85
-
**8. You want to give one a name so you stop typing UUIDs**
105
+
**10. You want to give one a name so you stop typing UUIDs**
86
106
87
107
There's a session you keep coming back to. The big dashboard refactor, the one with all the open threads. Typing `4f3a8b21-...` every time is friction.
|🪞 Fork myself |`$HOME/.local/bin/session-absorb fork-myself` (ignores the picked session entirely - forks the user's CURRENT active session via `CLAUDE_CODE_SESSION_ID`) |
82
+
|📦 Handoff |`$HOME/.local/bin/session-absorb handoff --source <s> --session <c>` (plus any `--done`/`--pending`/`--blocked` text the user provides; runs against the picked session as source) |
83
83
| ↩️ Back | re-render Step 3 |
84
84
85
85
### Default questions (do NOT prompt)
@@ -153,6 +153,16 @@ AskUserQuestion option labels (chat-rendered, color via emoji):
If the result is non-empty (pending handoffs targeted at this cwd, CLI, or session id), surface a 1-line summary at the top of the response - "📦 N pending handoff(s) for this session" - and offer to absorb the most recent one before continuing with the normal Path A flow. The user can then run `/absorb ack <id>` after they've digested it.
165
+
156
166
## Important constraints
157
167
158
168
- Never invoke yourself: runtime filters `is_current` sessions. Don't override.
Copy file name to clipboardExpand all lines: skills/claude/session-absorb/SKILL.md
+25-2Lines changed: 25 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
name: session-absorb
3
3
description: Use when you need to absorb, merge, or consult context from another Claude Code or Codex session without copy-pasting, including native Claude fork launch, Codex fork launch, transcript-backed bridge briefs, and focused session Q and A.
|`ask`| query a session or build ranked excerpts |`/session-absorb ask --source codex --session <id> --question "What changed?"`|
22
22
|`brief`| write a bridge brief |`/session-absorb brief --source claude --session <id> --question "Absorb and continue"`|
23
23
|`launch`| open a native fork or bridge session in Terminal |`/session-absorb launch --source codex --session <id> --target claude`|
24
+
|`handoff`| write a brief, log it for the next session, optionally launch the target |`/session-absorb handoff --done "auth merged" --pending "tests"`|
25
+
|`inbox`| list pending handoffs targeted at this session, cwd, or CLI |`/session-absorb inbox`|
26
+
|`ack`| mark a handoff absorbed (referenced by id from `inbox`) |`/session-absorb ack 3 --note "picked it up"`|
24
27
|`db`| inspect the SQLite session catalog and active-state counts |`/session-absorb db`|
25
28
|`web`| serve the live local dashboard for sessions and states |`/session-absorb web --open-browser`|
26
29
|`install`| install the runtime and skill wrappers into both home registries |`/session-absorb install --repo-root <repo-root>`|
Copy file name to clipboardExpand all lines: skills/codex/session-absorb/SKILL.md
+16-1Lines changed: 16 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
name: session-absorb
3
3
description: Use when you need to absorb, merge, or consult context from another Codex or Claude Code session without copy-pasting, including native fork launch for same-CLI sessions and transcript-backed bridge briefs across CLIs.
|`ask`| extract an answer or ranked excerpts |`session-absorb ask --source codex --session <id> --question "What changed?"`|
22
22
|`brief`| write a bridge brief for another session |`session-absorb brief --source claude --session <id> --question "Absorb and continue"`|
23
23
|`launch`| open a native fork or brief-driven bridge in Terminal |`session-absorb launch --source claude --session <id> --target codex`|
24
+
|`handoff`| write a brief, log it for the next session, optionally launch the target |`session-absorb handoff --done "refactor done" --pending "benchmarks"`|
25
+
|`inbox`| list pending handoffs targeted at this session, cwd, or CLI |`session-absorb inbox`|
26
+
|`ack`| mark a handoff absorbed (referenced by id from `inbox`) |`session-absorb ack 3 --note "got it"`|
24
27
|`db`| inspect the SQLite session catalog and active-state counts |`session-absorb db`|
25
28
|`web`| serve the live local dashboard for sessions and states |`session-absorb web --open-browser`|
26
29
|`install`| install the runtime and skill wrappers into your home directories |`session-absorb install --repo-root <repo-root>`|
@@ -115,6 +118,18 @@ Launch a cross-CLI bridge session from a brief:
115
118
```bash
116
119
session-absorb launch --source claude --session <session-id> --target codex --question "Absorb the design work and continue implementation."
117
120
121
+
Cross-CLI handoff with explicit ack. From Codex, push to a fresh Claude session and require ack:
0 commit comments