Files
oh-my-opencode/plans/fix-delegate-task-subagent-permissions.md
T

406 lines
30 KiB
Markdown
Raw Normal View History

2026-05-18 11:49:56 +09:00
# Fix Delegate-Task Subagent Permissions
## TL;DR
> Summary: Fix OMO `task` so delegated subagents can use repo exploration tools in their child sessions without permission prompts or denials. Match OpenCode native Task semantics by deriving child-session permissions and prompt tools from the delegated agent instead of only denying `question`.
> Deliverables:
> - Shared subagent permission/tool builder with unit coverage
> - Sync delegate-task child-session permission fix
> - Background and unstable delegate-task permission fix
> - Regression coverage for `read`/`bash`/search access and write/tool delegation denial
> - Module QA plus real tmux/non-interactive QA evidence
> Effort: Medium
> Risk: Medium — permission rules affect delegated child-session execution and can accidentally over-allow tools if not scoped.
## Scope
### Must have
- Subagents launched through OMO `task` can call repo exploration tools such as `read`, `bash`, `grep`, and `glob` in child sessions.
- Sync child sessions are created with `parentID`, OpenCode-compatible title, model fields, directory route, and a derived permission ruleset.
- Background child sessions receive the same derived permission ruleset through `LaunchInput.sessionPermission`.
- Prompt bodies for sync, background launch, background resume, and fallback-agent retry use the same derived prompt tool map so `session.prompt` does not overwrite useful child-session permissions with deny-only rules.
- `question` remains denied for delegated child sessions.
- Read-only subagents still cannot write or recursively delegate: `write`, `edit`, `apply_patch`, `task`, and `call_omo_agent` remain denied where the delegated agent restrictions deny them.
- Existing task metadata contract remains intact: `sessionId` is published and visible task metadata still includes `session_id`.
- Regression tests prove both sync and background paths include explicit `allow` rules for exploration tools and explicit `deny` rules for restricted tools.
- Real tmux/manual QA proves an `explore` subagent launched by `task` can inspect files and run a harmless shell command without `"Permission required"` output.
### Must NOT have (guardrails, anti-slop, scope boundaries)
- Do not disable OpenCode permission checks globally.
- Do not add `permission: "*", action: "allow"` or any broad wildcard allow.
- Do not grant write/edit/apply_patch to `explore`, `librarian`, or `oracle`.
- Do not refactor background polling, concurrency, wake gating, model fallback, or tmux layout.
- Do not change agent prompts, category model selection, metadata formatting, or task output text except where tests require permission metadata.
- Do not remove `getAgentToolRestrictions`; centralize the new derived session permission behavior around it or a closely related shared helper.
- Do not change the native OpenCode source under `../opencode`.
## Verification strategy
> Zero human intervention — all verification is agent-executed.
- Test decision: TDD + Bun test
- QA policy: every task has agent-executed scenarios
- Evidence: `evidence/task-<N>-<slug>.<ext>`
## Execution strategy
### Parallel execution waves
> Target 5-8 tasks per wave. <3 per wave (except final) = under-splitting.
> Extract shared dependencies as Wave-1 tasks to maximize parallelism.
Wave 1 (no dependencies):
- Task 1: Add shared subagent permission/tool builder and focused unit tests
- Task 2: Add native-reference contract tests around existing permission fixtures
Wave 2 (after Wave 1):
- Task 3: depends [1, 2] - Wire sync delegate-task session creation and prompt body
- Task 4: depends [1, 2] - Wire background and unstable delegate-task launch path
- Task 5: depends [1] - Wire background resume and fallback-agent prompt bodies
Wave 3 (after Wave 2):
- Task 6: depends [3, 4, 5] - Run module QA and lock regression output
- Task 7: depends [3, 4, 5] - Run real tmux/manual QA for delegated exploration
Critical path: Task 1 -> Task 3 -> Task 6
### Dependency matrix
| Task | Depends on | Blocks | Can parallelize with |
|------|------------|--------|----------------------|
| 1 | none | 3, 4, 5, 6, 7 | 2 |
| 2 | none | 3, 4, 6, 7 | 1 |
| 3 | 1, 2 | 6, 7 | 4, 5 |
| 4 | 1, 2 | 6, 7 | 3, 5 |
| 5 | 1 | 6, 7 | 3, 4 |
| 6 | 3, 4, 5 | none | 7 |
| 7 | 3, 4, 5 | none | 6 |
## Todos
> Implementation + Test = ONE task. Never separate.
> Every task MUST have: References + Acceptance Criteria + QA Scenarios + Commit.
- [ ] 1. Add shared subagent permission/tool builder
What to do: Create one focused helper, preferably `src/shared/subagent-session-permission.ts`, plus `src/shared/subagent-session-permission.test.ts`. The helper must produce both:
- `buildSubagentSessionPermission(agentName, options): SessionPermissionRule[]`
- `buildSubagentPromptTools(agentName, options): Record<string, boolean>`
Required behavior:
- Convert OMO permission-map values (`"allow" | "deny" | "ask"`) into OpenCode session rules (`{ permission, action, pattern: "*" }`).
- Always include `{ permission: "question", action: "deny", pattern: "*" }`.
- Add explicit `allow` rules for repo exploration tools when not denied by the agent: `read`, `bash`, `grep`, `glob`, `lsp_symbols`, `lsp_goto_definition`, `lsp_find_references`, `lsp_diagnostics`, `ast_grep_search`.
- Apply agent/tool deny rules last so read-only restrictions win over defaults.
- Preserve team-tool denylist behavior when `includeTeamToolDenylist` is true.
- Do not add wildcard allow rules.
Must NOT do: Do not change any call sites yet. Do not change agent definitions. Do not add a generic `utils.ts` or `helpers.ts`.
Parallelization: Can parallel: YES | Wave 1 | Blocks: [3, 4, 5, 6, 7] | Blocked by: []
References (executor has NO interview context — be exhaustive):
- Pattern: `src/shared/agent-tool-restrictions.ts:24` — current read-only denylist omits explicit `read`/`bash` allows, which leaves child sessions in ask/permission-required state.
- Pattern: `src/shared/agent-tool-restrictions.ts:66` — current `getAgentToolRestrictions()` is the source of prompt-body deny rules and team-tool deny rules.
- Pattern: `src/shared/question-denied-session-permission.ts:1` — current ruleset shape and `QUESTION_DENIED_SESSION_PERMISSION`.
- Pattern: `src/shared/permission-compat.ts:6` — OMO agent permission map value type.
- Pattern: `src/agents/explore.ts:27``explore` denies write/edit/apply_patch/task/call_omo_agent and explicitly allows some LSP/AST tools.
- Pattern: `src/agents/librarian.ts:24``librarian` denies write/edit/apply_patch/task/call_omo_agent.
- External: `../opencode/packages/opencode/src/agent/subagent-permissions.ts:17` — native Task derives child-session permissions from parent and subagent rules.
- External: `../opencode/packages/opencode/src/permission/evaluate.ts:9` — missing rule defaults to `ask`, which is the source of permission prompts/denials.
- Test: `src/agents/tool-restrictions.test.ts` — existing assertions around agent permission maps.
Acceptance criteria (agent-executable only):
- [ ] `bun test src/shared/subagent-session-permission.test.ts --bail` passes.
- [ ] Test asserts `buildSubagentSessionPermission("explore")` contains `allow` for `read`, `bash`, `grep`, and `glob`.
- [ ] Test asserts `buildSubagentSessionPermission("explore")` contains `deny` for `write`, `edit`, `apply_patch`, `task`, `call_omo_agent`, and `question`.
- [ ] Test asserts no generated rule is `{ permission: "*", action: "allow", pattern: "*" }`.
- [ ] Test asserts prompt tools mirror the permission intent: exploration tools `true`, restricted tools `false`.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: explore permission builder allows read-only repo exploration
Tool: bash
Steps: mkdir -p evidence && bun test src/shared/subagent-session-permission.test.ts --bail > evidence/task-1-permission-builder.txt
Expected: Exit 0, and test names mention read/bash exploration allow plus write/edit denial.
Evidence: evidence/task-1-permission-builder.txt
Scenario: builder rejects overbroad wildcard allow
Tool: bash
Steps: rg -n 'permission: "\\*", action: "allow"|\\["\\*", true\\]' src/shared/subagent-session-permission.ts src/shared/subagent-session-permission.test.ts > evidence/task-1-wildcard-scan.txt; test ! -s evidence/task-1-wildcard-scan.txt
Expected: Exit 0 and evidence file is empty.
Evidence: evidence/task-1-wildcard-scan.txt
```
Commit: YES | Message: `fix(task): derive subagent exploration permissions` | Files: [`src/shared/subagent-session-permission.ts`, `src/shared/subagent-session-permission.test.ts`]
- [ ] 2. Add native-reference contract tests around current fixtures
What to do: Update current permission tests so they describe the native-compatible contract before wiring code:
- `src/tools/delegate-task/sync-session-creator.test.ts`
- `src/tools/delegate-task/background-task.test.ts`
- `src/features/background-agent/manager-session-permission.test.ts`
The tests must assert that child session creation receives a permission ruleset with explicit exploration allows and restricted-tool denies. Keep existing title, `parentID`, and directory assertions.
Must NOT do: Do not make broad behavior changes in this task except the minimal helper import needed if Task 1 already exists. Do not delete the old `question` denial assertion; update it into the larger ruleset.
Parallelization: Can parallel: YES | Wave 1 | Blocks: [3, 4, 6, 7] | Blocked by: []
References (executor has NO interview context — be exhaustive):
- Pattern: `src/tools/delegate-task/sync-session-creator.test.ts:5` — current sync child-session test only expects `question` deny.
- Pattern: `src/tools/delegate-task/background-task.test.ts:209` — current delegate background launch test only expects `question` deny in `sessionPermission`.
- Pattern: `src/features/background-agent/manager-session-permission.test.ts:84` — manager-level test asserts explicit session permission rules are passed into `session.create`.
- External: `../opencode/packages/opencode/src/tool/task.ts:152` — native Task creates child session with `parentID`, title, and derived permission.
- External: `../opencode/packages/opencode/src/tool/task.ts:178` — native Task metadata includes child `sessionId`.
Acceptance criteria (agent-executable only):
- [ ] `bun test src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/background-task.test.ts src/features/background-agent/manager-session-permission.test.ts --bail` initially fails before Tasks 3 and 4 if run after only test edits.
- [ ] Tests assert `parentID` and title stay unchanged.
- [ ] Tests assert permission arrays contain `allow` for `read` and `bash`.
- [ ] Tests assert permission arrays contain `deny` for `question`, `write`, `edit`, `apply_patch`, and `task`.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: contract tests capture the regression
Tool: bash
Steps: mkdir -p evidence && bun test src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/background-task.test.ts src/features/background-agent/manager-session-permission.test.ts --bail > evidence/task-2-contract-tests.txt || true
Expected: Evidence shows the new expectations before implementation, or passes if Task 3/4 are already applied by parallel execution.
Evidence: evidence/task-2-contract-tests.txt
Scenario: existing metadata contract remains present
Tool: bash
Steps: rg -n 'session_id|sessionId|parentID|@\\$\\{.*subagent|@explore subagent' src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/background-task.test.ts src/features/background-agent/manager-session-permission.test.ts > evidence/task-2-metadata-contract.txt
Expected: Evidence includes session lineage/title assertions, not only permission assertions.
Evidence: evidence/task-2-metadata-contract.txt
```
Commit: YES | Message: `test(task): pin subagent session permission contract` | Files: [`src/tools/delegate-task/sync-session-creator.test.ts`, `src/tools/delegate-task/background-task.test.ts`, `src/features/background-agent/manager-session-permission.test.ts`]
- [ ] 3. Wire sync delegate-task session creation and prompt body
What to do:
- Update `createSyncSession()` to accept an optional `sessionPermission` argument and use it instead of hardcoded `QUESTION_DENIED_SESSION_PERMISSION`.
- Update `executeSyncTask()` to pass `buildSubagentSessionPermission(agentToUse, ...)` on initial child session creation and retry child session creation.
- Update `sendSyncPrompt()` to use `buildSubagentPromptTools(agentToUse, { allowTask })` rather than assembling a deny-only map inline.
- Keep `setSessionTools()` and `applySessionPromptParams()` behavior.
- Keep `routePromptRetry()` and `routePromptSyncRetry()` behavior unchanged.
Must NOT do: Do not alter polling, fetch result, fallback selection, metadata formatting, or `promptAsync` gate behavior.
Parallelization: Can parallel: YES | Wave 2 | Blocks: [6, 7] | Blocked by: [1, 2]
References (executor has NO interview context — be exhaustive):
- Pattern: `src/tools/delegate-task/sync-session-creator.ts:20` — current sync child session creation hardcodes `QUESTION_DENIED_SESSION_PERMISSION`.
- Pattern: `src/tools/delegate-task/sync-task.ts:88` — initial sync child session is created here.
- Pattern: `src/tools/delegate-task/sync-task.ts:264` — fallback retry creates another sync child session and must receive the same derived permission rules.
- Pattern: `src/tools/delegate-task/sync-prompt-sender.ts:70` — prompt body currently builds tools from `getAgentToolRestrictions()` only.
- Pattern: `src/tools/delegate-task/sync-prompt-route.test.ts:16` — existing route tests must keep passing.
- External: `../opencode/packages/opencode/src/tool/task.ts:194` — native Task prompts `nextSession.id`, not parent session.
- External: `../opencode/packages/opencode/src/session/prompt.ts:1622` — prompt `tools` are converted into session permission rules, so prompt body must not erase exploration allows.
Acceptance criteria (agent-executable only):
- [ ] `bun test src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/sync-prompt-sender.test.ts src/tools/delegate-task/sync-prompt-route.test.ts src/tools/delegate-task/sync-task.test.ts --bail` passes.
- [ ] `createSyncSession()` tests prove sync child session body includes `allow` rules for `read` and `bash`.
- [ ] `sendSyncPrompt()` tests prove prompt body tools include `read: true`, `bash: true`, `grep: true`, `glob: true`, `question: false`, and `write/edit/apply_patch/task` false for `explore`.
- [ ] Sync route tests still prove prompts are routed to the child session directory.
- [ ] Retry path tests prove fallback child sessions also receive derived permission rules.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: sync task creates an exploration-capable child session
Tool: bash
Steps: mkdir -p evidence && bun test src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/sync-prompt-sender.test.ts src/tools/delegate-task/sync-prompt-route.test.ts src/tools/delegate-task/sync-task.test.ts --bail > evidence/task-3-sync-permissions.txt
Expected: Exit 0; evidence contains passing sync permission and prompt-body tests.
Evidence: evidence/task-3-sync-permissions.txt
Scenario: sync prompt still denies recursive delegation and writes
Tool: bash
Steps: bun test src/tools/delegate-task/sync-prompt-sender.test.ts --bail > evidence/task-3-sync-denies.txt
Expected: Exit 0; tests assert `task`, `call_omo_agent`, `write`, `edit`, and `apply_patch` are false for read-only subagents.
Evidence: evidence/task-3-sync-denies.txt
```
Commit: YES | Message: `fix(task): pass derived permissions to sync subagents` | Files: [`src/tools/delegate-task/sync-session-creator.ts`, `src/tools/delegate-task/sync-task.ts`, `src/tools/delegate-task/sync-prompt-sender.ts`, related tests]
- [ ] 4. Wire background and unstable delegate-task launch path
What to do:
- Update `executeBackgroundTask()` to pass `buildSubagentSessionPermission(normalizedAgent, ...)` into `manager.launch()`.
- Update `executeUnstableAgentTask()` to pass the same derived permission builder into `manager.launch()`.
- Update `BackgroundManager`/`startTask()` permission tests to expect derived session permissions.
- Keep `LaunchInput.sessionPermission` optional for other callers.
- Keep background metadata and `buildTaskMetadataBlock()` output unchanged.
Must NOT do: Do not change background task concurrency, polling, idle detection, parent wake notification, or cancellation behavior.
Parallelization: Can parallel: YES | Wave 2 | Blocks: [6, 7] | Blocked by: [1, 2]
References (executor has NO interview context — be exhaustive):
- Pattern: `src/tools/delegate-task/background-task.ts:116` — background delegate-task launch currently passes only `QUESTION_DENIED_SESSION_PERMISSION`.
- Pattern: `src/tools/delegate-task/unstable-agent-task.ts:32` — unstable-agent path also passes only `QUESTION_DENIED_SESSION_PERMISSION`.
- Pattern: `src/features/background-agent/types.ts:102` — `LaunchInput.sessionPermission` type is already the correct extension point.
- Pattern: `src/features/background-agent/spawner.ts:100` — `startTask()` passes `input.sessionPermission` into `client.session.create`.
- Test: `src/tools/delegate-task/background-task.test.ts:209` — update this existing background permission assertion.
- Test: `src/tools/delegate-task/unstable-agent-permission.test.ts` — update unstable path assertion.
- Test: `src/features/background-agent/manager-session-permission.test.ts:84` — manager-level permission passthrough coverage.
Acceptance criteria (agent-executable only):
- [ ] `bun test src/tools/delegate-task/background-task.test.ts src/tools/delegate-task/unstable-agent-permission.test.ts src/features/background-agent/manager-session-permission.test.ts --bail` passes.
- [ ] Background launch tests assert `manager.launch().sessionPermission` includes `read`/`bash` allows for `explore`.
- [ ] Background launch tests assert write/edit/apply_patch/task/call_omo_agent/question denies remain.
- [ ] Manager passthrough test proves `client.session.create().body.permission` receives the derived ruleset exactly.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: background launch passes derived permissions through manager
Tool: bash
Steps: mkdir -p evidence && bun test src/tools/delegate-task/background-task.test.ts src/tools/delegate-task/unstable-agent-permission.test.ts src/features/background-agent/manager-session-permission.test.ts --bail > evidence/task-4-background-permissions.txt
Expected: Exit 0; evidence shows background and unstable permission tests pass.
Evidence: evidence/task-4-background-permissions.txt
Scenario: background metadata remains OpenCode-compatible
Tool: bash
Steps: bun test src/tools/delegate-task/background-task.test.ts --bail > evidence/task-4-background-metadata.txt
Expected: Exit 0; existing metadata tests still pass and visible output contains `session_id`.
Evidence: evidence/task-4-background-metadata.txt
```
Commit: YES | Message: `fix(task): pass derived permissions to background subagents` | Files: [`src/tools/delegate-task/background-task.ts`, `src/tools/delegate-task/unstable-agent-task.ts`, `src/features/background-agent/manager-session-permission.test.ts`, related tests]
- [ ] 5. Wire background resume and fallback prompt bodies
What to do:
- Update `src/features/background-agent/spawner.ts` initial prompt body, resume prompt body, and fallback-agent prompt body to use `buildSubagentPromptTools()`.
- Keep `includeTeamToolDenylist: input.teamRunId === undefined` behavior.
- Keep fallback agent behavior, `releasePromptAsyncReservation()`, and `task.agent = FALLBACK_AGENT` unchanged.
- Add tests that `promptAsync` body for launch and resume includes `read: true`, `bash: true`, and restricted-tool denies for `explore`.
Must NOT do: Do not change session creation, concurrency release, tmux callback timing, or fallback-agent selection.
Parallelization: Can parallel: YES | Wave 2 | Blocks: [6, 7] | Blocked by: [1]
References (executor has NO interview context — be exhaustive):
- Pattern: `src/features/background-agent/spawner.ts:158` — initial background prompt body currently builds tool map inline.
- Pattern: `src/features/background-agent/spawner.ts:29` — fallback prompt body currently builds a second inline tool map.
- Pattern: `src/features/background-agent/spawner.ts:299` — resume prompt body currently builds another inline tool map.
- Test: `src/features/background-agent/manager-session-permission.test.ts:9` — already captures prompt route and can be extended or paired with a new focused test.
- External: `../opencode/packages/opencode/src/session/prompt.ts:1622` — prompt body tools become session permission rules.
Acceptance criteria (agent-executable only):
- [ ] `bun test src/features/background-agent/manager-session-permission.test.ts src/features/background-agent/manager.test.ts src/features/background-agent/spawner.test.ts --bail` passes, or if `manager.test.ts` is too broad/slow, record the narrower replacement command in evidence.
- [ ] A launch prompt test asserts exploration tools are explicitly true and restricted tools false.
- [ ] A resume prompt test asserts the same tool map contract.
- [ ] Existing fallback-agent retry tests still pass.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: background launch prompt keeps exploration tools enabled
Tool: bash
Steps: mkdir -p evidence && bun test src/features/background-agent/manager-session-permission.test.ts --bail > evidence/task-5-background-prompt-tools.txt
Expected: Exit 0; evidence includes prompt body assertions for read/bash and restricted-tool denies.
Evidence: evidence/task-5-background-prompt-tools.txt
Scenario: no prompt gate or fallback routing regression
Tool: bash
Steps: bun test src/features/background-agent/manager.test.ts src/features/background-agent/spawner.test.ts --bail > evidence/task-5-background-manager.txt
Expected: Exit 0, or if pre-existing unrelated failures occur, evidence includes exact failing test names and a narrower passing command that covers spawner prompt behavior.
Evidence: evidence/task-5-background-manager.txt
```
Commit: YES | Message: `fix(background-agent): keep exploration tools enabled in subagent prompts` | Files: [`src/features/background-agent/spawner.ts`, `src/features/background-agent/manager-session-permission.test.ts`, related tests]
- [ ] 6. Run module QA and lock regression evidence
What to do:
- Run focused delegate-task/background-agent tests.
- Run typecheck.
- Run the full root test suite if focused tests and typecheck pass.
- Capture evidence files and summarize failures only if unrelated/pre-existing.
Must NOT do: Do not fix unrelated failures. Do not weaken tests to pass. Do not skip typecheck.
Parallelization: Can parallel: YES | Wave 3 | Blocks: [] | Blocked by: [3, 4, 5]
References (executor has NO interview context — be exhaustive):
- Command: `bun test src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/sync-prompt-sender.test.ts src/tools/delegate-task/sync-prompt-route.test.ts src/tools/delegate-task/sync-task.test.ts src/tools/delegate-task/background-task.test.ts src/tools/delegate-task/unstable-agent-permission.test.ts src/features/background-agent/manager-session-permission.test.ts --bail`
- Command: `bun run typecheck`
- Command: `bun test`
- Pattern: `package.json` — scripts use Bun only; no npm/yarn/pnpm.
Acceptance criteria (agent-executable only):
- [ ] Focused delegate-task/background-agent test command exits 0.
- [ ] `bun run typecheck` exits 0.
- [ ] `bun test` exits 0, or evidence documents exact unrelated pre-existing failures with focused command still green.
- [ ] No `as any`, `@ts-ignore`, or `@ts-expect-error` introduced.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: focused module regression suite
Tool: bash
Steps: mkdir -p evidence && bun test src/tools/delegate-task/sync-session-creator.test.ts src/tools/delegate-task/sync-prompt-sender.test.ts src/tools/delegate-task/sync-prompt-route.test.ts src/tools/delegate-task/sync-task.test.ts src/tools/delegate-task/background-task.test.ts src/tools/delegate-task/unstable-agent-permission.test.ts src/features/background-agent/manager-session-permission.test.ts --bail > evidence/task-6-focused-tests.txt
Expected: Exit 0.
Evidence: evidence/task-6-focused-tests.txt
Scenario: typecheck and anti-suppression scan
Tool: bash
Steps: bun run typecheck > evidence/task-6-typecheck.txt && rg -n 'as any|@ts-ignore|@ts-expect-error' src/shared/subagent-session-permission.ts src/tools/delegate-task src/features/background-agent > evidence/task-6-suppression-scan.txt || true
Expected: Typecheck exits 0; suppression scan contains no new suppressions in changed files.
Evidence: evidence/task-6-typecheck.txt
```
Commit: NO | Message: `test(task): verify delegate-task permission regression` | Files: [`evidence/task-6-focused-tests.txt`, `evidence/task-6-typecheck.txt`, `evidence/task-6-suppression-scan.txt`]
- [ ] 7. Run real tmux/manual QA for delegated exploration
What to do:
- Build the local plugin.
- Run a real OMO non-interactive session inside tmux from this repo that forces `task(subagent_type="explore", run_in_background=false or true)` to inspect a known file and run a harmless shell command.
- Confirm output contains the expected file fact and does not contain `"Permission required"`, `"missing permission"`, or `"permission denied"` for `read`/`bash`.
- Repeat with background mode and collect `background_output` after system completion.
- Capture tmux pane output and `/tmp/oh-my-opencode.log` excerpts.
Must NOT do: Do not run destructive shell commands. Do not use `sleep`; use tmux capture/polling loops with bounded attempts.
Parallelization: Can parallel: YES | Wave 3 | Blocks: [] | Blocked by: [3, 4, 5]
References (executor has NO interview context — be exhaustive):
- Command: `bun run build` — local plugin build.
- Command: `bun src/cli/index.ts run --agent Sisyphus --directory /Users/yeongyu/local-workspaces/omo --json "<message>"`
- Pattern: `src/cli/cli-program.ts:74` — local CLI supports `run <message>`.
- Pattern: `src/cli/run/AGENTS.md` — run command waits for todos/background tasks.
- Pattern: `src/tools/delegate-task/tools.ts:21` — `run_in_background` controls sync/background delegation.
- Pattern: `/tmp/oh-my-opencode.log` — project logger destination.
Acceptance criteria (agent-executable only):
- [ ] `bun run build` exits 0.
- [ ] tmux sync QA output includes an `explore` result referencing `src/tools/delegate-task/sync-session-creator.ts`.
- [ ] tmux sync QA output has no case-insensitive match for `Permission required|missing permission|permission denied`.
- [ ] tmux background QA output includes a background task ID and collected result.
- [ ] `/tmp/oh-my-opencode.log` has no child-session permission rejection for the QA session.
QA scenarios (MANDATORY — task incomplete without these):
```
Scenario: sync delegated explore can read and run harmless bash
Tool: tmux
Steps: mkdir -p evidence && bun run build > evidence/task-7-build.txt && tmux new-session -d -s omo-delegate-sync-qa 'cd /Users/yeongyu/local-workspaces/omo && bun src/cli/index.ts run --agent Sisyphus --directory /Users/yeongyu/local-workspaces/omo --json "Use task with subagent_type=explore, run_in_background=false, load_skills=[] to inspect src/tools/delegate-task/sync-session-creator.ts and run pwd. Report the permission field behavior and the cwd."' ; poll `tmux capture-pane -pt omo-delegate-sync-qa` until the command exits or the pane shows JSON; save final capture.
Expected: Capture includes a useful exploration result and no permission-required text.
Evidence: evidence/task-7-sync-tmux.txt
Scenario: background delegated explore can read and run harmless bash
Tool: tmux
Steps: tmux new-session -d -s omo-delegate-bg-qa 'cd /Users/yeongyu/local-workspaces/omo && bun src/cli/index.ts run --agent Sisyphus --directory /Users/yeongyu/local-workspaces/omo --json "Launch task subagent_type=explore with run_in_background=true and load_skills=[] to inspect src/shared/agent-tool-restrictions.ts. Wait for completion notification, collect background_output, and report whether read/bash were usable."' ; poll `tmux capture-pane -pt omo-delegate-bg-qa` until JSON or completion; save final capture and relevant log excerpt.
Expected: Capture includes background result and no permission-required text.
Evidence: evidence/task-7-background-tmux.txt
```
Commit: NO | Message: `test(task): capture real delegate-task permission QA` | Files: [`evidence/task-7-build.txt`, `evidence/task-7-sync-tmux.txt`, `evidence/task-7-background-tmux.txt`]
## Final verification wave (MANDATORY — after all implementation tasks)
> Runs in PARALLEL. ALL must APPROVE. Surface results to the caller and wait for an explicit "okay" before declaring complete.
- [ ] F1. Plan compliance audit — every task done, every acceptance criterion met
- [ ] F2. Code quality review — diagnostics clean, idioms match, no dead code
- [ ] F3. Real manual QA — every QA scenario executed with evidence captured
- [ ] F4. Scope fidelity — nothing extra shipped beyond Must-Have, nothing Must-NOT-Have introduced
## Commit strategy
- One logical change per commit. Conventional Commits (`<type>(<scope>): <subject>` body + footer).
- Atomic: every commit builds and passes tests on its own.
- No "WIP" / "fix typo squash later" commits on the final branch — clean up before merge.
- Reference the plan file path in the final commit footer: `Plan: plans/fix-delegate-task-subagent-permissions.md`.
## Success criteria
- All Must-Have shipped; all QA scenarios pass with captured evidence; F1F4 approved; commit history clean.