EnsureProjectOpencode: one discover-or-launch host primitive #267

Closed
opened 2026-07-09 10:20:35 +02:00 by dries · 0 comments
Owner

Parent

#265 — One OpenCode per project: worktree sessions run in-app.

What to build

A new central host capability that is the only code path that
launches opencode: guarantee exactly one opencode instance per project,
rooted at the project's main checkout.

  • New method on hostsvc.Host:
    EnsureProjectOpencode(ctx, req) (result, error). Request carries the
    project directory (any path inside the repo); result carries the
    discovered/launched opencode port (plus resolved repo root + tmux
    session name for observability).
  • Semantics: resolve the repo root (main checkout); discover a
    running opencode for that repo root; if none, launch exactly one
    opencode --port 0 in tmux rooted at the main checkout, seeded with
    OPENCODE_PERMISSION (inline JSON) containing an external_directory
    allow rule scoped to that project's .worktrees/<repo>/** root; wait
    for the port to become discoverable; return it. Idempotent — a
    second call for the same project returns the running instance and
    launches nothing.
  • Runs on the host that owns the directory (local Host, or a remote's
    in-process Host via gRPC), following the existing Host / Router
    (ForDir / ForRemote) seam. Add the remote passthrough (client
    remoteHost impl + Server handler) using the existing
    JsonReq/JsonResp envelope — no protobuf message regeneration.
  • The external_directory rule must be scoped to .worktrees/ only;
    do NOT blanket-allow external directories. It must merge with, not
    overwrite, any inherited permission set (composes with #101).
  • No caller is wired in this ticket — it lands with fakes and tests only.

Acceptance criteria

  • EnsureProjectOpencode on hostsvc.Host, local impl, and remote
    gRPC passthrough all present.
  • Already-discoverable instance → returns its port, launches nothing.
  • No instance → launches exactly once, seeds OPENCODE_PERMISSION
    with the scoped external_directory rule, waits for the port,
    returns it.
  • Two sequential calls for the same project → at most one launch.
  • Non-repo directory → returns git.ErrNotARepo.
  • Tests against a fake runner/discoverer cover idempotency, launch +
    seeding, and the non-repo error. Prior art:
    internal/tmux/launch_test.go, internal/mcp/launcher tests.
  • go test ./... && go vet ./... green; coverage delta ≥ 0.

Blocked by

  • None — can start immediately.
## Parent #265 — One OpenCode per project: worktree sessions run in-app. ## What to build A new central host capability that is the **only** code path that launches opencode: guarantee exactly one opencode instance per project, rooted at the project's main checkout. - New method on `hostsvc.Host`: `EnsureProjectOpencode(ctx, req) (result, error)`. Request carries the project directory (any path inside the repo); result carries the discovered/launched opencode port (plus resolved repo root + tmux session name for observability). - **Semantics**: resolve the repo root (main checkout); discover a running opencode for that repo root; if none, launch exactly one `opencode --port 0` in tmux rooted at the main checkout, seeded with `OPENCODE_PERMISSION` (inline JSON) containing an `external_directory` allow rule scoped to that project's `.worktrees/<repo>/**` root; wait for the port to become discoverable; return it. **Idempotent** — a second call for the same project returns the running instance and launches nothing. - Runs on the host that owns the directory (local `Host`, or a remote's in-process `Host` via gRPC), following the existing `Host` / `Router` (`ForDir` / `ForRemote`) seam. Add the remote passthrough (client `remoteHost` impl + `Server` handler) using the existing `JsonReq`/`JsonResp` envelope — no protobuf message regeneration. - The `external_directory` rule must be scoped to `.worktrees/` only; do NOT blanket-allow external directories. It must **merge** with, not overwrite, any inherited permission set (composes with #101). - No caller is wired in this ticket — it lands with fakes and tests only. ## Acceptance criteria - [ ] `EnsureProjectOpencode` on `hostsvc.Host`, local impl, and remote gRPC passthrough all present. - [ ] Already-discoverable instance → returns its port, launches nothing. - [ ] No instance → launches exactly once, seeds `OPENCODE_PERMISSION` with the scoped `external_directory` rule, waits for the port, returns it. - [ ] Two sequential calls for the same project → at most one launch. - [ ] Non-repo directory → returns `git.ErrNotARepo`. - [ ] Tests against a fake runner/discoverer cover idempotency, launch + seeding, and the non-repo error. Prior art: `internal/tmux/launch_test.go`, `internal/mcp/launcher` tests. - [ ] `go test ./... && go vet ./...` green; coverage delta ≥ 0. ## Blocked by - None — can start immediately.
dries closed this issue 2026-07-09 14:29:36 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dries/ocman#267
No description provided.