feat(opencode): allow agents to read external Rust crate source

@make, @test, @check often need to inspect dependency source (trait
definitions, impl details, test patterns) to inform implementation or
verify findings. Opencode applies a CWD check on tool access, so reads
outside the worktree previously prompted for each access.

- Add permission.read/grep/glob path allowlists for the three locations
  cargo deps live: ~/.cargo/registry/src/, ~/.cargo/git/checkouts/, and
  /nix/store/*-vendor-*/ for crane / buildRustPackage projects.
- Document the discovery pattern in each agent: `cargo metadata
  --format-version 1` returns absolute paths via packages[].manifest_path.
- Cross-reference the registry paths from the permission.bash allowlist
  comment so future readers see the bash inspection commands (rg/ls)
  intentionally accept paths outside CWD.
- @check gets its first permission block (was tools-only before).

Path-pattern syntax for read/grep/glob isn't fully documented; if
opencode rejects it, fall back to `permission: { external_directory:
allow }` at the project config level.
This commit is contained in:
Harald Hoyer 2026-05-08 13:24:30 +02:00
parent af6481a5a7
commit 3e515d54eb
3 changed files with 129 additions and 0 deletions

View file

@ -6,6 +6,24 @@ tools:
write: false
edit: false
bash: false
permission:
# ── External-directory reads (registry / git deps / nix-vendored) ──
# Opencode applies a CWD check on tool access; these patterns whitelist
# the cargo dependency source trees so the Read/Grep/Glob tools don't
# prompt for each access. @check sometimes needs to verify a finding
# against a dependency's actual source (trait bounds, impl details).
read:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
grep:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
glob:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
---
@ -15,6 +33,16 @@ You are a senior engineer who catches expensive mistakes before they ship. Your
**Note:** This agent reviews user-provided artifacts (diffs, specs, configs). It does not independently fetch code from repos.
**External crate source (Rust):** when verifying a finding against a dependency's actual source (trait bounds, impl details, behavior under specific inputs), you can read from these paths via Read/Grep/Glob (no permission prompt — see frontmatter):
| Source | Path pattern |
|---|---|
| Registry crates | `~/.cargo/registry/src/index.crates.io-*/<crate>-<version>/` |
| Git deps | `~/.cargo/git/checkouts/<crate>-<hash>/<branch>/` |
| Nix-vendored deps | `/nix/store/<hash>-vendor-*/<crate>-<version>/` |
The caller (`@check`'s dispatcher in the workflow) typically passes the dependency's name and version inline; you locate the path under the registry root. Use this sparingly — only when the finding's correctness genuinely depends on knowing the dep's source, not for general curiosity.
## Scope
You review:

View file

@ -6,6 +6,23 @@ tools:
edit: true
bash: true
permission:
# ── External-directory reads (registry / git deps / nix-vendored) ──
# Opencode applies a CWD check on tool access; these patterns whitelist
# the cargo dependency source trees so the Read/Grep/Glob tools (and
# bash inspection commands like `rg`/`ls`) don't prompt for each access.
# See "Reading External Crate Source" below for the discovery pattern.
read:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
grep:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
glob:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
bash:
# Default deny
"*": deny
@ -25,6 +42,12 @@ permission:
"cargo": allow
# ── Read-only inspection ──
# The wildcarded patterns below accept any path argument, including
# paths *outside* the worktree. This is intentional — see "Reading
# External Crate Source" below. Specifically reachable:
# ~/.cargo/registry/src/index.crates.io-*/<crate>-<version>/ (registry)
# ~/.cargo/git/checkouts/<crate>-<hash>/<branch>/ (git deps)
# /nix/store/*-vendor-*/<crate>-<version>/ (nix-vendored)
"ls *": allow
"ls": allow
"wc *": allow
@ -146,6 +169,42 @@ The devshell guarantees the right toolchain versions are available. Detect once
A task may legitimately span multiple languages (e.g. a Rust binary plus its Python test harness). Run the appropriate verification per file area; document each in the verification block.
## Reading External Crate Source
For Rust tasks, you may need to inspect dependency source (trait definitions, impl bodies, usage examples) to inform your implementation. External source is reachable via the Read/Grep/Glob tools and via `rg`/`ls` in bash. **Do not edit external source — it's read-only reference material.**
**Where dependency source lives:**
| Source | Path pattern |
|---|---|
| Registry crates (most deps) | `~/.cargo/registry/src/index.crates.io-*/<crate>-<version>/` |
| Git deps | `~/.cargo/git/checkouts/<crate>-<hash>/<branch>/` |
| Nix-vendored deps (crane, buildRustPackage) | `/nix/store/<hash>-vendor-*/<crate>-<version>/` |
| Workspace-local deps | inside the worktree itself, no special handling |
**Discovering the exact path** for a specific dependency:
```
nix develop -c cargo metadata --format-version 1
```
The JSON output's `packages[].manifest_path` field has the absolute path to each `Cargo.toml`; the source files are siblings under that crate's directory. The registry must be populated first — `cargo check` (or any prior build) downloads everything in `Cargo.lock`. If `cargo metadata` fails because deps haven't been fetched, run `nix develop -c cargo check` once.
**Reading patterns:**
- Search across a crate: `rg "trait Serialize" ~/.cargo/registry/src/index.crates.io-*/serde-1.*/src/`
- List a crate's modules: `ls ~/.cargo/registry/src/index.crates.io-*/tokio-1.*/src/`
- Read a specific file: use the Read tool with the absolute path (no permission prompt; the path is reachable).
**When to consult external source:**
- The task asks you to implement a trait from an external crate, and you need the trait definition.
- An external API is being misused and you want to verify the correct usage.
- A test failure points at a behavior of an external dep that's not obvious from its public docs.
**When *not* to consult external source:**
- For routine usage that's covered by `cargo doc` / docs.rs (you don't have web access, but the task spec or existing code in the worktree is usually enough).
- To "study" a dependency you're not actively using in this task.
## Dependency Constraint
**No new dependencies or lockfile changes** unless explicitly included in acceptance criteria.

View file

@ -6,6 +6,23 @@ tools:
edit: true
bash: true
permission:
# ── External-directory reads (registry / git deps / nix-vendored) ──
# Opencode applies a CWD check on tool access; these patterns whitelist
# the cargo dependency source trees so the Read/Grep/Glob tools (and
# bash inspection commands like `rg`/`ls`) don't prompt for each access.
# See "Reading External Crate Source" below for the discovery pattern.
read:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
grep:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
glob:
"~/.cargo/registry/src/**": allow
"~/.cargo/git/checkouts/**": allow
"/nix/store/*-vendor-*/**": allow
bash:
# Default deny
"*": deny
@ -28,6 +45,12 @@ permission:
"cargo fmt*": allow
# ── Read-only inspection ──
# The wildcarded patterns below accept any path argument, including
# paths *outside* the worktree. This is intentional — see "Reading
# External Crate Source" below. Specifically reachable:
# ~/.cargo/registry/src/index.crates.io-*/<crate>-<version>/ (registry)
# ~/.cargo/git/checkouts/<crate>-<hash>/<branch>/ (git deps)
# /nix/store/*-vendor-*/<crate>-<version>/ (nix-vendored)
"ls *": allow
"ls": allow
"wc *": allow
@ -126,6 +149,25 @@ Rust:
**Anti-patterns — refuse the path even if it would technically be writable:**
- `src/tests/foo.rs` and similar regular submodule paths under `src/`. These are not `#[cfg(test)]` modules — they are normal modules that would require a `mod tests;` declaration in production code (`lib.rs` / `main.rs`), which you cannot add. Report as `BLOCKED` and suggest either `tests/<feature>.rs` (integration) or a `#[cfg(test)] mod tests` block inside the relevant `src/<module>.rs`.
## Reading External Crate Source
When you need to inspect a dependency's source — to understand a trait you're testing against, find a known-good test pattern from a well-tested crate, or check a dep's behavior under specific conditions — external source is reachable via the Read/Grep/Glob tools and via `rg`/`ls` in bash. **Do not edit external source.**
**Where dependency source lives:**
| Source | Path pattern |
|---|---|
| Registry crates | `~/.cargo/registry/src/index.crates.io-*/<crate>-<version>/` |
| Git deps | `~/.cargo/git/checkouts/<crate>-<hash>/<branch>/` |
| Nix-vendored deps (crane, buildRustPackage) | `/nix/store/<hash>-vendor-*/<crate>-<version>/` |
Discover paths via `nix develop -c cargo metadata --format-version 1`; the JSON has `packages[].manifest_path` per dep. The registry must be populated — run `nix develop -c cargo check` once if the metadata call shows missing source.
Read patterns:
- `rg "trait Serialize" ~/.cargo/registry/src/index.crates.io-*/serde-1.*/src/`
- `ls ~/.cargo/registry/src/index.crates.io-*/tokio-1.*/tests/` — useful for borrowing test patterns
- Read tool with absolute path for a specific file.
## Test Philosophy
**Contract tests + regression.** Write tests that verify: