Skip to content

Make handoff a first-class action next to Fork #8720

Closed as not planned
Closed as not planned

Description

@aaronrosenthal

What problem are you trying to solve?

Superset gives you two ways to carry a session forward. One works well, the other doesn't.

Fork session is great. It copies the conversation exactly, which is what you want when you stay in the same agent and directory.

Continue with another agent (and branching a chat into a new worktree) is the other case, when the work has to move. Right now both paste the last 36k characters of the transcript into the new session. In practice that means:

  • You can't say what the next session is for, so the cut often drops the original goal and keeps a long log dump.
  • Secrets that a command printed go along with it. The docs warn about this.
  • You never see what was sent. The next agent treats guesses from the old session as facts.
  • Once the new session starts, the context is gone. You can't reopen it, share it, or save it for tomorrow.

Matt Pocock's /handoff skill does this better. The agent writes a short document for the next task. It links to files and commits instead of copying them, and it strips secrets. You read it before the next agent starts.

The rule I'd use: fork when you stay in the same place; hand off when the work moves.

Proposed solution

Make Hand off… a first-class action next to Fork, starting with the paths that already exist.

flowchart LR
  S[Session] --> Q{Same agent and<br/>same directory?}
  Q -- yes --> F[Fork session]
  Q -- no --> H[Hand off…]
  H --> T1[Headless fork<br/>writes the doc]
  T1 -. can't fork .-> T2[Summarize saved<br/>transcript]
  T2 -. no transcript .-> T3[Raw 36k tail<br/>today's behavior]
  T1 --> R[Strip secrets<br/>+ git state]
  T2 --> R
  T3 --> R
  R --> P[Review and edit] --> L[Launch or save]
Loading

Start here: a better handoff document

fork menu with Hand off…

  1. Ask "What's the next session for?"
  2. Have a headless fork of the session write the document: claude -p --resume <id> --fork-session "write a handoff for …". It has the full context, and the live session isn't interrupted. If an agent can't do this, summarize its saved transcript instead, and keep today's raw tail as the last fallback.
  3. Strip secrets.
  4. Show an editable preview before launch, and mark claims the old session only assumed.

Use this flow for both "Continue with another agent" and "branch into worktree".

step 1, goal and destination

step 2, review

Then, roughly in order:

  • Include git state automatically, and offer to carry uncommitted changes as a patch to a new worktree.
  • Save handoffs so you can reopen one, hand it off again, or see which session came from which.
  • Hand off to another host or cloud sandbox (feat(desktop): teleport a workspace between hosts and cloud sandboxes #8167), to a teammate, or from the CLI. Add a /handoff skill so agents can start one themselves.
  • Side tasks: fork, explore, and send just the result back to the parent pane.

saved handoffs and lineage

side task result

Open question: does a headless fork with -p work for Codex, OpenCode and the other agents, or only Claude? That decides how often the fallback runs.

Workarounds you've tried

  • Running /handoff by hand and pasting the file path into a new pane. It works, but Superset doesn't know about it, and the file sits in $TMPDIR.
  • Forking everything. A fork can't cross worktrees or agents.

Related: #5000 (asks to carry Claude sessions into a new worktree; a handoff solves that where a native fork can't).

Where this lives in the code
  • packages/shared/src/terminal-session-handoff.ts: today's 36k transcript prompt, which becomes the fallback.
  • TerminalSessionHandoffMenu.tsx: the fork / continue menu. Reuse its forkArgs launch for the headless fork.
  • ChatPane/hooks/useForkChat/useForkChat.ts: branch to a worktree, which uses the same prompt.
  • packages/cli/src/commands/agents/create/: --from-terminal, where a CLI handoff would go.

Activity

  1. github-actions commented on Oct 21, 2026

    @github-actions
    Contributor

    This is a feature request, not a bug. Each reference in the issue matches the current code. Below is a note for maintainers.


    Summary. This is a feature request, not a bug report. Today there are two ways to move a session along. Fork session starts a native provider fork using the agent's forkArgs. Continue with another agent, and branching a chat into a new worktree, both seed a new session with the last 36,000 characters of transcript, after removing control codes. The request is a Hand off… action for the cases where work changes agent or directory. In that flow you state what the next session is for, a headless fork of the old session writes a short handoff document, secrets are removed, and you review and edit the result before it launches. The current raw-tail prompt stays as the last fallback. The behaviour described in the issue is accurate.

    Where the current behaviour lives

    • packages/shared/src/session-handoff.ts:14: TERMINAL_HANDOFF_MAX_CHARS = 36_000.
    • packages/shared/src/session-handoff.ts:67-80: buildBoundedTerminalSessionTranscript keeps the tail of the transcript.
    • packages/shared/src/session-handoff.ts:46-57: the only cleaning done. It removes ANSI, OSC and DCS sequences and nothing else, so nothing is redacted.
    • packages/shared/src/session-handoff.ts:113-136 (buildTerminalSessionHandoffPrompt) and :148-172 (buildChatSessionHandoffPrompt): the prompts that wrap the tail.
    • TerminalSessionHandoffMenu.tsx:94-117,151-163: fetches the transcript when the dialog opens. The dialog shows only a character and token count (:273-278); the text itself is never shown or editable. On Continue it calls onCreateNewAgentSession with the built prompt. The fork path (:139-148) passes forkSessionId and an empty prompt.
    • ChatPane/hooks/useForkChat/useForkChat.ts:52-71: branching to a worktree uses buildChatSessionHandoffPrompt with the same 36k tail and queues it with queuePendingChatHandoff. Nothing is saved after the new session starts.
    • packages/cli/src/lib/terminal-handoff.ts:40 and packages/cli/src/commands/agents/create/command.ts:103-130: --from-terminal and --context-chars use the same prompt builder.
    • apps/docs/content/docs/agent-sessions.mdx:53: the docs already warn that the handoff does not redact tokens or keys.

    Root cause. There is no bug. The handoff was built as "bound, sanitize, fence" (the header says the approach came from Orca). Nothing in it summarises the transcript, takes a goal, redacts secrets, shows a preview, or saves the result.

    Notes on the open question (headless fork for each agent)

    Two pieces already exist in packages/shared/src/builtin-terminal-agents.ts:

    • forkCommand is defined for Claude, Codex, OpenCode, Pi, pdev, Grok and Droid. It is not defined for Amp, Gemini, Mastracode or Oh My Pi, so those can never use a fork path.
    • nonInteractiveCommand (headless mode) is defined for most agents. Examples: claude --strict-mcp-config -p, codex exec --skip-git-repo-check, opencode run --agent plan, pi --no-tools -p.

    forkArgs are suffix arguments taken from the interactive command (host-agent-presets.ts:62). A headless fork would need a new, separate field for each agent, for example headlessForkCommand. For Claude it would be claude -p --resume {sessionId} --fork-session. I have not confirmed from the code whether each of the other CLIs can resume and fork in headless mode. Each one needs to be checked by hand. Agents that can't would use the "summarise the saved transcript with nonInteractiveCommand" fallback, and if that also fails, today's 36k tail.

    Suggested direction (from what exists today)

    1. Shared builder. Add a step in packages/shared that takes { goal, transcript | handoffDoc, gitState } and returns the prompt. Keep buildTerminalSessionHandoffPrompt and buildChatSessionHandoffPrompt as the raw-tail fallback.
    2. Redaction. Add a redaction pass before boundTranscriptText and run it on every path, the fallback included. It is a pure function, so a bun:test with fixture strings is enough: AWS keys, ghp_… tokens, Bearer … headers, connection URLs with passwords.
    3. Dialog changes in TerminalSessionHandoffMenu.tsx:
      • Add a "What's the next session for?" field.
      • Generate the document in a host-service procedure that runs the headless fork. This keeps the live PTY untouched.
      • Show the result in an editable textarea instead of only a count, and send the edited text.
    4. Worktree branch. Have useForkChat use the same flow, so worktree branching gets the same document and preview.
    5. Saving handoffs. Storing handoffs for later, and lineage, should go in host-side SQLite, not localStorage, per apps/desktop/AGENTS.md. Any new tRPC procedure has to follow packages/trpc/AGENTS.md so it stays compatible with released clients.

    How to see the current behaviour

    1. In a terminal pane bound to an agent, run a command that prints a fake secret, for example echo AWS_SECRET_ACCESS_KEY=abc123.
    2. Open the fork menu, choose Continue with another agent…, and pick a target.
    3. The dialog shows only a character count. The new session's first prompt contains the secret unchanged.

    A unit test can show the same thing: buildTerminalSessionHandoffPrompt({ transcript: "token=ghp_xxx", sourceTerminalId: "t" }) returns a prompt that still contains ghp_xxx.

  2. aaronrosenthal commented on Nov 5, 2026

    @aaronrosenthal
    ContributorAuthor

    Closing. Discovered the superset:orchestrate skill meets my use cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions