diff --git a/src/plugin-handlers/tool-config-handler-task-deny.test.ts b/src/plugin-handlers/tool-config-handler-task-deny.test.ts
new file mode 100644
index 000000000..8ce3d6bc7
--- /dev/null
+++ b/src/plugin-handlers/tool-config-handler-task-deny.test.ts
@@ -0,0 +1,100 @@
+///
+
+import { describe, expect, it } from "bun:test"
+import type { OhMyOpenCodeConfig } from "../config"
+import { OhMyOpenCodeConfigSchema } from "../config"
+import { applyToolConfig } from "./tool-config-handler"
+
+type TestAgent = {
+ permission?: Record
+}
+
+const TASK_DENIED_SUBAGENTS = [
+ "librarian",
+ "explore",
+ "oracle",
+ "multimodal-looker",
+ "metis",
+ "momus",
+] as const
+
+const TASK_ALLOWED_AGENT_NAMES = [
+ "sisyphus",
+ "atlas",
+ "hephaestus",
+ "sisyphus-junior",
+] as const
+
+function createParams(agentNames: readonly string[]): {
+ readonly config: Record
+ readonly pluginConfig: OhMyOpenCodeConfig
+ readonly agentResult: Record
+} {
+ const agentResult: Record = {}
+ for (const agentName of agentNames) {
+ agentResult[agentName] = { permission: {} }
+ }
+
+ return {
+ config: { tools: {}, permission: {} },
+ pluginConfig: OhMyOpenCodeConfigSchema.parse({}),
+ agentResult,
+ }
+}
+
+function requirePermission(
+ agentResult: Record,
+ agentName: string,
+): Record {
+ const permission = agentResult[agentName]?.permission
+ if (!permission) {
+ throw new Error(`Missing permission for ${agentName}`)
+ }
+ return permission
+}
+
+describe("applyToolConfig task permission hard denials", () => {
+ describe("#given read-only and specialist subagents", () => {
+ describe("#when applying tool config", () => {
+ for (const agentName of TASK_DENIED_SUBAGENTS) {
+ it(`#then should explicitly deny task for ${agentName}`, () => {
+ const params = createParams([agentName])
+
+ applyToolConfig(params)
+
+ const permission = requirePermission(params.agentResult, agentName)
+ expect(permission.task).toBe("deny")
+ })
+ }
+ })
+ })
+
+ describe("#given librarian search permissions", () => {
+ describe("#when applying tool config", () => {
+ it("#then should keep grep_app allowed while task is denied", () => {
+ const params = createParams(["librarian"])
+
+ applyToolConfig(params)
+
+ const permission = requirePermission(params.agentResult, "librarian")
+ expect(permission["grep_app_*"]).toBe("allow")
+ expect(permission.task).toBe("deny")
+ })
+ })
+ })
+
+ describe("#given primary and executor agents", () => {
+ describe("#when applying tool config", () => {
+ for (const agentName of TASK_ALLOWED_AGENT_NAMES) {
+ it(`#then should keep task allowed for ${agentName}`, () => {
+ const params = createParams([agentName])
+
+ applyToolConfig(params)
+
+ const permission = requirePermission(params.agentResult, agentName)
+ expect(permission.task).toBe("allow")
+ })
+ }
+ })
+ })
+})
diff --git a/src/plugin-handlers/tool-config-handler.ts b/src/plugin-handlers/tool-config-handler.ts
index f1139f75f..bf07b2261 100644
--- a/src/plugin-handlers/tool-config-handler.ts
+++ b/src/plugin-handlers/tool-config-handler.ts
@@ -4,6 +4,15 @@ import { isTaskSystemEnabled } from "../shared";
type AgentWithPermission = { permission?: Record };
+const TASK_DENIED_SUBAGENT_KEYS = [
+ "librarian",
+ "explore",
+ "oracle",
+ "multimodal-looker",
+ "metis",
+ "momus",
+] as const;
+
function getConfigQuestionPermission(): string | null {
const configContent = process.env.OPENCODE_CONFIG_CONTENT;
if (!configContent) return null;
@@ -21,6 +30,12 @@ function agentByKey(agentResult: Record, key: string): AgentWit
| undefined;
}
+function denyTaskForAgent(agentResult: Record, key: string): void {
+ const agent = agentByKey(agentResult, key);
+ if (!agent) return;
+ agent.permission = { ...agent.permission, task: "deny" };
+}
+
export function applyToolConfig(params: {
config: Record;
pluginConfig: OhMyOpenCodeConfig;
@@ -59,6 +74,10 @@ export function applyToolConfig(params: {
isCliRunMode ? "deny" :
"allow";
+ for (const agentKey of TASK_DENIED_SUBAGENT_KEYS) {
+ denyTaskForAgent(params.agentResult, agentKey);
+ }
+
const librarian = agentByKey(params.agentResult, "librarian");
if (librarian) {
librarian.permission = { ...librarian.permission, "grep_app_*": "allow" };