Skip to content

fix(server): isolate sessions per-worktree — require an explicit directory - #40143

Closed
JoshGatto wants to merge 1 commit into
anomalyco:devfrom
JoshGatto:feat/worktree-isolation
Closed

fix(server): isolate sessions per-worktree — require an explicit directory#40143
JoshGatto wants to merge 1 commit into
anomalyco:devfrom
JoshGatto:feat/worktree-isolation

Conversation

@JoshGatto

Copy link
Copy Markdown

What this PR does (plain English)

Makes sure that a session (a chat with the coding agent) always knows which project folder it belongs to — and never silently assumes the folder of whatever process happened to be running the server.

Right now, when a request reaches the server without saying which folder it is for, the server "falls back" to its own current working directory (process.cwd()). That is a problem when the same server is shared across many projects (worktrees): two sessions can end up bound to the wrong folder, or a folder that doesn't belong to anyone, because they inherited the server's folder instead of the session's folder.

This PR changes that rule: a request that does not declare its folder is rejected with a clear 400 error, instead of being silently attached to a guess. The folder must now be provided explicitly, either in the request URL or via the x-opencode-directory header.

Why this matters

  • Correctness — sessions belong to the folder they were started in, not to the server process.
  • Isolation — this is the foundation for safely running one server across many worktrees (per-worktree isolation). Work on this continues in later phases.
  • Predictability — a missing folder now fails loudly and immediately, so the caller knows they forgot something, rather than getting subtly wrong behaviour later.

How (conceptual, no code needed)

The server had three places that used the "fallback to the current folder" rule. All three now follow the new rule: no folder declared → 400 error.

Where What it did before What it does now
Global request middleware Used the server's folder when none was provided Returns 400 "missing directory"
Route-planning middleware Used the server's folder as a last resort Returns 400 "missing directory"
"New session" handler Created sessions in the server's folder by default Rejects the request with 400 unless a folder is given

Sessions that already have a folder (for example, replying to an existing conversation, forking, or renaming) are unaffected — they keep working because the folder is recovered from the session itself.

A regression test was added that proves a folder-less "new session" request is rejected with the new 400 error.

What changed (this phase)

  • 3 server source files (middleware + session handler)
  • 1 test file (new regression test)
  • No user-facing UI changes yet

How it was tested

  • bun run typecheck — all packages pass
  • Server test suite (workspace-proxy, httpapi-provider, httpapi-mcp, httpapi-session) — 37 passing, 1 pre-existing skip, 0 failures

Phases / roadmap

This is Phase 1 of a larger effort to give each worktree a fully isolated server. Later phases (each kept reviewable on its own) will:

  1. Phase 1 — Server hardening (this PR): reject directory-less requests instead of guessing.
  2. Phase 2 — Per-agent enforcement: ensure every agent/session carries its directory end-to-end.
  3. Phase 3 — UI/UX: user-facing behaviour and copy updates (flagged for design review).
  4. Phase 4 — Read-only cross-worktree access: allow viewing sessions across worktrees without mutating them.
  5. Phase 5 — PR / git subagents: directory-aware git and PR tooling.
  6. Phase 6 — Verification & PR polish: full end-to-end checks, docs, and release notes.

Note on process: GitHub's stacked-PR feature requires all branches in the same repository. Because this PR is contributed from a fork (JoshGatto/opencodeanomalyco/opencode), the phases are tracked as clearly separated commits on this branch and described above, so the review history stays readable even without native cross-fork stacking.

Stop binding directory-less requests to the server's process.cwd() so
sessions can never resolve to a shared or server-global worktree.

- LocationMiddleware: 400 when x-opencode-directory / location[directory]
  is absent (packages/server/src/location.ts)
- workspace-routing: drop cwd from defaultDirectory(); new MissingDirectory
  plan returns 400 for directory-less requests
- session.create: reject payloads without a location (400) instead of
  defaulting to process.cwd()
- test: assert directory-less session creation returns a v2 public
  request error (400)
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found several related PRs but none that appear to be true duplicates of PR #40143. Here are the most relevant ones:

Related PRs (not duplicates):

  1. PR fix(server): don't forward host directory to remote workspace #40136fix(server): don't forward host directory to remote workspace

    • Related to directory handling in the server, but specifically about remote workspace scenarios
  2. PR fix(opencode): add --dir option to web/serve; use directory as worktree #35976fix(opencode): add --dir option to web/serve; use directory as worktree

    • Touches on directory/worktree concepts but focused on CLI options
  3. PR fix (core): Multiple clones of same repo are different projects #35311fix(core): Multiple clones of same repo are different projects

    • Related to project/directory isolation but from a different angle
  4. PR fix(tui): scope non-git sessions by directory, not hierarchical path #31210fix(tui): scope non-git sessions by directory, not hierarchical path

    • Directory scoping for sessions but in the TUI layer

No duplicate PRs found

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

Feel free to open a new pull request that follows our guidelines.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Aug 2, 2026
@github-actions github-actions Bot closed this Aug 2, 2026
@JoshGatto
JoshGatto deleted the feat/worktree-isolation branch August 2, 2026 12:33
@JoshGatto
JoshGatto restored the feat/worktree-isolation branch August 2, 2026 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant