12 KiB
issue, issue_title
| issue | issue_title |
|---|---|
| 106 | document opencode compatibility |
Document OpenCode Compatibility
Problem Statement
The upstream fork documented compatibility with OpenCode, but this repo does not mention it beyond a brief acknowledgment in README.md line 109.
This extension's flat permission format was directly inspired by OpenCode's permission model, and in several areas has moved closer to parity.
Users coming from OpenCode — or evaluating this extension alongside it — have no way to understand what transfers directly and where the two diverge.
Goals
- Add a new doc page (
docs/opencode-compatibility.md) comparing this extension's permission model with OpenCode's. - Link to it from
README.md's Documentation table and fromdocs/configuration.md. - Cover shared concepts and call out concrete divergences based on source-level analysis of both systems.
Non-Goals
- Changing any runtime behavior to match OpenCode — divergences are documented, not resolved.
- Tracking OpenCode's rapidly evolving feature set on a rolling basis — this is a point-in-time comparison.
- Documenting OpenCode's internal architecture — only user-facing permission semantics.
Background
OpenCode's permission system (documented at https://opencode.ai/docs/permissions/, source at packages/opencode/src/permission/) uses the same three-action model (allow / ask / deny), the same flat permission object with * fallback, last-match-wins evaluation, wildcard patterns, home-directory expansion, external_directory gating, per-agent overrides, and session-scoped "always" approvals.
This extension was designed with OpenCode's model as a reference (noted in docs/architecture/target-architecture.md and docs/architecture/README.md).
Shared Concepts (verified from source)
- Actions:
allow/ask/deny. - Flat
permissionobject with"*"universal fallback. - Granular object syntax: surface key → string (catch-all) or pattern-map object.
- Last-match-wins evaluation order — both use
findLaston ordered rules. - Wildcard
*matches zero or more of any character. - Home directory expansion (
~/$HOME) in patterns. external_directorysurface for out-of-cwd path gating.bashsurface with command-pattern matching.skillsurface with name-pattern matching.tasksurface for subagent/delegation gating.- Session-scoped "always" approvals from the ask dialog (
once/always/reject). - Per-agent permission overrides.
- Tool hiding — both remove denied tools before the agent runs (OpenCode's
disabled()function, this extension'sfilterActiveTools+ system-prompt sanitization).
Divergences (verified from source)
| Area | OpenCode | This extension | Notes |
|---|---|---|---|
| Default fallback | "*": "allow" (most surfaces) |
"*": "ask" (least privilege) |
OpenCode is permissive by default; this extension requires explicit opt-in |
.env file protection |
Built-in read: { "*.env": "ask", "*.env.*": "ask", "*.env.example": "allow" } |
No built-in .env rules |
User must configure manually |
? wildcard |
Supported (matches exactly one character) | Not supported (? is escaped as literal) |
Only * works in this extension |
| Trailing wildcard optionality | "ls *" matches bare "ls" (trailing * becomes optional) |
"ls *" does NOT match bare "ls" |
OpenCode's Wildcard.match special-cases patterns ending in * |
doom_loop surface |
Active, defaults to ask |
Deprecated and removed | Not a permission concern in Pi's architecture |
| File mutation surfaces | edit covers edit, write, apply_patch |
Separate write and edit surfaces |
Pi has distinct tools per operation |
| Search/discovery surfaces | glob, grep, list are gatable surfaces |
find, grep, ls are the Pi tool names |
Different tool names, same concept |
| OpenCode-only surfaces | lsp, question, webfetch, websearch, todowrite, plan_enter, plan_exit |
Not applicable | Pi does not expose these tools |
mcp surface |
Not a documented permission surface | First-class surface with server/tool-level granularity | Pi-specific feature |
| Top-level string shorthand | "permission": "allow" sets all surfaces at once |
Not supported; permission must be an object |
Use "permission": { "*": "allow" } instead |
| External directory globs | Uses ** for recursive matching in docs |
Uses * (single wildcard matches across path separators) |
Both * implementations match / in paths (dot-all regex flag) |
| Bash arity table | Built-in arity.ts (~100 entries) extracts "human-understandable command" from tokens |
No arity table; matches against full command string | Session approval patterns serve a similar role |
| Per-agent config | agent key inside opencode.json or YAML frontmatter in .md files |
YAML frontmatter in Pi agent definition .md files only |
OpenCode supports both; this extension only uses frontmatter |
| Config file paths | ~/.config/opencode/opencode.json or .opencode/config.json |
~/.pi/agent/extensions/pi-permission-system/config.json or <cwd>/.pi/extensions/pi-permission-system/config.json |
Completely different directory conventions |
| Subagent prompt forwarding | Not documented as explicit feature | ask policies work in non-UI subagent contexts via prompt forwarding |
Pi-specific feature |
| Pi infrastructure auto-allow | N/A | Read-only tools to Pi infra dirs bypass the external_directory gate | Pi-specific feature |
| Permission review log | No equivalent documented | Writes decisions to logs/pi-permission-system-permission-review.jsonl |
Auditability feature |
Design Overview
This is a documentation-only change. No code, schema, or config changes are needed.
The new doc page should:
- Open with a brief statement that this extension's permission model was inspired by OpenCode's, referencing the OpenCode v1.1.x permission rework.
- Present a "What transfers directly" section covering the shared concepts — users can reuse their mental model and, in many cases, similar config snippets.
- Present a "Where they diverge" section with the comparison table and explanatory notes for the most impactful differences (default fallback,
.envprotection,?wildcard, trailing wildcard optionality, tool surface name mapping). - Include a "Porting an OpenCode config" mini-guide showing a before/after example of translating an OpenCode
permissionblock to this extension's format. Cover: surface name renames (edit→write+edit,glob→find), the missing top-level string shorthand, and the default flip fromallowtoask. - Note that this is a point-in-time comparison and link to the upstream docs for the latest.
Module-Level Changes
docs/opencode-compatibility.md — new
Full comparison page as described in Design Overview.
README.md — changed
Add row to the Documentation table linking to the new page (e.g., "OpenCode compatibility — shared concepts and divergences").
docs/configuration.md — changed
Add a brief "See also" note linking to the compatibility doc, likely near the top or at the end.
Test Impact Analysis
No code changes — no test impact.
TDD Order
This is a docs-only change; no TDD cycles apply.
Use /build-plan, not /tdd-plan.
docs:writedocs/opencode-compatibility.mdwith full comparison content.docs:updateREADME.mddocumentation table.docs:add cross-reference indocs/configuration.md.
Suggested single commit: docs: document OpenCode compatibility (#106).
Risks and Mitigations
| Risk | Mitigation |
|---|---|
| Comparison becomes stale as OpenCode evolves | Note the reference point (OpenCode v1.1.x permission rework, source as of 2026-05) and link to upstream docs |
| Could imply feature parity where it doesn't exist | Explicit divergence table with concrete differences |
| Could this silently weaken a permission? | No — docs-only change, no runtime behavior affected |
| Inaccurate claims about OpenCode behavior | All divergences verified from OpenCode source (packages/opencode/src/permission/, src/util/wildcard.ts, src/config/permission.ts) |
Open Questions
- Should the porting guide include a worked example for
mcp(Pi-only surface)? Defer until writing — include if it clarifies, omit if it confuses. - Should the doc mention the
?wildcard gap as a potential future enhancement or just document it as a difference? Document as a difference only — feature changes belong in a separate issue.