Skip to content

todowrite/todoread cannot be enabled for subagents via agent permission config #19101

Closed

Description

@n3m6

Description

Description

The documentation states that todowrite and todoread are "disabled for subagents by default, but you can enable it manually" via the agent's permission field. However, setting todowrite: allow and todoread: allow in a custom subagent's permission config has no effect — the tools remain unavailable at runtime.

Steps to Reproduce

  1. Create a custom subagent markdown file (e.g., ~/.config/opencode/agents/executor.md):
---
description: Executes markdown plans iteratively
mode: subagent
permission:
  edit: deny
  bash:
    "*": deny
  task:
    "*": deny
    "build": allow
  webfetch: deny
  todowrite: allow
  todoread: allow
---

You are a plan executor agent. Use todowrite and todoread to track tasks.
  1. Invoke the agent via @executor or have a primary agent delegate to it via the Task tool.
  2. The agent attempts to call todowrite.

Expected Behavior

The todowrite and todoread tools should be available to the subagent, as configured in the agent's permission block.

Actual Behavior

⚙ invalid [tool=todowrite, error=Model tried to call unavailable tool 'todowrite'. Available tools: invalid, read, glob, grep, task, skill.]

Root Cause

The Task tool implementation in packages/opencode/src/tool/task.ts hardcodes todowrite and todoread as denied in two places, overriding the agent's permission config:

1. Session creation — hardcoded deny permissions on the child session:

return await Session.create({
  // ...
  permission: [
    { permission: "todowrite", pattern: "*", action: "deny" },
    { permission: "todoread",  pattern: "*", action: "deny" },
    // ...
  ],
})

2. SessionPrompt.prompt call — hardcoded false in the tools object:

const result = await SessionPrompt.prompt({
  // ...
  tools: {
    todowrite: false,
    todoread: false,
    // ...
  },
})

In prompt.ts, the deprecated tools parameter is converted to session-level permissions and applied via Session.setPermission, which overwrites the session permissions set during creation. Since Permission.merge(agent.permission, session.permission) is used at evaluation time, the session-level deny always wins over the agent-level allow.

There is an existing pattern for conditionally skipping this override — the task permission uses a hasTaskPermission check:

const hasTaskPermission = agent.permission.some((rule) => rule.permission === "task")

// ...
permission: [
  // ...
  ...(hasTaskPermission
    ? []
    : [{ permission: "task", pattern: "*", action: "deny" }]),
],

But no equivalent check exists for todowrite/todoread.

Suggested Fix

Add a similar check for todowrite and todoread that respects the agent's permission config:

const hasTodoWritePermission = agent.permission.some(
  (rule) => rule.permission === "todowrite" && rule.action === "allow"
)
const hasTodoReadPermission = agent.permission.some(
  (rule) => rule.permission === "todoread" && rule.action === "allow"
)

Then conditionally include the deny rules in session creation:

permission: [
  ...(hasTodoWritePermission
    ? []
    : [{ permission: "todowrite", pattern: "*", action: "deny" }]),
  ...(hasTodoReadPermission
    ? []
    : [{ permission: "todoread", pattern: "*", action: "deny" }]),
  // ...
],

And similarly for the tools object passed to SessionPrompt.prompt:

tools: {
  todowrite: hasTodoWritePermission ? undefined : false,
  todoread: hasTodoReadPermission ? undefined : false,
  // ...
},

Environment

  • OpenCode version: latest (dev branch as of 2025-03-25)
  • OS: Linux
  • Relevant files: packages/opencode/src/tool/task.ts, packages/opencode/src/session/prompt.ts

Plugins

no plugins

OpenCode version

1.3.0

Steps to reproduce

  1. Create a custom subagent markdown file (e.g., ~/.config/opencode/agents/executor.md):
---
description: Executes markdown plans iteratively
mode: subagent
permission:
  edit: deny
  bash:
    "*": deny
  task:
    "*": deny
    "build": allow
  webfetch: deny
  todowrite: allow
  todoread: allow
---

You are a plan executor agent. Use todowrite and todoread to track tasks.
  1. Invoke the agent via @executor or have a primary agent delegate to it via the Task tool.
  2. The agent attempts to call todowrite.

Screenshot and/or share link

No response

Operating System

Ubuntu 25.10

Terminal

Alacritty

Activity

  1. added
    bugSomething isn't working
    on Mar 25, 2026
  2. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 25, 2026
  3. github-actions commented on Mar 25, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  4. added 4 commits that reference this issue on Mar 25, 2026
    f70b919
    992ccd8
    e575892
    ec283ba
  5. ariane-emory commented on Mar 25, 2026

    @ariane-emory
    Contributor

    The todoread tool was refactored away in its entirety in these two commits, so I'll disregard that part of the issue:

    1. Feb 2, 2026 - Commit 2c2b1ea: Commented out TodoReadTool (changed from active to // TodoReadTool,)
    2. Mar 21, 2026 - Commit fe53af4: Removed the import and commented line entirely during the Effect refactor.

    It appears that agents now receive the contents of the todo list as the return value of the todowrite tool, and there is no longer a separate todoread tool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions