fix(opencode): scope project agents to their workspace#21532

open4
main
other-providers-14/opencode-workspace-agents
opened11d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

Project-local OpenCode agents are missing from workspace snapshots, and OpenCode 2 always starts the build agent even when another agent is selected.

Discover visible primary/all agents through each runtime's directory client and publish them as workspace options. Web/desktop and mobile resolve capabilities for the destination cwd and normalize stale choices before sending, while preserving reasoning, project visibility, hidden-model handling, and unavailable Antigravity selections. OpenCode 2 uses the selected agent for prompts and native commands; plan mode remains authoritative. Optional OpenCode 2 agent reads have a three-second budget so two reads plus scan settling stay within the workspace deadline. A failed agent lookup retains successful skills/commands; the registry retains the previous directory's options when available, otherwise clients use the machine catalog.

Upper layer of the replacement for @maria-rcks's #15637, based on #21531 for the workspace-options foundation. The original's agent discovery, filtering, shared projection, selected-agent execution and client intent are preserved in the current provider packages and mobile signatures. The old scan wait/cache churn is omitted; current main's scan lifecycle remains.

Verification: 375 distinct scoped feature tests pass across the implementation and targeted follow-up runs, including 146 focused driver/adapter/mobile cases (139 existing cases retained; one discovery case extended, five native execution rows, one mobile workspace scenario, and one stalled-discovery case). Without the feature implementation, four behavior assertions fail. The added stalled-discovery case independently fails at the actual production 20-second deadline before the timeout fix and passes afterward; the latest fix reran all 146 focused and 39 adjacent cases. Foundation has 87 passing cases; recovery coverage fails before last-known options are retained. Scoped lint, formatting and seven typechecks pass; existing baseline lint warnings are unchanged. Full-stack reviews found and fixed repeated-refresh option loss, optional discovery exhausting the workspace deadline, and three mobile React Compiler bailouts. Existing compiler coverage independently changed from three failures/two passes to five passes; two web compiler checks and all 34 mobile model-option cases also pass, with no added tests. The fourth full-stack review round ended with fresh Claude and Sol reviews finding no blockers at 7da6fe51ad. They independently passed 268 and 240 selected cases respectively, including the existing mobile/web compiler checks.

Live Linux proof: matching discovery screenshots and A/B switching were captured at 6db48fc828. After the registry-only recovery fix, native execution was repeated at 463c2858ce: native OpenCode 1.18.18 lists Triage Reviewer only in project A; project B has Build only; returning to A restores the selection. Selecting Triage Reviewer and sending to free Big Pickle completed with WORKSPACE_AGENT_OK, then FINAL_WORKSPACE_AGENT_OK after restarting that revision and waiting for its directory inventory. A read-only native database check confirms session and user/assistant agent triage-reviewer, correct project directory and normal completion; the project remains clean. Native boundary output.

Before β€” actual foundation base d156601d96, same project, viewport and menu: Before: project-local reviewer missing

After β€” the same discovery UI, unchanged by the later registry recovery and OpenCode 2 timeout fixes: After: project-local reviewer available

Other workspace: Project B: reviewer is absent

Native completed turn: Triage Reviewer completed the requested turn

Workspace selection and switching recording

The headless browser needed a local DejaVu fallback font, loaded identically on base and head. After the live-proof revision, production changes only bound the OpenCode 2 timeout and hoist three mobile expressions without changing their behavior. OpenCode 1 and the web UI shown here are unchanged. OpenCode 2 is verified through real-client HTTP/SSE replay and a controlled clock regression, not a native account. macOS, Windows, iOS, Android, Electron desktop, remote/relay/tunnel clients, and a live mobile build were not verified. The separate scheduled-task model editor retains its existing machine-wide catalog. Before an initial workspace refresh or after snapshot eviction, clients still normalize a saved workspace-only agent to the visible machine default (Build); re-check the agent after reconnect, particularly when the custom agent is more restrictive. MCP capability listing and explicit delegated-option validation remain machine-wide. Removed/unknown native agent IDs surface provider errors rather than silently substituting Build. CI also exposed two missing exports in an existing permission-test mock. The fixture now provides no-worktree state and uses the real model resolver through a partial import; all five permission assertions are unchanged and pass (39 cases with model options). Fresh fifth-round Claude and Sol full-stack reviews found no blockers at 3fbaeca05c; the affected permission/model-option suites pass 39/39, and Claude independently passed 266 selected cases. All executed CI checks pass at final head 3fbaeca05c; the unrelated browser timing failures passed on rerun. The older cancelled native-fingerprint run is superseded by a successful run. Correctness and CodeRabbit checks pass with no unresolved threads. Macroscope's approval check is neutral and explicitly requires human review of agent-default/execution behavior.

Implementation: Codex gpt-6.1-sol (high); tests: Codex gpt-6-astra (high); review: Claude claude-opus-5-5 and Codex gpt-6-sol through T3 Code.

Fixes #11871

Checks

21 successful Β· 10 skipped
All checks passed
5477dba
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval β€” This change adds workspace-specific OpenCode agent discovery and selection across server, web, and mobile, including changing which agent executes prompts and native commands. It also introduces workspace-dependent agent defaults and new discovery timeout behavior, making the runtime and product-default impact broader than a routine bug fix.

Notes:

  • No code objects were reviewed. Approvability was decided on eligibility alone.

No code changes detected at 5477dba. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Thread transfer impact

βœ… Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiBβœ…
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiBβœ…
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiBβœ…
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiBβœ…
CodexLive turn messages220 (0.0%)8βœ…
ClaudeTotal thread wire5.0 KiB5.0 KiB+7 B (+0.1%)6.8 KiBβœ…
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiBβœ…
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB+7 B (+0.6%)2.0 KiBβœ…
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiBβœ…
ClaudeLive turn messages220 (0.0%)8βœ…

Baseline: 7208335 Β· PR result: 5477dba Β· Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Synced from GitHub

Review in Change Stack β†’

No actionable comments were generated in the recent review. πŸŽ‰

ℹ️ Recent review info
βš™οΈ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: e0900c4a-2365-46b1-9741-ff41f3573ec9
πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 3fbaeca05c8597ce5761e1c26c8731dda3ea6d3b and 5477dba4ca4c9f0bda86336b61f669bc02a8675e.

πŸ“’ Files selected for processing: 10
  • apps/mobile/src/features/threads/NewTaskDraftScreen.tsx
  • apps/mobile/src/features/threads/ThreadComposer.tsx
  • apps/mobile/src/features/threads/ThreadSettingsSheet.tsx
  • apps/mobile/src/state/use-thread-composer-state.ts
  • apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
  • apps/web/src/components/ChatView.tsx
  • apps/web/src/components/chat/ChatComposer.tsx
  • packages/provider-opencode/src/server/status.test.ts
  • packages/provider-opencode/src/server/status.ts
  • packages/provider-opencode/src/server/v2/adapter.ts

Limit details: You’ve used all 10 included reviews currently available.

πŸ“ Walkthrough

The changes add working-directory-aware model selection across mobile and web chat flows. OpenCode workspace scans discover agents and expose eligible agents as model options. OpenCode turn handling uses the selected agent, with plan mode selecting the plan agent.

Changes: Workspace-scoped model and agent selection

Layer / File(s)Summary
OpenCode agent discovery and options
packages/provider-opencode/src/server/..., packages/provider-opencode/src/server/*test.ts
Workspace scans load agents with bounded waits and add available agent options to snapshots. Tests cover workspace-specific results, failures, timeouts, and fixtures.
Working-directory model resolution
apps/mobile/src/lib/..., apps/mobile/src/features/threads/..., apps/mobile/src/state/...
Model-option helpers and mobile thread flows resolve providers and selections using the active working directory.
Web provider resolution
apps/web/src/components/...
Web chat resolves provider entries against the active project and worktree directory before deriving provider selection.
OpenCode turn agent selection
packages/provider-opencode/src/server/v2/adapter.ts, apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
Turn handling uses the selected agent outside plan mode and selects the plan agent in plan mode. Tests cover prompts, native commands, and completion.

Priority: βž– Normal

Estimated code review effort: 3 (Moderate) | ~30 minutes

Change: Bug fix

Possibly related PRs

  • pingdotgg/t3code#15637: Introduced related workspace option descriptors, CWD-based provider resolution, and selected-agent execution.

Suggested reviewers: maria-rcks

Merge Risk: βšͺ Minimal Β· up to 5477d

The change scopes OpenCode project agents to their workspace and uses the selected agent for turns. No actionable merge-blocking issue was identified.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main change: limiting OpenCode project agents to their workspace.
Description checkPassedThe description covers the problem, implementation, scope, linked issue, verification results, screenshots, recording, limitations, and agent attribution. It does not use the template headings, but th…
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description covers the problem, implementation, scope, linked issue, verification results, screenshots, recording, limitations, and agent attribution. It does not use the template headings, but the required information is present and the verification details are comprehensive.

✨ Finishing Touches
πŸ“ Generate docstrings
  • Commit to this branch
  • Create a new PR
πŸ§ͺ Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix Β· Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

Comment @coderabbitai help to get the list of available commands.

Added 4 commits

  • test(mobile): preserve permission fixtures with workspace selection5477dba
  • fix(mobile): keep workspace selection compiler compatible96832ac
  • fix(opencode): scope project agents to their workspace9e99722
  • fix(opencode): bound optional workspace agent discoverye0d364b
Synced from GitHub

This would be incredibly helpful πŸ™πŸ»

Synced from GitHub

Another report for the OpenCode 2 half of this PR.

On OpenCode 2 (@opencode/cli), the Agent select is missing from the model options for every model, including with only global agents and no project-local ones. So this isn't limited to project-local agents. The OpenCode 2 catalog path in status.ts only builds the Reasoning option, and the OpenCode 2 adapter's agentFor always returns build, or plan in plan mode. OpenCode 1.x shows the picker as expected.

I'd like this PR to land, because it covers both parts: discovering the agents and then using the selected one. I reproduced the same two gaps independently and wrote a replay test for the execution half: with the Agent option set to a custom primary agent, the OpenCode 2 session receives session.switchAgent for that agent, and with plan mode on it switches to plan regardless of the pick. Happy to share it if it's useful alongside your native execution rows.

Note that the PR currently shows as conflicting with main, which has moved a lot recently (the OpenCode 2 catalog loader in openCode2Catalog.ts now reads models and providers together).

Synced from GitHub

OpenCode 2 half reproduced, with a focused patch

Environment: T3 Code from current main (5211acfe95), Linux web/server, OpenCode 2.2.0 over http://127.0.0.1:4096, no project-local agents.

Confirmed both v2 gaps in this PR's description:

  1. openCode2ModelCapabilities in packages/provider-opencode/src/server/status.ts builds only the variant descriptor. No agent descriptor is emitted from agent.list, so the composer has no Agent control.
  2. agentFor in packages/provider-opencode/src/server/v2/adapter.ts is fixed to plan in plan mode and build otherwise, so a selected agent is never applied.

I implemented a narrower version scoped only to OpenCode 2, in case the v2 half is useful independently of the workspace work. Patch and tests: https://gist.github.com/soares-daniel/308618f601c137d05b1d791adaa8aa68

What it does:

  • loads client.agent.list({ location: { directory } }) and client.config.get(...), emits visible primary/all agents as the existing agent select descriptor, and marks the server's configured default_agent (falling back to build);
  • reads the selected agent model option in agentFor, so the turn's session.switchAgent and the initial session rules use it;
  • in the v2 adapter, keeps the selected agent's deny rules and explicit allows after T3's Full access allow-all, converting only ask to allow.

Verification at 080d0f147a:

  • New status.test.ts case filters hidden and subagent agents, checks the option order, and checks the configured default.
  • New v2/adapter.agent.test.ts covers selected-agent execution in default and plan modes, the no-selection fallback, and Full-access rule order.
  • vp run check:changed passes format, lint, both knip runs, 10 package typechecks, and 47 tests across 3 files.
  • With the provider reconnected, the Agent menu shows Orchestrator Default and Build; the default comes from default_agent in the server config. I did not run a paid provider turn, so this is picker plus focused-test evidence, not a completed live turn. A screenshot is available if useful.

This does not implement per-workspace agent discovery, so it would not fix the 1.x project-local case in #11871 by itself. I have not opened a competing PR.

Synced from GitHub

Two gaps left at 5477dba

I rebased a v2-only version of this on dac8b11ddc to compare. The descriptor and agentFor here match what I had, so I did not open a separate PR. Two behaviors are still missing at 5477dba.

1. The configured default_agent is ignored

openCodeAgentOptionDescriptor picks Build:

ts
1const defaultAgent = visible.find((agent) => agent.name === "build")?.name ?? visible[0]?.name;

OpenCode's config declares which agent should run by default in default_agent, and config.get reports it. Hardcoding Build means T3 preselects an agent the user's config does not ask for, and the picker disagrees with opencode on the same machine. Nothing else reads the config today.

Reading it next to the agents keeps the descriptor input unchanged apart from the default:

ts
1const configuredDefault = yield* client.config.get({ location }).pipe(
2 Effect.map((entries) =>
3 entries.reduce<string | undefined>(
4 (found, entry) =>
5 entry.type === "document" && entry.info.default_agent ? entry.info.default_agent : found,
6 undefined,
7 ),
8 ),
9 // A server that cannot report its config should still list its agents.
10 Effect.orElseSucceed(() => undefined),
11);

Then thread it through as openCodeAgentOptionDescriptor(agents, configuredDefault) and prefer it:

ts
1const defaultAgent =
2 visible.find((agent) => agent.name === configuredDefault)?.name ??
3 visible.find((agent) => agent.name === "build")?.name ??
4 visible[0]?.name;

default_agent is an id, and the call site already normalizes to name: agent.id, so the lookup lines up.

2. The session's first rules are still built for build

agentFor now follows the selection for session.switchAgent, but the initial rules pass in v2/adapter.ts still hardcodes the agent:

ts
1const permissions = yield* rulesFor(
2 { directory, agent: "build", grants: [] },
3 policy,
4 threadInput.threadId,
5);

A session opened with a selected agent therefore gets its first path rules computed for Build, before the switch corrects the agent. rulesFor takes the agent from its first argument, so using the same selector keeps the two in agreement:

ts
1const permissions = yield* rulesFor(
2 { directory, agent: agentFor(threadInput), grants: [] },
3 policy,
4 threadInput.threadId,
5);

Verification for both

Split patch, tested on dac8b11ddc:

  • status.test.ts covers filtering hidden and subagent agents, option order, and the configured default (Build when the config has none).
  • v2/adapter.agent.test.ts covers the selected agent in default and plan mode, and the no-selection fallback.
  • vp run check:changed passes format, lint, knip, 10 package typechecks, and 46 tests across 3 files.
  • Against a live OpenCode 2.2.0 server, the picker lists the configured primary agent first as Default, and Build second. I did not run a paid provider turn, so this is picker plus focused-test evidence.

I am not opening a competing PR for either point. Happy to fold these into this branch if you would rather have them as commits here.