Skip to content

fix: tolerate hosts without ctx.permission.rules on session.create - #43

Closed
abcdef8751 wants to merge 1 commit into
hueyexe:mainfrom
abcdef8751:fix/v2-permission-rules-host-compat
Closed

abcdef8751 wants to merge 1 commit into
hueyexe:mainfrom
abcdef8751:fix/v2-permission-rules-host-compat

Conversation

@abcdef8751

Copy link
Copy Markdown

Problem

team_spawn (and any path calling client.session.create with permissions) crashes on current OpenCode hosts:

ctx.permission.rules is not a function. (In 'ctx.permission.rules({ sessionID: created.id, permissions })', 'ctx.permission.rules' is undefined)

opencode 2.0.27+ no longer exposes permission.rules on the plugin context — the permission domain is now request / reply / list / get / asked only. This is the OQ-V2-rules call site: it was spike-verified against 2.0.3, and every spawn on newer hosts throws.

Repro: team_create + team_spawn on opencode v2.0.27 → spawn fails before the teammate session is usable.

Fix

Feature-detect the method in src/v2-client.ts:

  • The rules() call was already best-effort — the permission rules are shipped in the session.create input (permissions: [...]), and the post-create re-assert was only re-applying them after agent rules ran.
  • When the host doesn't expose rules(), skip it cleanly instead of throwing. Fail-open: create proceeds with the permissions that the host does honor.

Testing

  • Added a regression test (test/v2-client.test.ts): session.create with a permission-less permission domain still succeeds, still ships the rules in the create input, and never calls the absent rules().
  • Existing rules() path test unchanged and still passing.
  • bun run typecheck ✅ · bun test 851 passing ✅ · bun run build ✅

Note: this was also verified live — spawned two teammates on opencode v2.0.27, both ran their full team-messaging flow and shut down cleanly.

opencode 2.0.27+ no longer exposes permission.rules on the plugin
context (the permission domain is request/reply/list/get/asked only).
The V2 client called it unconditionally after every session.create,
so team_spawn crashed for every teammate.

Feature-detect the method: the re-assert was already best-effort
(the create-input permissions are still applied), so skip it cleanly
when the host lacks it. Covered by a regression test.

Resolves an upstream OQ (V2-rules) blocking all spawns on current hosts.
@Ayonotx

Ayonotx commented Oct 18, 2026

Copy link
Copy Markdown

Confirmed working on OpenCode 2.0.32 (Windows, Node/Electron desktop + CLI).

Repro of the 0.18.0 bug: every team_spawn fails with 'ctx.permission.rules is not a function' (same as issue #40), tripping the spawn circuit breaker.

Important discovery: applying this PR only to dist/ is NOT enough — OpenCode 2.0.x loads the plugin from src/index.ts and transpiles TypeScript at load time (verified via server logs: 'loading plugin ... entrypoint=file:///.../src/index.ts'). After patching src/v2-client.ts with the exact guard from this PR, spawn works again end-to-end: 2 teammates spawned with explicit models (opencode/deepseek-v4.1-flash-free and opencode/nemotron-3.5-super-vl-free), completed, and shut down cleanly.

Suggestion: merge quickly and consider publishing 0.18.1+ so Desktop/CLI 2.0.27+ users don't have to hand-patch their npm cache (which gets wiped on plugin reinstall). Thanks for the plugin!

hueyexe pushed a commit that referenced this pull request Oct 19, 2026
…, read-only agents (#46)

fixes the `team_spawn` crash + silent worktree failure from #40 on
opencode 2.0.19+, plus the stuff that still stops teammates from working
after that.

## vs #41 / #43

both guard `ctx.permission.rules`, #41 also validates `depends_on`. this
does both, plus:

▸ **worktree root cause**: #41 adds a warning but couldn't find why
`worktree.create` made nothing. 2.0.19+ worktree endpoints need a
`projectID`. ensemble never sent one → creation failed → everyone shared
the base tree. now passes `ctx.location.project.id` to
create/list/remove/refresh

▸ **detached worktrees (2.0.32+)**: opencode now does `git worktree add
--detach` (`packages/core/src/git.ts`). teammate commits land on a
detached HEAD → `team_merge`: "not something we can merge". if the new
worktree has no branch, ensemble creates it

▸ **edits stuck on approval**: v2 checks in-location files as relative
paths, so `edit <worktree>/** allow` never matched → ask nobody answers.
worktree teammates also get `edit * allow`. outside-the-worktree stays
behind `external_directory`

▸ **read-only detection**: was name-only (`plan`, `explore`). custom
reviewers got a worktree + `shell * allow`. now reads the agent's own
rules via `agent.get`, names as fallback

not touched: the 4th #40 thing (notifications redelivered after purge).

on `permission.rules`: since 2.0.19 core merges session rules *after*
agent rules (`merge(agent, session)`, last match wins), so the
`session.create` permissions already win. skipping `rules()` when it's
gone loses nothing.

## verification

✓ `bun run typecheck` clean
✓ `bun test` 857 pass / 0 fail (new: projectID pass-through, detached
naming, read-only from rules, `edit *`, unknown `depends_on`)
✓ `bun run lint` only pre-existing warnings
✓ live on **2.0.24 + 2.0.32**:

```
team_create → team_spawn(build, worktree) → own worktree + branch → commit
           → team_shutdown → team_merge ✓ → team_cleanup
```

✗ not verified: subagent-mode teammates (`explore` etc.) on opencode's
free `big-pickle`. they get "free tier can only be used from within
OpenCode", built-ins too, so it looks like a host/provider thing, not
ensemble.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01GUtz6gBn7rhXaufK97d8cm

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@hueyexe

hueyexe commented Oct 19, 2026

Copy link
Copy Markdown
Owner

Closing as superseded — thank you for the report-quality guard work. All three open PRs (#41, #43, #46) fixed the same broken ctx.permission.rules call from issues #40/#45; a deep review found #46 (plus follow-up fixes now on main) to be the superset: it also fixes the V2Context type declaration (rules? optional), attributes the API removal to the correct version (2.0.19, with documented merge-order reasoning), fixes the root cause of the silent worktree fallback (missing projectID in the 2.x worktree API), and adds depends_on validation. Two notes for future PRs: the version claim in the added comment ("2.0.27+") was factually wrong — #40 reported the break on 2.0.19 — and an unverified behavioral assumption should be marked // OQ-<n> per repo policy rather than asserted in a comment. Your test coverage and clean diff hygiene were solid.

@hueyexe hueyexe closed this Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants