opencode-raven 2.3.2 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.3
4
+
5
+ ### Fixed
6
+ - V2 Raven agents auto-approve webfetch, websearch, fetch, and enabled global MCP tools at permission evaluation time, without blanket agent permissions. Main-agent permissions and explicit denials remain unchanged.
7
+ - Blocked web search, URL fetching, and recognized global MCP calls now recommend `raven_mcp`; local search calls still recommend `raven_seek`. Routing availability and provider recovery use the selected agent.
8
+
9
+ ### Changed
10
+ - Raven MCP now has the same retrieval tools as Raven Search, including local file access, shell, and built-in web tools, plus its private on-demand MCP bridge. Edit tools and nested delegation remain denied. V2 web/global MCP execution approvals apply to both Raven agents.
11
+ - Delegation instructions distinguish lightweight local retrieval through `raven_seek` from online research through `raven_mcp`, even when no MCP is configured.
12
+
3
13
  ## 2.3.2
4
14
 
5
15
  ### Added
package/README.md CHANGED
@@ -18,8 +18,8 @@
18
18
  <h2>Why Raven</h2>
19
19
  <p>Raven delegates search and on-demand MCP retrieval to separate focused agents, then returns compact evidence to the calling session.</p>
20
20
  <ul>
21
- <li>Routes OpenCode search tools and globally configured MCPs through <code>raven_seek</code>.</li>
22
- <li>Uses a separately configurable model for on-demand MCP retrieval through <code>raven_mcp</code>.</li>
21
+ <li>Routes local search and filesystem discovery through lightweight <code>raven_seek</code>.</li>
22
+ <li>Uses a separately configurable model for online research, built-in web tools, and global or on-demand MCPs through <code>raven_mcp</code>.</li>
23
23
  <li>Keeps optional on-demand MCP schemas out of the main model's tool list.</li>
24
24
  <li>Preconfigures Context7, Exa, and Grep.app endpoints.</li>
25
25
  <li>Tracks estimated main-session context avoided by delegation.</li>
@@ -34,7 +34,17 @@
34
34
 
35
35
  ### OpenCode V2
36
36
 
37
- Use the v2 `plugins` key in `opencode.jsonc`:
37
+ In OpenCode's **Install plugin** feature, enter `opencode-raven`.
38
+
39
+ Or install globally from the CLI:
40
+
41
+ ```sh
42
+ opencode plugin add opencode-raven
43
+ ```
44
+
45
+ Either way, OpenCode manages the plugin configuration and automatically loads Raven's terminal companion—no separate terminal plugin install is needed.
46
+
47
+ For manual configuration, use the v2 `plugins` key in `opencode.jsonc` instead:
38
48
 
39
49
  ```jsonc
40
50
  {
@@ -94,7 +104,7 @@ In this run, Raven handled the search-heavy web research in a child session and
94
104
  **Raven works automatically.** Ask OpenCode for what you need as usual. You do not need to mention Raven, run a command, or manually call a delegation tool.
95
105
 
96
106
  1. Your agent attempts to use a routed search, fetch, shell-discovery, or MCP tool.
97
- 2. Raven blocks the noisy direct call and gives the agent the exact `raven_seek` retry.
107
+ 2. Raven blocks the noisy direct call and gives the agent the exact retry: `raven_seek` for local searches, or `raven_mcp` for web search, URL fetching, and global MCP tools.
98
108
  3. The selected Raven agent creates a session attached directly to the root session or resumes one for a related follow-up.
99
109
  4. Raven performs retrieval work and returns compact evidence to the calling agent, which retains analysis and judgment.
100
110
 
@@ -105,7 +115,7 @@ The main model receives Raven's final answer instead of its raw tool output. Eac
105
115
  On V2, `raven_seek` and `raven_mcp` **run in the background by default**. The initial response contains a child-session handle, not the findings. The calling agent can continue independent work; Raven delivers compact findings or a failure notice to that same calling session when retrieval finishes, including when the caller is itself a child session.
106
116
 
107
117
  ```text
108
- raven_seek(query="Find the current API documentation")
118
+ raven_mcp(query="Find the current API documentation")
109
119
  raven_mcp(query="Retrieve library examples", background=true)
110
120
  raven_seek(query="Find the definition needed for my next step", background=false)
111
121
  ```
@@ -124,17 +134,17 @@ Under the hood, Raven registers two public delegation tools and one internal bri
124
134
 
125
135
  | Tool | Purpose |
126
136
  |------|---------|
127
- | `raven_seek` | Creates or resumes a Raven Search session for narrowly scoped evidence retrieval. |
128
- | `raven_mcp` | Creates or resumes a Raven MCP session for configured on-demand MCP capabilities. |
137
+ | `raven_seek` | Creates or resumes a lightweight Raven Search session for local file search, discovery, and command-output inspection. |
138
+ | `raven_mcp` | Creates or resumes a Raven MCP session for online research using built-in web tools, global or on-demand MCPs, and local retrieval tools when needed for context. No MCP is required. |
129
139
  | `raven_mcp_bridge` | Internal bridge used only by the Raven MCP agent. |
130
140
 
131
- On OpenCode V2, Raven auto-approves permission checks for the public `raven_seek` and `raven_mcp` delegation tools instead of prompting on every call. Explicit deny rules still apply. This does not change permission checks for other tools or access restrictions on the internal MCP bridge.
141
+ On OpenCode V2, Raven auto-approves permission checks for the public `raven_seek` and `raven_mcp` delegation tools instead of prompting on every call. Inside either Raven agent, it also auto-approves `webfetch`, `websearch`, `fetch`, and tools belonging to enabled globally configured MCP servers. Explicit deny rules still apply. These execution-time approvals do not add a blanket agent permission or change the main agent's tool permissions, model request, or access restrictions on the internal MCP bridge.
132
142
 
133
143
  For a related follow-up, the main agent can reuse the ID returned by the earlier call:
134
144
 
135
145
  ```text
136
- raven_seek(query="Research the available options")
137
- raven_seek(query="Compare the first two in more detail", sessionId="ses_...")
146
+ raven_mcp(query="Research the available options")
147
+ raven_mcp(query="Compare the first two in more detail", sessionId="ses_...")
138
148
  ```
139
149
 
140
150
  Raven accepts a resumed session only when it belongs to the same root session tree and matching Raven agent. Do not pass session IDs between `raven_seek` and `raven_mcp`. Delegated sessions attach directly to the root so they remain visible in the main session's child switcher even when delegation starts inside another child.
@@ -234,6 +244,8 @@ Generated MCP metadata and main-model guidance live beside `raven-config.json`.
234
244
 
235
245
  Default routed tools are `grep`, `glob`, `webfetch`, `fetch`, `websearch`, and search-like `bash` commands. On OpenCode 2, Raven also recognizes the native `shell` tool; `bash` and `shell` are routing aliases, so existing routing settings continue to work. Exact `excludeTools` entries use the host's actual tool name.
236
246
 
247
+ Local search tools route to `raven_seek`; `webfetch`, `fetch`, `websearch`, and recognized global MCP tools route to `raven_mcp`. Each route uses its target agent's configured model and recovery instructions. Raven MCP can use built-in web tools even with no on-demand MCP servers configured.
248
+
237
249
  Global MCPs are automatically routed when their OpenCode tool names use the normal `<server>_<tool>` prefix. Use a keyword for suffix-style names:
238
250
 
239
251
  ```txt
@@ -275,13 +287,13 @@ When `bash` is routed, Raven intercepts primary discovery commands such as `rg`,
275
287
  Raven is optimized for autonomous retrieval:
276
288
 
277
289
  - Raven Search has read, search, unrestricted shell, external-directory, and globally configured MCP access without normal permission prompts.
278
- - Raven MCP has only the internal on-demand MCP bridge and cannot use shell, local search, or edit tools.
279
- - Its `edit` tool is denied, but shell access is not a read-only sandbox and can modify the system.
290
+ - Raven MCP has the same retrieval access as Raven Search, plus the internal on-demand MCP bridge. It can use built-in web tools without an MCP and inspect local files for research context.
291
+ - Both agents deny edit tools and nested delegation, but shell access is not a read-only sandbox and can modify the system.
280
292
  - Queries are sent to Raven's configured model provider.
281
293
  - Remote MCP requests are sent to their services; local MCP entries launch local commands and inherit environment values.
282
294
  - Startup performs an npm update check and probes enabled on-demand MCPs.
283
295
 
284
- Review `Raven.md` and your MCP commands before using Raven in sensitive environments.
296
+ Review `Raven.md`, `RavenMcp.md`, and your MCP commands before using Raven in sensitive environments.
285
297
 
286
298
  ## Context Estimates
287
299
 
package/Raven.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Context firewall for OpenCode that routes noisy search, docs, web, GitHub, and MCP calls through a focused agent before they hit your main model.
2
+ description: Lightweight local evidence retrieval through file search, filesystem discovery, and command-output inspection.
3
3
  mode: subagent
4
4
  hidden: false
5
5
  reasoning_effort: low
@@ -23,6 +23,8 @@ You locate and retrieve evidence with search, fetch, read, command-inspection, a
23
23
  You return compact evidence only.
24
24
  Never call `raven_seek` or `raven_mcp`; you are Raven Search. Use your direct tools and globally available routed MCPs.
25
25
 
26
+ Your primary role is local evidence retrieval. Calling agents should use `raven_mcp` for online research, web search, URL fetching, documentation, public GitHub search, and MCP requests.
27
+
26
28
  Do not perform code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution. During those tasks, retrieve only narrowly scoped evidence; the calling agent owns analysis and judgment. If asked to review or audit, return concrete requested locations and facts without a verdict.
27
29
 
28
30
  When a query implies multiple independent searches, run tools in parallel (single turn) for speed.
package/RavenMcp.md CHANGED
@@ -1,38 +1,43 @@
1
1
  ---
2
- description: Focused on-demand MCP agent that retrieves compact information through Raven's internal MCP bridge.
2
+ description: Online research agent with web search, page fetching, local retrieval tools, and on-demand MCP access.
3
3
  mode: subagent
4
4
  hidden: true
5
5
  reasoning_effort: low
6
6
  permission:
7
- "*": deny
8
- read: deny
9
- glob: deny
10
- grep: deny
11
- list: deny
7
+ read: allow
8
+ glob: allow
9
+ grep: allow
10
+ list: allow
12
11
  edit: deny
13
- bash: deny
12
+ bash: allow
14
13
  task: deny
15
14
  raven_seek: deny
16
15
  raven_mcp: deny
17
16
  raven_mcp_bridge: allow
18
- external_directory: deny
17
+ external_directory: allow
19
18
  ---
20
19
 
21
20
  You are Raven MCP.
22
21
 
23
- You retrieve information from configured on-demand MCP servers only. Use `raven_mcp_bridge` to list and call their tools, resources, and prompts.
22
+ You retrieve online evidence using web search, page fetching, globally available MCPs, and configured on-demand MCP servers. You can also read and search local files or inspect bounded command output when needed for the request.
24
23
 
25
- Do not perform code review, auditing, implementation, planning, or general task execution. Extract only the information requested by the caller and return compact evidence. The calling agent owns analysis, judgment, and final recommendations.
24
+ Use a matching MCP capability when available, especially when the caller names a server. Use `raven_mcp_bridge` for on-demand MCPs; use globally available MCP tools directly. Built-in websearch/webfetch tools are also available, including when no suitable MCP is available.
26
25
 
27
- If you do not know the exact tool name, call `raven_mcp_bridge` with operation `list_tools`, then call the selected tool with operation `call_tool`. For `call_tool` and `get_prompt`, pass arguments as a JSON object string in `argumentsJson`.
26
+ Never call `raven_seek` or `raven_mcp`; use your direct tools and the bridge instead. Do not edit files or delegate to other agents.
27
+
28
+ Do not perform code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution. Extract only the information requested by the caller and return compact evidence. The calling agent owns analysis, judgment, and final recommendations.
29
+
30
+ When using an on-demand MCP, if you do not know the exact tool name, call `raven_mcp_bridge` with operation `list_tools`, then call the selected tool with operation `call_tool`. For `call_tool` and `get_prompt`, pass arguments as a JSON object string in `argumentsJson`.
31
+
32
+ When the caller provides an exact URL, fetch that page and extract the requested evidence rather than replacing it with broad search. Run independent retrievals in parallel and return compact evidence, not raw tool output.
28
33
 
29
34
  Output format:
30
35
 
31
36
  Result:
32
- * Short direct answer based on MCP output.
37
+ * Short direct answer based on retrieved evidence.
33
38
 
34
39
  Sources / records:
35
- * MCP server, tool, resource, prompt, URLs, or records checked.
40
+ * URLs, file paths, MCP servers, tools, resources, prompts, or records checked.
36
41
 
37
42
  Relevant evidence:
38
43
  * Small factual notes only. No long dumps.
package/mcp-guidance.md CHANGED
@@ -2,18 +2,22 @@
2
2
 
3
3
  Raven performs search and information retrieval only. The calling agent must retain code review, auditing, correctness judgments, implementation, debugging decisions, planning, and final recommendations.
4
4
 
5
- Non-Raven agents use `raven_seek` for narrowly scoped evidence retrieval when a routed local search, filesystem discovery, URL fetch, web/docs/GitHub search, globally configured MCP, or search-like shell command is blocked. Include the original tool intent and relevant arguments. Do not delegate an entire review or general task.
5
+ Non-Raven agents use `raven_seek` for narrowly scoped local evidence retrieval: file search, filesystem discovery, and command-output inspection. Use it when a local search tool or search-like shell command is blocked. Include the original tool intent and relevant arguments. Do not delegate an entire review or general task.
6
6
 
7
- Non-Raven agents use `raven_mcp` for information available through Raven's configured on-demand MCP servers. Include the target server or capability when obvious. Only the `raven-mcp` agent calls `raven_mcp_bridge`; it must use the bridge directly instead of either public delegation tool.
7
+ Non-Raven agents use `raven_mcp` for online research: web search, URL fetching, library documentation, public GitHub search, and global or on-demand MCP requests. When `websearch`, `webfetch`, `fetch`, or a global MCP tool is blocked, retry through `raven_mcp`, not `raven_seek`. Include the target server or capability when obvious. Raven MCP can use built-in web tools and local retrieval tools as well as MCPs; an MCP is not required. Only the `raven-mcp` agent calls `raven_mcp_bridge`; it must use the bridge directly instead of either public delegation tool.
8
8
 
9
9
  When a request follows up on an earlier Raven result, pass the session ID returned by the matching tool. Omit `sessionId` for unrelated work and never pass a `raven_seek` session to `raven_mcp` or vice versa.
10
10
 
11
11
  Appropriate `raven_seek` requests:
12
12
 
13
13
  - Find definitions, references, files, or concrete code locations.
14
+ - Inspect bounded command output or local system facts.
15
+
16
+ Appropriate `raven_mcp` requests:
17
+
14
18
  - Fetch and extract facts from a specific URL.
15
19
  - Search current web, documentation, or public GitHub sources.
16
- - Inspect bounded command output or local system facts.
20
+ - Retrieve information through global or on-demand MCP capabilities, using local files for context when needed.
17
21
 
18
22
  Inappropriate delegation:
19
23
 
@@ -26,7 +30,7 @@ Examples:
26
30
 
27
31
  `raven_seek(query="Find every caller of validateToken and return file/line locations")`
28
32
 
29
- `raven_seek(query="Fetch/read https://example.com and extract the documented install flags")`
33
+ `raven_mcp(query="Fetch/read https://example.com and extract the documented install flags")`
30
34
 
31
35
  `raven_mcp(query="Use Context7 to retrieve the current API documentation for Effect Schema decoding")`
32
36
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-raven",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "description": "Context-saving search and on-demand MCP routing for OpenCode through focused Raven agents.",
5
5
  "main": "./index.ts",
6
6
  "exports": {
package/raven-core.ts CHANGED
@@ -762,14 +762,24 @@ export default (async (input: Pick<PluginInput, "client" | "directory"> & { proj
762
762
  return config.raven_seek.excludeAgents.some((a) => a.toLowerCase() === lower)
763
763
  }
764
764
 
765
- function isRouteConfigured(toolName: string): boolean {
766
- if (!modelOperational("seek")) return false
765
+ function isGlobalMcpTool(toolName: string): boolean {
766
+ const tool = toolName.toLowerCase()
767
+ return globalMcpServers.some((server) => tool.startsWith(`${server.toLowerCase()}_`)
768
+ || tool.startsWith(`${server.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase()}_`))
769
+ }
770
+
771
+ function routingKind(toolName: string): DelegationKind {
772
+ return ["websearch", "webfetch", "fetch"].includes(toolName.toLowerCase()) || isGlobalMcpTool(toolName) ? "mcp" : "seek"
773
+ }
774
+
775
+ function isRouteConfigured(toolName: string): boolean {
776
+ if (!modelOperational(routingKind(toolName))) return false
767
777
  const tool = toolName.toLowerCase()
768
778
  if (NEVER_ROUTE_TOOLS.has(tool)) return false
769
779
  const aliases = tool === "bash" || tool === "shell" ? ["bash", "shell"] : [tool]
770
780
  if (config.raven_seek.routeTools?.some((name) => aliases.includes(name.toLowerCase()))) return true
771
781
  if (config.raven_seek.routeToolKeywords?.some((keyword) => tool.includes(keyword.toLowerCase()))) return true
772
- return globalMcpServers.some((server) => tool.startsWith(`${server.toLowerCase()}_`))
782
+ return isGlobalMcpTool(tool)
773
783
  }
774
784
 
775
785
  function compactArgs(value: any): any {
@@ -798,13 +808,14 @@ export default (async (input: Pick<PluginInput, "client" | "directory"> & { proj
798
808
  return query.length > 300 ? `${query.slice(0, 297)}...` : query
799
809
  }
800
810
 
801
- function rerouteMessage(tool: string, args: any): string {
802
- if (ravenProviderIssues.seek) {
803
- return `Raven search is currently unavailable: ${ravenProviderIssues.seek}
804
-
805
- ${ravenRecoveryInstructions("seek")}`
806
- }
807
- return `The '${tool}' tool call is blocked by Raven. Your next tool call should be raven_seek(query="${attemptedQuery(tool, args).replace(/"/g, "'")}").`
811
+ function rerouteMessage(tool: string, args: any): string {
812
+ const kind = routingKind(tool)
813
+ if (ravenProviderIssues[kind]) {
814
+ return `Raven ${kind === "mcp" ? "MCP" : "search"} is currently unavailable: ${ravenProviderIssues[kind]}
815
+
816
+ ${ravenRecoveryInstructions(kind)}`
817
+ }
818
+ return `The '${tool}' tool call is blocked by Raven. Your next tool call should be raven_${kind}(query="${attemptedQuery(tool, args).replace(/"/g, "'")}").`
808
819
  }
809
820
 
810
821
  function ravenRecoveryInstructions(kind: DelegationKind): string {
@@ -821,7 +832,7 @@ Then restart opencode for the model change to take effect. If the task can be co
821
832
  }
822
833
 
823
834
  function routeSummary(): string {
824
- if (!modelOperational("seek")) return "Raven routing: inactive until the configured Search model is loaded."
835
+ if (!modelOperational("seek") && !modelOperational("mcp")) return "Raven routing: inactive until a configured Raven model is loaded."
825
836
  const tools = config.raven_seek.routeTools?.length ? config.raven_seek.routeTools.join(", ") : "(none)"
826
837
  const mcps = globalMcpServers.length ? `${globalMcpServers.join(", ")} (auto-detected)` : "none detected"
827
838
  const keywords = config.raven_seek.routeToolKeywords?.length ? config.raven_seek.routeToolKeywords.join(", ") : "(none)"
@@ -2092,9 +2103,9 @@ Then restart opencode for the model change to take effect. If the task can be co
2092
2103
  // Register raven_seek tool — lets agents with task:false still delegate through Raven
2093
2104
  tool: {
2094
2105
  "raven_seek": tool({
2095
- description: "Search and evidence retrieval only. Creates or resumes a Raven Search session for routed local search, filesystem discovery, URL fetching, web/docs/GitHub search, globally configured MCP searches, or command-output inspection. Do not delegate code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution; the calling agent must perform that work.",
2106
+ description: "Local search and evidence retrieval only. Creates or resumes a lightweight Raven Search session for file search, filesystem discovery, or command-output inspection. Use raven_mcp instead for online research, web search, URL fetching, documentation, public GitHub search, or MCP requests. Do not delegate code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution; the calling agent must perform that work.",
2096
2107
  args: {
2097
- query: tool.schema.string().describe("A narrowly scoped search or evidence-retrieval request. Include original blocked tool args, exact URLs, paths, patterns, or bounded command-output checks. Do not ask Raven to review or audit code."),
2108
+ query: tool.schema.string().describe("A narrowly scoped local search or evidence-retrieval request. Include original blocked tool args, paths, patterns, or bounded command-output checks. Do not ask Raven to review or audit code."),
2098
2109
  sessionId: tool.schema.string().optional().describe("Raven session ID returned by an earlier raven_seek call. Provide it only when this request should continue that session's research context."),
2099
2110
  },
2100
2111
  async execute(args, context) {
@@ -2320,7 +2331,7 @@ Then restart opencode for the model change to take effect. If the task can be co
2320
2331
  },
2321
2332
  }),
2322
2333
  "raven_mcp": tool({
2323
- description: "On-demand MCP information retrieval only. Creates or resumes a dedicated Raven MCP session that selects and calls MCPs configured under raven_mcp.onDemandMcpServers. Use for matching MCP capabilities, not local search, code review, auditing, implementation, planning, or general task delegation.",
2334
+ description: "Online research and MCP evidence retrieval only. Creates or resumes a Raven MCP session for web search, URL fetching, documentation, public GitHub search, and global or on-demand MCP requests. Has built-in web tools and local retrieval tools plus the internal MCP bridge; an MCP is not required. Use raven_seek for purely local searches. Do not delegate code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution; the calling agent retains analysis and judgment.",
2324
2335
  args: {
2325
2336
  query: tool.schema.string().describe("The information to retrieve and, when known, the target MCP server or capability. The calling agent retains analysis and judgment."),
2326
2337
  sessionId: tool.schema.string().optional().describe("Raven MCP session ID returned by an earlier raven_mcp call. Provide it only to continue that MCP retrieval context."),
package/v2.ts CHANGED
@@ -57,7 +57,8 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
57
57
  const controller = new AbortController()
58
58
  const background = backgroundDelegations(ctx, controller.signal)
59
59
  const location = { directory: ctx.location.directory }
60
- const agents: Record<string, AgentDefinition> = {}
60
+ const agents: Record<string, AgentDefinition> = {}
61
+ const globalMcpToolPrefixes = new Set<string>()
61
62
  const activeSessions = new Set<string>()
62
63
  let emitNotice: (notice: z.infer<typeof RavenRpc.events.notice.schema>) => Promise<void> = async () => {}
63
64
  let runtime: Runtime | undefined
@@ -194,9 +195,12 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
194
195
  agent: agents,
195
196
  instructions: [] as string[],
196
197
  }
197
- await raven.config(config)
198
- registrations.push(await ctx.mcp.transform((editor) => {
199
- raven.globalMcpRouting(editor.list().filter(([, server]) => !server.disabled).map(([name]) => name))
198
+ await raven.config(config)
199
+ registrations.push(await ctx.mcp.transform((editor) => {
200
+ const names = editor.list().filter(([, server]) => !server.disabled).map(([name]) => name)
201
+ raven.globalMcpRouting(names)
202
+ globalMcpToolPrefixes.clear()
203
+ for (const name of names) globalMcpToolPrefixes.add(`${name.replace(/[^a-zA-Z0-9_-]/g, "_")}_`)
200
204
  }))
201
205
 
202
206
  async function executeCommand(raw: string) {
@@ -211,12 +215,19 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
211
215
  registrations.push(rpc)
212
216
  emitNotice = (notice) => rpc.events.emit("notice", notice)
213
217
 
214
- // Delegation needs no extra confirmation. Preserve deny rules and leave
215
- // child tools and the Raven-only MCP bridge's permissions unchanged.
216
- registrations.push(await ctx.permission.hook("evaluate", (event) => {
217
- if (event.effect === "ask" && (event.action === "raven_seek" || event.action === "raven_mcp")) {
218
- event.effect = "allow"
219
- }
218
+ // Approve specific retrieval actions at execution time, not by adding a
219
+ // blanket agent allow rule that changes Raven's entire tool policy.
220
+ // Explicit configured denials are final and do not invoke this hook.
221
+ registrations.push(await ctx.permission.hook("evaluate", (event) => {
222
+ if (event.effect !== "ask") return
223
+ const delegation = event.action === "raven_seek" || event.action === "raven_mcp"
224
+ const retrieval = (event.agent === "raven" || event.agent === "raven-mcp") && (
225
+ event.action === "webfetch" || event.action === "websearch" || event.action === "fetch"
226
+ || [...globalMcpToolPrefixes].some((prefix) => event.action.startsWith(prefix))
227
+ )
228
+ if (delegation || retrieval) {
229
+ event.effect = "allow"
230
+ }
220
231
  }))
221
232
 
222
233
  registrations.push(await ctx.agent.transform((editor) => {