Repository navigation
feat(agent-launch): create a folder workspace and start its agent in one host operation - #26083
Conversation
agent.launch can now create a folder workspace and start its agent there, the same operation it already runs for a new git worktree. The host creates the folder workspace (metadata only, no startup terminal), resolves it the way an existing target is resolved, then settles the mode and builds the surface as for any existing folder workspace. Hosts advertise agent.launch.create-folder-workspace.v1 so a client offers the target only to a host that accepts it.
…ke their create method A create-folder-workspace launch could do three things its two-call equivalent never did: - A phone could create folder workspaces. The mobile allowlist admits agent.launch but not folderWorkspace.create, and is checked by method name only. A create target now needs the authorization of the create method it stands for, read from the same allowlist, and a phone is refused with agent_launch_target_forbidden before admission, so no ledger row and no create. create-worktree maps to worktree.create, which phones already may call, so nothing changes for it. - A create refused before anything was stored (group gone, folder missing, SSH host unreachable) replayed as agent_session_operation_unknown, and a retry under the same operation id was refused until the row expired. runtime.createFolderWorkspace now raises those refusals as FolderWorkspaceCreateRefusedError, with the same message text, and the launch records it as failed for any target. A failure after the create still replays unknown. - A paired caller's folder create activated the new chat on the host window and did not select the caller's own tab. Only create-worktree, whose host activation runs setup, keeps the host navigation now; a folder create navigates like an existing workspace. Tests cover the phone refusal, replay of a success, a refused create settling failed and replaying that failure, an after-create failure staying unknown, an SSH connection reaching the agent's view mode, paired navigation, and an older host refusing the target at parse.
A folder create refused before anything was stored is recorded as the launch's failure, and a retry under the same operation id answers from that record. The record went through the 128-character cap every launch failure code gets, and folder refusals carry the folder's absolute path, so a retry could show the user a path cut short: a different folder. The refusal is now recorded whole when it fits a path as long as Linux's PATH_MAX after its code. Past that, which no folder a stat accepts reaches, only the code before the path is kept, so the replay degrades to the bare code instead of a partial path. Also: the controller test asserts the exact refusal message, the create-folder-workspace capability comment says a phone needs its own gate, and the forbidden-target code says why it is not `forbidden`.
… an assertion The changed-code quality gate refuses the `as never` cast on the stub store. It is now a RuntimeStore whose unreached members throw.
…ntime project The operationId replay tests open the real SQLite record store, so the file belongs with the other ledger-backed agent.launch tests.
# Conflicts: # config/scripts/vitest-sqlite-runtime-files.mjs # src/main/runtime/rpc/methods/agent-launch-caller-selection.ts # src/main/runtime/rpc/methods/agent-launch-worktree-creation.ts
…off the host window The folder-create test now asserts surfaceOwner: false on the terminal a paired caller's launch creates, rather than matching any options. The caller-selection header now says only an in-process worktree create keeps worktree.create's navigation.
Review and QA summary (head
|
| Check | Result |
|---|---|
New folder + terminal agent: workspace under its group, createdWithAgent: codex, agent started in that folder with the prompt |
Pass |
| Chat as the default: new-folder launch ends in the same state as the same launch into an existing folder | Pass (parity) |
| Same request replayed: same result, no second folder; changed request, same id: conflict | Pass |
| Missing folder / missing group: clean failure naming the path; replay returns the same failure | Pass |
| Older host (main build): doesn't advertise the capability, refuses the target as invalid, nothing created | Pass |
| Phone pairing: new target refused on both launch requests; existing-workspace launch still works | Pass |
| Existing-workspace and new-worktree launches: unchanged result shape and behaviour | Pass |
| Remote desktop client creates a folder workspace: host window stays on its workspace and tab; the client's own tab list has the new tab active. The local CLI and existing-workspace launches were also checked as controls | Pass |
| SSH host (throwaway Linux container, connected the older way without a managed server): agent runs in the remote folder; host offline gives a clean "path unavailable" failure, and the replay matches | Pass |
| Managed Orca server over SSH: the desktop-side request is refused cleanly and saves nothing. The same request to the server's runtime creates the folder on the server and opens the terminal in that remote folder; replay makes no second folder | Pass |
| SSH with chat default on: the old main bug (empty chat box while the terminal ran) no longer reproduces; the launch opens the terminal | Pass |
Screenshots are in the PR description.
Not verified
- A real agent answering in the chat or terminal (stand-in only); a healthy structured chat session (the stand-in never starts one, so chat was checked only for parity).
- Managed-server offline refusal via the server route; Windows and Linux desktop hosts for this head; the phone app UI (the phone check was protocol-level only).
Unexpected things seen (none caused by this PR)
- Folder workspaces in a project group created without a parent folder don't show in the sidebar. App-created groups have one; groups created through a host request may not.
- With chat as the default and an agent whose chat never starts, the request answers "outcome unknown" after about 16 seconds and leaves an empty terminal tab. This happens identically when launching into an existing folder.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (4)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review. 📝 WalkthroughWalkthroughFolder-workspace creation is now an agent-launch target. The launch contract, runtime capability, and mobile-target authorization support the target. The executor creates the workspace before starting a terminal agent or structured session. The RPC path resolves the workspace scope and connection, and typed creation refusals are preserved in replay outcomes. Paired-client launches select the created folder workspace. Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to No merge-blocking issue is established for this change. The reported post-creation failure outcome should be addressed before a client adopts the new target. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Main's worktree.create caller (#26709) builds a legacy-host launch factory with only createWorktree; type that policy's factory as worktree-only so it needn't implement this PR's createFolderWorkspace, which only agent.launch uses.
|
End-of-review sync with main (merge
|
|
Second end-of-review sync with main (merge
|
ELI5
Orca's host has one request,
agent.launch, that can make a new git worktree and start an agent in it in one step. It couldn't do that for a folder workspace (a plain folder inside a project group, not a git worktree). Starting an agent in a new folder workspace took two separate requests, and the window, not the host, decided chat vs terminal.This PR lets
agent.launchcreate a folder workspace and start its agent in one host request. No button in the app sends it yet; the folder composer moves onto it in the next PR.What Changed
The problem. We are moving every "new workspace + agent" entry point onto one host operation, so the host decides chat vs terminal, where the agent runs, and records what it did (step 3 of the launch unification; earlier parts #26052 and #26060).
agent.launchonly knew two targets: an existing workspace, or a new git worktree. A new folder workspace had no target, so the folder composer could not move onto it.User-facing change. None yet: no client sends the new target in this PR. When the composer moves onto it, a new folder workspace with an agent will be created and started by the host in one step, exactly like starting an agent in an existing folder workspace.
The mechanism.
{ kind: 'create-folder-workspace', create }, wherecreateis the existingfolderWorkspace.createrequest, checked by the same schema.createdWithAgent= the launch's agent), then resolves the new workspace exactly as an existing-folder target is resolved, so its id (folder:<id>) and SSH connection match. From there chat vs terminal and the surface are built exactly as for an existing folder workspace.folderWorkspace.create's permission, checked before anything happens, so a phone with mobile pairing is refused (agent_launch_target_forbidden) while its existing-workspace launches keep working.agent.launch.create-folder-workspace.v1; an older host rejects the unknown target kind, so a client checks this first.folderhere) instead of every create counting as a git worktree; no new stored field.Why
folderWorkspace.createor from an existing-folder launch.Linked Issue
Part of the new-workspace launch unification (step 3a). Earlier parts: #26052, #26060.
Visual Proof
Host-only change: no app control sends the new target, so there is no before/after in the app. These are hidden test-build screenshots taken while sending the new request directly, at head
7283f36ed9d, with a stand-in agent (no real agent ran).Testing
Unit/integration:
agent-launch-folder-workspace-create.test.ts(new, through the realagent.launchhandler with SQLite), plus executor, caller-selection, project-group controller and params tests. At7283f36ed9d:tc:node,tc:web,tc:cli, all repo static checks, and the six named launch test files (91/91) pass; CI passes.Live, on macOS hidden test builds driven by runtime requests (details in the review comment): new folder + terminal agent, chat default, replay and conflict, missing folder / missing group refusals and their replays, an older host refusing the unknown target, phone refusal, existing and new-worktree launches unchanged, the paired-client screen rule, an SSH host (agent runs remotely; offline refusal and replay), and a managed Orca server over SSH (desktop-side request refused cleanly; request to the server's runtime creates and launches there; replay makes no second folder). Windows was not run for this head.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Review
Reviewed in rounds, including an independent design comparison, and a final readiness review on the tree merged with current main. Findings, fixes and deferred items are in the review comment.
Agent skill upstream boundary
Notes
Author: @BrennanKB5
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)