feat: vendor permission system source

This commit is contained in:
云服务部-叶林立
2026-08-19 14:35:19 +08:00
parent 198584daf8
commit 410c50a3e5
809 changed files with 157793 additions and 139 deletions
@@ -0,0 +1,127 @@
---
issue: 106
issue_title: "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 from `docs/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)
1. Actions: `allow` / `ask` / `deny`.
2. Flat `permission` object with `"*"` universal fallback.
3. Granular object syntax: surface key → string (catch-all) or pattern-map object.
4. Last-match-wins evaluation order — both use `findLast` on ordered rules.
5. Wildcard `*` matches zero or more of any character.
6. Home directory expansion (`~` / `$HOME`) in patterns.
7. `external_directory` surface for out-of-cwd path gating.
8. `bash` surface with command-pattern matching.
9. `skill` surface with name-pattern matching.
10. `task` surface for subagent/delegation gating.
11. Session-scoped "always" approvals from the ask dialog (`once` / `always` / `reject`).
12. Per-agent permission overrides.
13. Tool hiding — both remove denied tools before the agent runs (OpenCode's `disabled()` function, this extension's `filterActiveTools` + 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:
1. Open with a brief statement that this extension's permission model was inspired by OpenCode's, referencing the OpenCode v1.1.x permission rework.
2. Present a "What transfers directly" section covering the shared concepts — users can reuse their mental model and, in many cases, similar config snippets.
3. Present a "Where they diverge" section with the comparison table and explanatory notes for the most impactful differences (default fallback, `.env` protection, `?` wildcard, trailing wildcard optionality, tool surface name mapping).
4. Include a "Porting an OpenCode config" mini-guide showing a before/after example of translating an OpenCode `permission` block to this extension's format.
Cover: surface name renames (`edit``write`+`edit`, `glob``find`), the missing top-level string shorthand, and the default flip from `allow` to `ask`.
5. 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`.
1. `docs:` write `docs/opencode-compatibility.md` with full comparison content.
2. `docs:` update `README.md` documentation table.
3. `docs:` add cross-reference in `docs/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
1. Should the porting guide include a worked example for `mcp` (Pi-only surface)?
Defer until writing — include if it clarifies, omit if it confuses.
2. 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.