-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Add session forking capability #5882
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements session forking functionality across the full stack (CLI, backend API, and desktop UI), allowing users to create independent copies of sessions with preserved conversation history. This enables exploring different conversation paths without losing the original thread, similar to how Claude Code handles session forking.
Key changes:
- Added
POST /sessions/{id}/forkendpoint that leveragescopy_session()with provider and model preservation - Implemented
--forkCLI flag (requires--resume) supporting session ID, name, or path identifiers - Created fork buttons in SessionListView and ChatInput that open forked sessions in new windows via
useForkSessionhook
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
crates/goose/src/session/session_manager.rs |
Added fork_session() method and fixed copy_session() to preserve provider_name and model_config; includes test for conversation preservation |
crates/goose-server/src/routes/session.rs |
Added fork_session API endpoint handler that returns forked session |
crates/goose-server/src/openapi.rs |
Registered fork_session endpoint in OpenAPI schema |
crates/goose-cli/src/cli.rs |
Added --fork flag with --resume requirement; updated get_or_create_session_id to handle fork logic for ID/name/path identifiers |
crates/goose-cli/src/session/builder.rs |
Added fork field to SessionBuilderConfig struct and updated default/test values |
crates/goose-cli/src/commands/bench.rs |
Set fork: false in benchmark session configuration |
ui/desktop/src/hooks/useForkSession.ts |
Created hook that calls fork API, handles errors/loading, and opens forked session in new window |
ui/desktop/src/components/sessions/SessionListView.tsx |
Added fork button with GitFork icon and handleForkSession callback that reloads sessions on success |
ui/desktop/src/components/ChatInput.tsx |
Added fork button in bottom toolbar with disabled state during forking |
ui/desktop/src/api/types.gen.ts |
Generated TypeScript types for ForkSession API including data, errors, and responses |
ui/desktop/src/api/sdk.gen.ts |
Generated forkSession SDK function as POST to /sessions/{session_id}/fork |
ui/desktop/openapi.json |
Added OpenAPI specification for fork endpoint with 200/404/500 responses |
* main: fix: adjust strange spacing in agent.rs (#5877) Move recipe actions to bottom bar icon and edit goosehints to settings (#5864) [docs] Add “Building a Social Media Agent” Blog Post (#5844) deps: upgrade rmcp to 0.9.1 (#5860) chore: suggest using text/markdown when fetching content (#5854) Revert "fix: do not load active extensions when no extensions in the recipe" (#5871) goose remote access (#5251) docs: add DataHub MCP server extension documentation (#5769)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
DOsinga
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have the same functionality in edit message, this duplicates this with an extra method and an extra route; either remove the old way or use it I would say.
|
Just reiterating what @DOsinga said the desktop now has fork session support in chat
|
* main: (155 commits) remove Tool Selection Strategy preview (#6250) fix(cli): correct bash syntax in terminal integration functions (#6181) fix : opening a session to view it modifies session history order in desktop (#6156) test: fix recipe and audio tests to avoid side effects (#6231) chore: Update gemini versions in test_providers.sh (#6246) feat: option to stream json - jsonl really (#6228) feat: add mcp app renderer (#6095) docs: update skills extension to support .agents/skills directories (#6199) Add YouTube short to Chrome DevTools MCP tutorial (#6244) docs: Caveats for privacy information in logs documentation (#6218) move goose issue solver to opus (#6233) feat: improved UX for tool calls via execute_code (#6205) Blog: Code Mode Doesn't Replace MCP (#6227) fix: prevent keychain requests during cargo test (#6219) test: fix test_max_turns_limit slow execution and wrong message type (#6221) Skills vs MCP blog (#6220) Add blog post: Does Your AI Agent Need a Plan? (#6209) fix(ui): enable MCP UI to send a prompt message when an element is clicked (#6207) docs: param option for recipe deeplink/open (#6206) docs: edit in place or fork session (#6203) ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
|
@DOsinga @zanesq just simplified the PR based your feedback, what do y'all think now? I named this "fork" since that's what Claude Code calls the equivalent functionality I'm trying to implement, but I think I made it confusing since there's already a "Fork Session" in goose UI. what I want here is really "duplicate" instead of "fork"
|
d5c9184 to
3fb2dc7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
* main: (89 commits) fix(google): treat signed text as regular content in streaming (#6400) Add frameDomains and baseUriDomains CSP support for MCP Apps (#6399) fix(ci): add missing dependencies to openapi-schema-check job (#6367) feat: http proxy support Add support for changing working dir and extensions in same window/session (#6057) Sort keys in canonical models (#6403) added validation and debug for invalid call tool result (#6368) Update MCP apps tutorial: fix _meta structure and version prereq (#6404) Fixed fonts (#6389) Update confidence levels prompt injection detection to reduce false positive rates (#6390) Add ML-based prompt injection detection (#5623) docs: update custom extensions tutorial (#6388) fix ResultsFormat error when loading old sessions (#6385) docs: add MCP Apps tutorial and documentation updates (#6384) changed z-index to make sure the search highlighter does not appear on modal overlay (#6386) Handling special claude model response in github copilot provider (#6369) fix: prevent duplicate rendering when tool returns both mcp-ui and mcp-apps resources (#6378) fix: update MCP Apps _meta.ui.resourceUri to use nested format (SEP-1865) (#6372) feat(providers): add streaming support for Google Gemini provider (#6191) Blog: edit links in mcp apps post (#6371) ...
b4105b9 to
1b9cf6f
Compare
* main: (41 commits) Allow customizing the new line keybinding in the CLI (#5956) Ask for permission in the CLI (#6475) docs: add Ralph Loop tutorial for multi-model iterative development (#6455) Remove gitignore fallback from gooseignore docs (#6480) fix: clean up result recording for code mode (#6343) fix(code_execution): handle model quirks with tool calls (#6352) feat(ui): support prefersBorder option for MCP Apps (#6465) fixed line breaks (#6459) Use Intl.NumberFormat for token formatting in SessionsInsights (#6466) feat(ui): format large and small token counts for readability (#6449) fix: apply subrecipes when using slash commands (#6460) Fix: exclude platform_schedule_tool in CLI (#6442) Fix: Small update in how ML-based prompt injection determines final result (#6439) docs: remove SSE transport and rename to Streamable HTTP (#6319) fix: correct Cloudinary extension command and env variable (#6453) fix: add gap between buttons in MacDesktopInstallButtons.js (#6452) refactor: include hidden dotfiles folders in file picker search (#6315) upgraded safe npm packages (#6450) chore(deps): bump react-router and react-router-dom in /ui/desktop (#6408) chore(deps): bump lru from 0.12.5 to 0.16.3 (#6379) ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.
|
LGTM Front end changes look good also tested locally in the desktop app and everything is working. I'll defer to @DOsinga for the cli changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
crates/goose-cli/src/cli.rs:742
- The
--historyflag at line 741 requiresresume, but when--forkis used, the user might also want to see the history. The condition at line 1131 correctly handles(resume || fork) && history, but the CLI argument at line 741 only requiresresume. This means users must specify both--resume --fork --historyinstead of being able to use--fork --history. Consider updating therequiresconstraint to allow--historywith either--resumeor--fork.
/// Show message history when resuming
#[arg(
long,
help = "Show previous messages when resuming a session",
requires = "resume"
)]
b25ebb4 to
fb5f379
Compare
* main: (68 commits) fix(docs): use dynamic import for globby ESM module (#6636) chore: trigger CI Document tab completion (#6635) Install goose-mcp crate dependencies (#6632) feat(goose): standardize agent-session-id for session correlation (#6626) chore: tweak release docs (#6571) fix(goose): propagate session_id across providers and MCP (#6584) increase worker threads for ci (#6614) docs: todo tutorial update (#6613) Added goose doc map md file for goose agent to find relevant doc easily. (#6598) add back goose branding to home (#6617) fix: actually set the working dir for extensions from session (#6612) Multi chat (#6428) Lifei/fixed accumulated token count (#6587) Dont show MCP UI/Apps until tool is approved (#6492) docs: max tokens config (#6596) User configurable templates (#6420) docs: http proxy environment variables (#6594) feat: exclude subagent tool from code_execution filtering (#6531) Fix path for global agent skills (#6591) ...
a67f544 to
cb9bc17
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.
|
* main: docs: ml-based prompt injection detection (#6627) Strip the audience for compacting (#6646) chore(release): release version 1.21.0 (minor) (#6634) add collapsable chat nav (#6649) fix: capitalize Rust in CONTRIBUTING.md (#6640) chore(deps): bump lodash from 4.17.21 to 4.17.23 in /ui/desktop (#6623) Vibe mcp apps (#6569) Add session forking capability (#5882) chore(deps): bump lodash from 4.17.21 to 4.17.23 in /documentation (#6624) fix(docs): use named import for globby v13 (#6639) PR Code Review (#6043) fix(docs): use dynamic import for globby ESM module (#6636) chore: trigger CI Document tab completion (#6635) Install goose-mcp crate dependencies (#6632) feat(goose): standardize agent-session-id for session correlation (#6626)
Co-authored-by: Zane Staggs <zane@squareup.com> Signed-off-by: fbalicchia <fbalicchia@cuebiq.com>
* origin/main: Fix GCP Vertex AI global endpoint support for Gemini 3 models (#6187) fix: macOS keychain infinite prompt loop (#6620) chore: reduce duplicate or unused cargo deps (#6630) feat: codex subscription support (#6600) smoke test allow pass for flaky providers (#6638) feat: Add built-in skill for goose documentation reference (#6534) Native images (#6619) docs: ml-based prompt injection detection (#6627) Strip the audience for compacting (#6646) chore(release): release version 1.21.0 (minor) (#6634) add collapsable chat nav (#6649) fix: capitalize Rust in CONTRIBUTING.md (#6640) chore(deps): bump lodash from 4.17.21 to 4.17.23 in /ui/desktop (#6623) Vibe mcp apps (#6569) Add session forking capability (#5882) chore(deps): bump lodash from 4.17.21 to 4.17.23 in /documentation (#6624) fix(docs): use named import for globby v13 (#6639) PR Code Review (#6043) fix(docs): use dynamic import for globby ESM module (#6636) # Conflicts: # Cargo.lock # crates/goose-server/src/routes/session.rs

This PR adds session forking (duplication) across CLI, backend API, and desktop UI with a unified, simplified approach
Based on feedback this PR was simplified from the original implementation
I often do something like this in Claude Code by running
claude --resume <id> --fork-session:After the change in this PR, now I can do in goose by
goose --resume --session-id <id> --fork.Unified Fork API
edit_messageendpoint →forkand added booleantruncateandcopyparametersfork_session()wrapper (thin wrapper aroundcopy_session()) from original PR implementationuseForkSessionhook, ChatInput fork button from original PR implementationBackend Changes
POST /sessions/{id}/forkwithForkRequest { truncate: bool, copy: bool, timestamp?: i64 }truncate=truerequirestimestamp, returns structuredErrorResponsecopy_session()andtruncate_conversation()primitivescopy_session()to preserveprovider_nameandmodel_configCLI Implementation
--forkflag (requires--resume) duplicates sessionscopy_session()directly (no HTTP endpoint needed)Desktop UI
forkSession({ truncate: false, copy: true })Use Case Matrix
falsetruetruefalseEdit in PlaceUI option)truetrueFork SessionUI option)Addresses #5865