Skip to content

Fix team_spawn on opencode 2.x, silent worktree fallback, and unvalidated depends_on - #41

Closed
Its-Satyajit wants to merge 1 commit into
hueyexe:mainfrom
Its-Satyajit:bugfix/opencode-2x-permissions-and-task-validation
Closed

Its-Satyajit wants to merge 1 commit into
hueyexe:mainfrom
Its-Satyajit:bugfix/opencode-2x-permissions-and-task-validation

Conversation

@Its-Satyajit

@Its-Satyajit Its-Satyajit commented Sep 29, 2026 •

Copy link
Copy Markdown

Fixes three of the four bugs in #40. Each fix has a test that fails on main and passes here.

1. team_spawn throws on opencode 2.x (blocker)

src/v2-client.ts:122 called ctx.permission.rules unconditionally. opencode 2.0.4 removed that plugin API, so every spawn died with:

Failed to create session for teammate "alpha": ctx.permission.rules is not a function.

That made the whole plugin unusable on 2.x, not just degraded.

The fix feature-detects the call and skips the re-assert when the API is absent. Skipping rather than deleting matters. The comment at v2-client.ts:118-121 records why the re-assert exists: session.create permissions lose to agent rules, which strips team tools from read-only agents, and rules() evaluates after the agent's rules to restore them. On 2.x the re-assert cannot run, so agent rules still win and read-only agents may lose their team tools. Please call that out in the release notes. It is silent, and it is the one part of this bug I could not verify away.

2. worktree: true reported success and created nothing

On opencode 2.0.19, spawning with worktree: true created no worktree. git worktree list showed only the base directory, a filesystem search for the worktree name found nothing, and both teammates committed straight onto master. The lead saw Teammate "alpha" spawned (agent: build). team_merge later reported No branch to merge for "alpha".

The cause on our side is src/tools/team-spawn.ts:114-124, which catches every worktree.create failure and downgrades it to a TUI toast. Nobody watching the tool output sees it.

The fix appends a warning to the spawn result naming the teammate and stating that they share the working directory, so branch: is never the only thing in the string.

I could not determine why worktree.create produced nothing. opencode 2.0.19 documents the command as loading the project's canonical configuration, creating a worktree with its selected strategy, then running the project's setup script, and no worktree strategy is configured here. A missing project worktree strategy is the likely cause, but I have not confirmed it and this fix does not address the cause.

3. A typo in depends_on produced a permanently dead task

team_tasks_add accepted any string in depends_on. A typo produced a task that was blocked, which team_claim refuses, which team_tasks_complete also refuses. Nothing else edits depends_on, so only purging the team freed it.

The fix validates every dependency against the current team before inserting anything, and rejects the whole call listing the unknown ids. Validation is scoped to team_id, so an id from another team is rejected too. Nothing is inserted when validation fails, so a batch cannot land half-written.

Not fixed here

The fourth bug in #40, teammates in shutdown state redelivering notifications to a lead whose team was purged, is untraced. The team_message table is empty after a purge, so the redelivery is not DB-driven, and I did not find the source. I left it out rather than guess.

Verification

Run with bun install --frozen-lockfile on bun 1.4.2, matching the lockfile.

bun run typecheck   clean, 0 errors
bun run lint        14 warnings, 5 infos, all pre-existing, none in changed files
bun test            856 pass, 0 fail
bun run build       ok
node smoke          node-smoke: ok (runtime node)

One caveat on the test count. recovery.test.ts has a test that intermittently times out at 5s under full-suite load and passes when the file runs alone. It is unrelated to these changes and pre-existing.

A note on how I first read the typecheck. Installing with a newer @types/bun than the lockfile pins produced 50 Response.text/Response.json errors in unrelated test files. Restoring the lockfile version cleared all of them. If you see those errors, check the @types/bun version before assuming they are real.

…on validation

Fixes three bugs from issue hueyexe#40.

- v2-client: feature-detect ctx.permission.rules before the permission
  re-assert. opencode >= 2.0.4 removed the API, so every team_spawn
  threw. The call is skipped, not deleted, so the re-assert still runs
  where the API exists.
- team-spawn: report worktree creation failure in the tool result. The
  catch block only toasted, so the lead saw "spawned" while the teammate
  worked in the shared directory.
- team-tasks-add: validate depends_on ids before inserting. A typo used to
  produce a blocked task that could never be claimed or completed.
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 added a commit that referenced this pull request Oct 19, 2026
…ty, isolation warning

- team_spawn: bind session to the worktree directory when workspace binding
  is unavailable, so the 'edit * allow' rule scopes to the worktree instead
  of the whole shared tree
- v2-client: gitCreateBranch now returns the effective branch (or null);
  logs failures and falls back to 'git switch' for the existing-branch
  re-spawn race. worktree.create records the effective branch only — a
  failed create can no longer point team_merge at a stale same-named branch
  whose commits would silently shadow new work
- v2-client: guard ctx.permission?.rules against a missing permission domain
- team_spawn: spawn result now warns plainly when worktree isolation did
  not complete (cherry-picked from PR #41, issue #40 bug 2)
- tests: branch-failure error path, cross-team depends_on rejection (from
  PR #41)
@hueyexe

hueyexe commented Oct 19, 2026

Copy link
Copy Markdown
Owner

Closing as superseded by #46 — with real credit due: a deep review found your isolationInfo spawn-result warning was the only hunk across all three PRs that closed issue #40's worktree observability gap, and your cross-team depends_on test was the strongest of the set. Both were cherry-picked onto main (see commit 024967a and the v0.20.0 release notes). Your guard (ctx.permission?.rules) was also the most defensive of the three and its optional-chaining form is now on main too. What kept this from merging as-is: #46 additionally fixed the root cause of the worktree failure (missing projectID for the 2.0.19+ worktree API), detached-worktree branch naming, and the V2Context type. One correction for the record: your comment that agent rules still win on 2.x contradicts core's documented merge order from 2.0.19 (merge(agent.permissions, session.permissions), last-match evaluation) — session rules merge last, so create() permissions are honored. Excellent bug report triage in the PR description regardless — the red-first verification methodology was exactly right.

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.

2 participants