@khalilgharbaoui/opencode-claude-code-plugin 0.60.0 → 0.60.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khalilgharbaoui/opencode-claude-code-plugin",
3
- "version": "0.60.0",
3
+ "version": "0.60.2",
4
4
  "description": "Claude Code CLI provider plugin for opencode",
5
5
  "homepage": "https://opencode-claude-code-plugin.dev/",
6
6
  "funding": {
@@ -155,9 +155,9 @@ Defaults below describe normal headless opencode use when the key is absent.
155
155
  | `compactionModel` | string | `"claude-haiku-4-5"` | `/compact` uses a fresh short-lived process on the selected transport without the usual bridge/proxy/skill wiring. On the PTY it disables built-in tools, uses an empty strict MCP config, submits summary instructions with the transcript as text, and closes the TUI after its answer. Nonblank `CLAUDE_CODE_COMPACTION_MODEL` wins. This is inference and can be billed. |
156
156
  | `ignoreAnthropicApiKey` | boolean | `false` | Strip `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` from headless/interactive spawn env, allowing stored auth to be used. Does not log in, change the parent env, or guarantee subscription billing if other CLI/cloud auth is configured. Warns at startup when either nonempty variable is present, regardless of the flag. |
157
157
  | `idleProcessTimeoutMs` | number | unset | Kill a conversation's idle `claude` worker this many ms after a finished turn. The timer starts when a turn completes, reuse cancels it, and a worker found mid-turn when it fires is re-timed rather than killed. The session id is kept, so the next message resumes transparently. Unset or `0` keeps workers until LRU eviction (16 processes, oldest idle first). Values above `2147483647` are ignored. Applies to the interactive transport too (the TUI is closed; the next message resumes it). Deleting a chat in opencode releases its workers and session ids immediately regardless. |
158
- | `turnStats` | boolean | `false` | Append one `▌ **stats:**` line to each finished turn: cost, wall duration, CLI turn count, input/output/cache-read/cache-write tokens, and a permission-denial count when the turn had any, taken from the CLI's own `result`. Never on a compaction turn or a turn that ended in error. Its own text part, stripped from transcripts rebuilt for the CLI, so the model never sees it. The same numbers are logged at INFO regardless, and `modelUsage` plus `permission_denials` always reach `providerMetadata`. Reported cost is the CLI's figure, not a billing guarantee. |
158
+ | `turnStats` | boolean | `false` | Append one `▌ **stats:**` line to each finished turn: cost, wall duration, CLI turn count, input/output/cache-read/cache-write tokens, and a permission-denial count when the turn had any, taken from the CLI's own `result`. Never on a compaction turn or a turn that ended in error. Its own text part, stripped from transcripts rebuilt for the CLI, so the model never sees it. The same numbers are logged at INFO regardless, and `modelUsage` plus `permission_denials` always reach `providerMetadata`. The cost is THIS turn's: the CLI reports the Claude session's running total, and the footer prints the difference from that session's previous total (the INFO line carries both, `costUsd` and `turnCostUsd`). The first turn of a session resumed after an opencode restart, or of a fork, prints no cost, because `--resume` restores the running total and there is nothing to subtract; the next turn has it again. Not a billing guarantee. |
159
159
  | `forkSessions` | boolean | `false` | When a new opencode session turns out to be a fork of one this provider already served, branch the parent's Claude conversation with `claude --resume <parent> --fork-session` instead of re-rendering the whole thread as text into the first message. Measured on CLI 2.1.280 with haiku 4.5 over a ~13k-token thread: 814 cache tokens written and 39,710 read, against 22,355 written and 17,385 read for the replay, so $0.0058 against $0.0467 for that turn; the parent's transcript is byte-identical afterwards. Neither opencode major tells a provider that a session is a fork, so the parent is found by matching this prompt's history against what each sibling session key was last asked to continue. Off by default because a resumed Claude conversation reuses the system prompt recorded on its FIRST request (`--system-prompt-snapshot`, default `on`), so a forked session answers under the parent's appended system prompt rather than this turn's; measured directly, a parent seeded with codename ZEBRA and forked while passing QUAIL answered ZEBRA. Falls back to the replay, unchanged, for: another account, an unknown or released parent session id, a busy parent (live process, proxied call in flight, unanswered plan-mode question), a fork cut mid-conversation, a fork taken mid tool round trip, a different cwd / model / agent / effort / prompt-cache TTL, compaction, an account-failover switch, and a `claude` whose `--help` does not advertise `--fork-session`. Recording costs nothing while the option is off. |
160
- | `resumeAfterRestart` | boolean | `true` | After an opencode restart, resume the conversation's Claude session (`--resume`) instead of replaying the thread as text. Persists session id + conversation digest per session key in `$XDG_STATE_HOME/opencode-claude-code-plugin/claude-sessions.json` (0600, 256 entries, 30 days) after each successful turn. Resumes only on the same session key and binary, with the transcript on disk and the history equal to the recorded conversation plus Claude's reply; anything else (edit, revert, compaction, account switch, open tool round trip) replays. Not on compaction. Log: `resuming the claude session from before the restart` (NOTICE) or `not resuming ...` with a reason (INFO). `false` disables reading and writing. |
160
+ | `resumeAfterRestart` | boolean | `true` | After an opencode restart, resume the conversation's Claude session (`--resume`) instead of replaying the thread as text. Persists session id + conversation digest per session key in `$XDG_STATE_HOME/opencode-claude-code-plugin/claude-sessions.json` (0600, 256 entries, 30 days) after each successful turn. Resumes only on the same session key and binary, with the transcript on disk and the history equal to the recorded conversation plus Claude's reply; anything else (edit, revert, compaction, account switch, open tool round trip) replays. opencode-dcp's `<dcp-message-id>` references (and its `@12@` compact form) are not part of the digest: dcp renumbers them on every opencode restart, so after an undo the same message came back under another number and the conversation was refused as `conversation-changed`. Records carry a digest `version`; one without it (written by an older plugin) is compared the old way. Not on compaction. Log: `resuming the claude session from before the restart` (NOTICE) or `not resuming ...` with a reason (INFO). `false` disables reading and writing. |
161
161
  | `resumeAcrossModelChanges` | boolean | `true` | When the operator changes a conversation's model or reasoning effort mid-conversation, continue the same Claude session (`--resume <id> --model <new>`) instead of replaying the thread as text. Both are in the session key, so changing either used to start a fresh Claude conversation (issue #91); neither needs one, because `--model` and `CLAUDE_CODE_EFFORT_LEVEL` are spawn-time and the CLI applies either to a resumed transcript (measured on 2.1.288). The session is MOVED off the old key, so one Claude conversation has exactly one owner. Refused on every term `resumeAfterRestart` is refused on (another account, a transcript that is gone, a conversation that changed) plus two more: a sibling whose transcript may still be written to, and anything that is not the same cwd, request scope, opencode session, agent and prompt-cache TTL. Not on compaction, not on an account-failover switch. It reads the record `resumeAfterRestart` writes, so `resumeAfterRestart: false` turns it off too. Log: `continuing this conversation's claude session under the new model or effort` (NOTICE). |
162
162
  | `crossAccountResume` | boolean | `true` | On any account switch (a by-hand pick of another account's model in the same session, the switch form, and the switch back when the override expires), and only between accounts in the same `accountGroups` group, continue the same Claude conversation on the other account instead of replaying the thread as text. An account is a `CLAUDE_CONFIG_DIR` and a conversation is one `projects/<encoded cwd>/<id>.jsonl` inside it, so the switch copies that file into the target account's own projects dir (0600, dir 0700) and keeps the session id for the `--resume` both transports already build. Measured on CLI 2.1.288: a copied transcript resumes under another config dir with its context intact, the CLI resolves a session by FILENAME (not the `sessionId` in the records), it appends to the copy it found rather than to the cwd's path, the source comes out byte-identical, and no record holds a user, org or account id. Never overwrites: an older copy already at the target path (what a switch back finds) makes the carry take a fresh session id, and the live copy is the longest one. Refuses on nothing to carry, a non-file at the target path, or a failed copy, and each refusal falls back to the replay. Not on compaction, and inert with one account. Log: `carried this conversation's claude transcript to the other account` or `replaying this conversation as text on the other account` with a reason (both NOTICE). What is NOT verified live is a different Anthropic login answering another's conversation; `false` keeps the replay. |
163
163
  | `usageWarnThresholds` | number[] | `[50, 75, 90, 95]` | Percent levels of a usage window at which a SERVED turn ends with one `▌ **usage:**` note (its own text part, stripped from rebuilt transcripts): account, window, utilization, reset in local time. Read from every headless `rate_limit_event` (not only a rejected one), whose `utilization` is a FRACTION (`0.9` is 90%) and is ABSENT on an `allowed` event with headroom, which is unknown, never zero, and crosses nothing. Readings persist per account per window in `$XDG_STATE_HOME/opencode-claude-code-plugin/account-usage.json` (`0600`, names, numbers and times only), and so does the dedup: each threshold is said once per account per window across reused processes, sessions and restarts, again only after the window's reset. A crossing in a `/compact` turn or a child session is not said there and is said by the next ordinary turn on the account. Never on `doGenerate`, never turns a served turn into a failure. `[]` turns the notes off but keeps the readings. The single-account name is `default`. Interactive transport: no event, so only a limit reply is recorded (`limited`). Log: `claude account usage crossed a warning threshold` (NOTICE). |
@@ -229,7 +229,7 @@ their secret values. Arbitrary MCP `{env:NAME}` placeholders are outside this li
229
229
  | `CLAUDE_CODE_INTERACTIVE_TRANSPORT` | Fallback when both `transport` and `interactive` are absent: `1` enables; empty/`0`/`false`/`no`/`off` disable (case-insensitive). Explicit `transport` or `interactive: false` wins. |
230
230
  | `CLAUDE_CODE_INTERACTIVE_BYPASS` | Deprecated no-op, like `interactiveBypass`. |
231
231
  | `CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS` | Set to `0` for the interactive TUI unless the operator set it, so a proxied call past 120 s stays in the foreground as on headless. |
232
- | `CLAUDE_CODE_START_WATCHDOG_MS` | Positive integer ms before a headless start or proxy-result continuation is considered silent; default 90000 for missing/invalid/nonpositive values. First expiry respawns, second errors. Bookkeeping-only output is not progress. Keep within timer range; do not lower for routine config checks. |
232
+ | `CLAUDE_CODE_START_WATCHDOG_MS` | Positive integer ms before a headless start or proxy-result continuation is considered silent; default 90000 for missing/invalid/nonpositive values. First expiry respawns, second errors. Bookkeeping-only output is not progress. A process that has not sent its first `system`/`init` yet gets at least its `MCP_TIMEOUT` plus 30 s (150 s by default), since the CLI sends `init` only after its MCP servers connect or time out; the log's `beforeInit` says which delay fired. Keep within timer range; do not lower for routine config checks. |
233
233
  | `CLAUDE_CODE_RESULT_FALLBACK_MS` | Positive integer ms of stdout silence, after the CLI has produced output, before the turn is closed with no `result`; default 60000 for missing/invalid/nonpositive values. The close is announced in the reply as a `▌ **stream timeout:**` note, which is stripped from any rebuilt transcript. An aborted turn gets no note. |
234
234
  | `OPENCODE_CLAUDE_CODE_LOG_FILE` | Overrides `logging.file`: trimmed `0/false/no/off` are false; any other nonempty value is true; empty falls back to config. Prefer `1` or `0`. |
235
235
  | `OPENCODE_CLAUDE_CODE_LOG_DIR` | Overrides `logging.dir`. |
@@ -516,6 +516,15 @@ Tell the user what a pick actually does before recommending one:
516
516
  the copy is refused does the conversation get replayed into a fresh session on the
517
517
  target account, which costs input tokens there and loses anything the CLI held but
518
518
  opencode did not.
519
+ - The turn on the picked account starts with one `▌ **account failover:**` line that says
520
+ which way the conversation arrived: "continues where it stopped" (carried) or
521
+ "replayed into a fresh Claude session there" (not), and names an account block's
522
+ reason instead of "is out of usage".
523
+ - After an earlier pick already moved the conversation (`work` to `personal`), a limit on
524
+ `personal` makes the form name `personal`, not `work`, and offer neither; the
525
+ remembered limit, the usage-limit note and an account-block note's login command are
526
+ `personal`'s too. A pick is still stored under the provider's own account, which is
527
+ where every turn resolves its account from, so the conversation moves on from there.
519
528
  - MCP servers configured only in the limited account's Claude profile will be **missing**
520
529
  on the target account.
521
530
  - `stop`, dismissing the form, or answering with anything that is not one of the offered
@@ -587,7 +596,8 @@ What to tell a user who asks for it, or asks why billing moved:
587
596
  through the same override. Never compaction (it fails outright) and never a title
588
597
  request (no spawn). An available account beats the `fallbackModels` chain, as the form
589
598
  does. Stopping the turn, or cancelling the stream it returned, stops the attempt in
590
- flight and starts no further account.
599
+ flight and starts no further account. (A cancel is a stop in every mode, `"off"` and
600
+ `"ask"` included.)
591
601
  - Verified with a scripted `claude` only; the switch path itself is the one measured
592
602
  live for the form.
593
603
 
@@ -652,7 +662,8 @@ Or once for every discovered subagent without a full provider/model pin:
652
662
  ```
653
663
 
654
664
  Rules, in order: on opencode 2 a model named for that dispatch in the conversation
655
- (the `task` call's `model`) wins over everything here; else `forceModel` wins; else
665
+ (the `task` call's `model`, recipe "One subagent on a model the user names") wins over
666
+ everything here; else `forceModel` wins; else
656
667
  `mode: subagent` with `defaultSubagentModel` set; else untouched. An agent with `model: <provider>/<id>` is left exactly as written,
657
668
  account and all (`model: claude-code-work/claude-opus-5@work` pins the account too).
658
669
  Undeclared built-ins are not discovered; a user definition with a built-in name can
@@ -692,6 +703,67 @@ the opencode schema requires it. Markdown fallback reads top-level scalar fields
692
703
  | `maxBudgetUsd` | Positive dollars, passed as `--max-budget-usd` (per process life, reset on resume). Discovered `mode: subagent` agents only; on a main agent it is refused with a WARN. Headless only. |
693
704
  | `fallbackModels` | Ordered registered bare model ids to try when this agent's model is refused. Both YAML spellings (`[a, b]` or a `- ` block). Replaces the provider-level `fallbackModels` rather than extending it. Keeps the caller's account; an entry carrying `@account` has it stripped. Unknown ids warn and are skipped. |
694
705
 
706
+ ### One subagent on a model the user names (opencode 2)
707
+
708
+ On opencode 2 the user can choose a subagent's model in the message itself, with no
709
+ configuration: the proxied `task` (and each `task_batch.tasks` item) takes an optional
710
+ `model`, forwarded to opencode's own `subagent` tool, which resolves it by exact id
711
+ against the models opencode has. opencode 1's `task` has no such field, so the plugin
712
+ leaves it out there; on 1.x point the user at `forceModel`, `defaultSubagentModel` or
713
+ `subagentDispatch: "ask"` instead. (PR #123, h #g254, h #g255.)
714
+
715
+ opencode's form is `providerID/modelID`, plus `#low`, `#medium`, `#high`, `#xhigh` or
716
+ `#max` for a reasoning variant (every model has them except `claude-haiku-4-5`):
717
+
718
+ | Install | Reference |
719
+ |---|---|
720
+ | No `accounts` | `claude-code/claude-sonnet-5-5` |
721
+ | `accounts`, the default account | `claude-code-default/claude-sonnet-5-5` |
722
+ | `accounts`, another account | `claude-code-<account>/claude-sonnet-5-5@<account>` |
723
+
724
+ A bare model id (`claude-sonnet-5-5`, `claude-sonnet-5-5#high`) is completed to the
725
+ reference this conversation's own provider serves (the first column's provider and
726
+ marker) before opencode sees it, so the subagent stays on the conversation's account.
727
+ Only an id the plugin registers is completed, and only with no `@` marker or the
728
+ provider's own; a full reference, another account's marker and an unknown id reach
729
+ opencode as written. Use the full reference only for another account or provider.
730
+
731
+ Tell the user to name the model by id: "Run the reviewer subagent on
732
+ `claude-sonnet-5-5#high`." Two ids in one request ("review it on `claude-opus-5-5` and
733
+ on `claude-sonnet-5-5`, in parallel") become one `task_batch` with a model per task. A
734
+ model named in words is a guess, and it depends on the model doing the dispatching.
735
+ Measured on opencode 2.0.31 with "a general subagent on Sonnet 5.5" and "on
736
+ claude-sonnet-5-5": Opus 5.5 passed `claude-code/claude-sonnet-5-5` first time; Haiku
737
+ 4.5 passed a bare `claude-sonnet-5-5` first both times, and before bare ids were
738
+ completed went on to `anthropic/claude-sonnet-5-5` and `claude-sonnet-5.5`, each refused
739
+ by opencode (`Invalid model "…"`, `Model "…" is not available`) with no subagent
740
+ started. With the completion both of Haiku's requests ran on the first call. A guessed
741
+ provider that IS in the user's opencode config would be accepted, though: an
742
+ `anthropic` provider serving that id would run the subagent there, outside this plugin
743
+ and billed to that provider. That is the reason to have the user name the model.
744
+
745
+ What the plugin adds on top of forwarding:
746
+
747
+ - The named model beats the agent's `forceModel` and `defaultSubagentModel`, and a
748
+ named `#variant` beats its `reasoningEffort`, which is opencode's own order. With no
749
+ variant the agent's effort still applies. A child resumed by `task_id` with a model
750
+ runs on it.
751
+ - A task that names a model is left out of the `subagentDispatch` form, and a dispatch
752
+ whose every task names one raises no form.
753
+ - A model on a plugin account outside the dispatching account's `accountGroups` group
754
+ is refused before any task of the call starts; `subagentDispatchCrossGroup: true`
755
+ lifts that. A model on any other provider is opencode's routing and is not checked.
756
+ - On 1.x a `model` set anyway is refused before dispatch, for the whole batch.
757
+
758
+ Claude is told to set `model` only when the user asked for one. If it ever sets one
759
+ unasked, that subagent runs on it, under the same rules.
760
+
761
+ Verify: the subagent's sidebar row shows the model it really spawned with, its tool row
762
+ shows the `model` opencode received (none there means opencode picked the model as
763
+ usual), and `plugin.log` has `bare task model completed to this conversation's own
764
+ provider` for a completion and `explicit task model claimed by its child session`. Every spawn logs
765
+ `task model gate` with `supported`, which is false on a 1.x host.
766
+
695
767
  ### Ask before each subagent dispatch
696
768
 
697
769
  Opt-in; off by default. Turns a fan-out into one question instead of a static agent file.
@@ -865,7 +937,7 @@ Names below become `mcp__opencode_proxy__<name>`; input config is case-insensiti
865
937
  | `edit` | `"Edit"`, default; replaces CLI Edit. |
866
938
  | `write` | `"Write"`, default; replaces CLI Write. |
867
939
  | `webfetch` | `"WebFetch"`, default; replaces CLI WebFetch. |
868
- | `task` | `"Task"`, default; disables CLI Agent and dispatches opencode subagents under its permissions. No proxy deadline by default; a positive `proxyToolTimeoutMs` entry adds one. Takes `background: true` only on a host that runs background subagents (see below). |
940
+ | `task` | `"Task"`, default; disables CLI Agent and dispatches opencode subagents under its permissions. No proxy deadline by default; a positive `proxyToolTimeoutMs` entry adds one. Takes `background: true` only on a host that runs background subagents (see below), and `model` only on opencode 2 (recipe "One subagent on a model the user names"). |
869
941
  | `task_batch` | Included with Task; one MCP call fans out two or more independent task inputs concurrently. Separate task calls were measured serial (2026-09-06, two 8-second calls: the second MCP request left the CLI 7 ms after the first resolved). The input must be a `tasks` array of at least two items, each with `description`, `prompt` and `subagent_type`; anything else is refused before the calls are queued. |
870
942
  | `task_status` | Included with Task, and only on a host that runs background subagents. Reads a background subagent's state by `task_id` and collects its result. A recovery path for a completion notification that never arrived, not a progress poll; a result is handed over once. Answered in-process (opencode has no such tool) and refuses any session that is not this conversation's subagent. Not nameable in `proxyTools`. |
871
943
  | `task_cancel` | Included with Task, same host gate as `task_status`. Aborts a background subagent's child session; a cancelled subagent sends no completion notification. |
@@ -884,13 +956,6 @@ rejects what the previous turn left pending and tells the CLI. The process exiti
884
956
  chat being deleted, or opencode exiting rejects the rest. That is why `task` and
885
957
  `task_batch` carry no default deadline and a subagent runs to completion.
886
958
 
887
- On opencode 2, `task` and each `task_batch.tasks` item take an optional `model`: opencode's exact `providerID/modelID` reference with an optional `#variant` (`claude-code/claude-sonnet-5-5#high`; on a multi-account install `claude-code-<account>/<model>@<account>`). The model is told to set it only when the user asked for a particular model, and only with an id the user gave. The proxy forwards it unchanged to opencode's own `subagent` tool, which resolves it against the models it has; omitted, opencode picks the model as usual, and `task_id` and `background` behave as before. What the plugin adds on top (h #g254):
888
-
889
- - An explicit model beats the agent's `forceModel` and `defaultSubagentModel`, and a named `#variant` beats its `reasoningEffort` (opencode's own order). The child's prologue finds the request by parent session, agent type and first message, the dispatch form's rule, and applies it only while the child runs on exactly that model.
890
- - A task that names a model is left out of the `subagentDispatch` form; a dispatch whose every task names one raises no form.
891
- - A model on a plugin account outside the dispatching account's `accountGroups` group is refused before any task of the call starts; `subagentDispatchCrossGroup: true` lifts it. A model on any other provider is opencode's own routing and is not checked.
892
- - opencode 1's `task` has no such field: the plugin reads the live `task` schema, leaves `model` out there, and refuses a call or a whole batch that sets it anyway, before dispatch.
893
-
894
959
  Three timers remain and are distinct from that: the optional per-tool deadlines
895
960
  (`proxyToolTimeoutMs`, a backstop the user chooses), the start and inactivity
896
961
  watchdogs (for a process that is alive but silent, which emits nothing to listen to; a
@@ -1203,6 +1268,8 @@ Useful log lines to search for (redact payloads): `spawning new claude process`,
1203
1268
  `bridged opencode skills into claude`, `interrupt sent for aborted turn`, `btw:`,
1204
1269
  `rendering opencode-side tool result as text`, `proxy-mcp tool call received`,
1205
1270
  `evicting idle claude process`, `evicting LRU claude process`, `background subagent gate`,
1271
+ `task model gate`, `bare task model completed`, `explicit task model claimed by its child session`,
1272
+ `task model refused`,
1206
1273
  `proxy call still waiting`, `fast mode` warnings.
1207
1274
 
1208
1275
  Version requirements. The first four are flag gates in `src/cli-version.ts`; the last two
@@ -1393,6 +1460,10 @@ Prefer the doctor: it needs no logging change and no restart.
1393
1460
  | `Subagent failed (task_id …): Tool execution aborted` while the child finished fine | Bug fixed in 0.15.1 | Upgrade |
1394
1461
  | A `subtask: true` command's subagent output is "lost" | Bug fixed in 0.15.4 | Upgrade |
1395
1462
  | Two subagents run one after another | The CLI serialises MCP calls | Plugin 0.17.0+; the model must use `mcp__opencode_proxy__task_batch` |
1463
+ | On opencode 2, a subagent the user asked for on a particular model ran on another | Claude passed no `model` (the subagent's tool row shows none), most often because the model was named in words and the dispatching model did not turn it into a reference; or the plugin is older than 0.60.0, whose `task` tool had no `model` | Have the user name the model by id (`claude-sonnet-5-5`, completed to this conversation's own account) or by full reference for another account; see "One subagent on a model the user names". If the tool row does carry a `model` and the sidebar row shows another model, that is a bug: ask for `/claude-code-doctor bundle` |
1464
+ | `Invalid model "…"` or `Model "…" is not available` on a subagent row, on opencode 2 | Claude passed a reference opencode does not have, usually a guess at a model named in words | Nothing ran: opencode refused it before starting anything, and Claude normally tries again. A bare id the plugin registers is completed instead of refused, so on a current plugin this is a misspelt id, another account's marker without its provider, or a guessed provider; an older plugin refused every bare id. Naming the model by id or full reference avoids the guessing |
1465
+ | A dispatch refused with `… which is outside this conversation's account group, so no tasks were started` | The `model` sits on a plugin account in another `accountGroups` group | Working as designed. Name a model on an account in this conversation's group, or set `subagentDispatchCrossGroup: true` only if the user wants groups crossed |
1466
+ | On opencode 1, Claude says its task tool cannot take a model, or a dispatch fails with "This opencode's task tool takes no per-call `model`" | opencode 1's `task` has no `model` field | Not available on 1.x. Use an agent's `forceModel`, `defaultSubagentModel`, or `subagentDispatch: "ask"` |
1396
1467
  | Esc does not stop Claude; aborted turns keep running | Plugin older than 0.16.0 | Upgrade |
1397
1468
  | Esc pressed in the first moment of a turn does nothing, and the turn runs and bills anyway | A turn prepares before it asks the CLI for anything (spawn directory, `claude --version`, opencode's MCP status and tool registry), and a stop that landed in that window used to be dropped. Fixed: the turn ends there, spawning nothing and writing nothing, and the reply is empty | Upgrade and fully relaunch every opencode window. Grep `plugin.log` for `abort while the turn was still being prepared` |
1398
1469
  | Under `opencode serve` or the web UI every project spawns Claude in the server's launch dir | Plugin older than 0.16.0 | Upgrade, or pin `cwd` |