Skip to content

Slice 1: Add workspace parameter to amicode_session tool #1060

Closed

Description

@jeonghun-jj-lee

Important

Problem — The amicode_session tool always inherits the parent session's directory — there is no way for an agent to programmatically spawn a child session into an isolated git worktree. The backend APIs exist (POST /experimental/worktree, worktree.ready/worktree.failed events, Session.CreateInput.workspaceID) but the tool does not call them.

Approach — Add an optional workspace string parameter to amicode_session. When "create", call the existing worktree API, wait for readiness with a 30-second timeout, then bind the child session to the new worktree directory. When a path string, validate it as a git worktree of the current project. On any failure, fail hard — never silently fall back to the parent directory. Clean up orphan worktrees on partial failure.

Scope — in: tool schema, parseSpawnArgs extension, handler worktree logic, EngineClientShape extension, timeout + compensating cleanup, feature-gate error translation, soft warning at 5+ worktrees, tests · out: skill prompt updates (Slice 2), lifecycle management tool (Slice 3), engine API changes

Acceptance Criteria

  • amicode_session schema includes workspace with type ["string", "null"] and description documenting "create", path, and null semantics
  • parseSpawnArgs in session_spawn.ts validates the new workspace field: accepts null, "create", or a non-empty string path; rejects other values
  • When workspace: "create", the handler calls the worktree creation API (via engineClient), waits for the worktree.ready event, and creates the child session scoped to the returned worktree directory
  • The synchronous wait has a 30-second timeout — on expiry, the handler attempts DELETE on the partial worktree and returns a timeout error
  • When session creation fails after successful worktree creation, the handler attempts a compensating DELETE of the worktree (best-effort) before returning the session error
  • When workspace: "<path>", the handler validates the path is a git worktree of the current project (the worktree's .git file points back to the main repo's .git directory) and rejects unknown paths with a clear error
  • When the experimental worktrees feature gate is off, the API's rejection is translated into an actionable error message ("Workspace isolation requires the experimental worktrees feature to be enabled")
  • A soft warning is included in the tool's response text when the project already has 5+ active worktrees (does not block creation)
  • The tool fails hard on any worktree error — never silently falls back to the parent directory
  • EngineClientShape is extended with worktree methods (at minimum create, list, remove) so the handler and tests can type-check worktree calls
  • Existing amicode_session behavior is unchanged when workspace is null or omitted

Testing Decisions

Extend the existing test infrastructure in packages/extension/test/:

  • session_spawn.test.ts — add cases for parseSpawnArgs with the workspace field: null, "create", valid path, empty string, non-string → validates the pure arg parsing
  • session_spawn_double_create.test.ts — extend makeMockEngine() with worktree: { create, list, remove } methods; add a test that concurrent workspace: "create" spawns both get their own worktrees (the double-create gate deduplicates sessions, not worktrees)
  • New: session_workspace.test.ts — focused integration tests for the worktree path:
    • workspace: "create" → mock engine returns worktree info → session created with worktree directory
    • workspace: "create" + worktree creation timeout → compensating delete called, tool returns error
    • workspace: "create" + session creation failure after worktree → compensating delete called
    • workspace: "create" + feature gate off (API rejects) → actionable error message
    • workspace: "<path>" with valid worktree → session created with that directory
    • workspace: "<path>" with invalid path → rejection error
    • workspace: null → unchanged behavior (inherits parent directory)

Reuse the makeMockEngine() pattern from existing tests, extended with worktree methods.

Key Decisions

  1. String parameter, not object. workspace is "create" | "<path>" | null — a simple string for LLM reliability. Branch naming is left to the worktree API's default (the opencode/<slug> convention). If explicit branch control is needed later, migrate to an object in Slice 3.

  2. worktree.ready means git worktree add returned 0. It does NOT include project bootstrap (dependency install, etc.). Bootstrap is the child session's skill's responsibility.

  3. Git-worktree-of-this-repo validation. Existing worktree paths are validated by checking the .git file points back to the main repo's .git directory — not limited to the known-sandboxes registry. This accepts manually-created worktrees.

  4. API is the feature-gate authority. The tool does not duplicate the experimental-feature check; it translates the API's rejection into an actionable error.

  5. Error response structure. Tool errors include a reason field distinguishing: timeout, api_rejected (feature gate), validation_failed (bad path), session_failed (post-worktree session error).

Constraints & Invariants

  • The opencode engine's worktree APIs are consumed as-is — no engine changes in this slice
  • The EngineClientShape interface must remain backward-compatible — new worktree methods are optional so existing tests that construct mock engines without them still compile
  • The session_spawn.ts module must remain zero-import (pure policy) — worktree API calls stay in the handler, not the policy module
  • The existing double-create gate (spawnGate.coalesce) continues to work — workspace parameter is included in the gate key so two concurrent workspace: "create" spawns are NOT coalesced (each needs its own worktree)

Prior Art

  • packages/extension/src/amicode_tools_core.ts lines 1941-2149 — the tool definition and handler to modify
  • packages/extension/opencode-plugin/session_spawn.ts — the pure policy module for arg parsing
  • packages/extension/test/session_spawn_double_create.test.ts lines 43-64 — the makeMockEngine() pattern to extend
  • packages/app/src/components/prompt-input/submit.ts lines 357-398 — the UI's worktree creation flow (reference implementation)
  • packages/opencode/src/worktree/index.ts — the Worktree.Service interface and Info type
  • packages/opencode/src/session/session.ts lines 261-272 — Session.CreateInput with the existing workspaceID field

Source

Part of #1059

Activity

  1. jeonghun-jj-lee commented on Sep 14, 2026

    @jeonghun-jj-lee
    ContributorAuthor

    Landed in #1063 (5b25681a) — Slice 1: workspace parameter on amicode_session. Shipped as part of the single-PR #1059 implementation. Closing now.

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

Metadata

Metadata

Labels

afkImplementable without human interaction

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions