@georgedong32/permission-modes
Claude-Code-style permission modes (ask / plan / auto) for the pi coding agent — with per-mode model profiles, outside-cwd write tracking, and per-mode skill filtering.
Package details
Install @georgedong32/permission-modes from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@georgedong32/permission-modes- Package
@georgedong32/permission-modes- Version
1.1.6- Published
- Jul 1, 2026
- Downloads
- 47/mo · 15/wk
- Author
- georgedong32
- License
- MIT
- Types
- extension
- Size
- 169.5 KB
- Dependencies
- 0 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@georgedong32/permission-modes
Claude-Code-style permission modes for the pi coding agent. Three modes, cycled with Shift+Tab, that control how tool calls and file edits get approved. v1.1.1 adds per-mode model profiles. v1.1.3 adds outside-cwd write tracking with /undo-outside-writes. v1.1.4 adds per-mode skill filtering — keep your system prompt lean and focused on the current mode.
Modes
| Mode | edit / write | reads outside cwd | bash | agent control |
|---|---|---|---|---|
ask ● |
prompt on each edit/write (Allow / Allow all → auto / Block) |
prompt | mutating commands prompt; read-only pass | — |
plan ⏸ |
disabled (stripped from the active tool set) | allowed (exploration needed for planning) | read-only allowlist only; mutating commands blocked | produce a numbered Plan:, then Execute / Stay / Refine |
auto ▶ |
auto-approved (outside cwd tracked for undo via /undo-outside-writes) |
auto-approved | auto-approved; prompts if destructive outside project root | auto-continues until done, bounded by /auto-depth |
Cycle (Shift+Tab): ask → plan → auto → ask.
When there is no interactive UI (pi -p, --mode json), anything that would prompt is blocked instead of silently allowed.
Model profiles (v1.1.1)
Define named profiles in ~/.pi/agent/model-profiles.json mapping each mode to a model ID:
{
"active": "default",
"default": {
"ask": "anthropic/claude-opus-4-5",
"plan": "anthropic/claude-opus-4-5",
"auto": "anthropic/claude-haiku-4-5"
},
"fast": {
"ask": "anthropic/claude-haiku-4-5",
"plan": "anthropic/claude-haiku-4-5",
"auto": "anthropic/claude-haiku-4-5"
}
}
A model ID is "provider/model" or "provider/model:thinking" (the :thinking suffix sets the thinking level after the switch — e.g. anthropic/claude-sonnet-4-5:high). When the mode changes, the extension auto-switches the model via pi.setModel(). The footer shows profile:<name> · model/thinking when a profile is active.
If the file doesn't exist on first install, the extension creates it for you (pre-filled with the user's default model from ~/.pi/agent/settings.json when available).
Why a separate model-profiles.json and not pi's built-in models.json? Pi uses ~/.pi/agent/models.json for custom provider definitions; using a different filename avoids format conflict.
Commands, shortcut, flag
| Kind | Name | Behavior |
|---|---|---|
| Command | /ask, /plan, /auto |
switch to that mode (/default also works as alias) |
| Command | /mode [name] |
set the given mode, or pick from a list |
| Command | /auto-depth <n> |
cap auto-mode follow-ups (0 = unlimited; default 20) |
| Command | /model-profile |
show selector of available profiles |
| Command | /model-profile <name> |
activate the named profile (also /model-profile list to print them) |
| Shortcut | Shift+Tab |
cycle modes |
| Shortcut | Alt+T |
cycle thinking level (off → minimal → low → medium → high → xhigh) |
| Shortcut | Alt+I |
cycle model profile (next profile from ~/.pi/agent/model-profiles.json; re-applies the model for the current mode) |
| Command | /outside-writes |
list tracked outside-cwd writes (read-only) |
| Command | /undo-outside-writes |
restore outside-cwd writes (selector, all, or --list) |
| Flag | --permission-mode <name> |
start in a mode (accepts ask, plan, auto, or default as alias; default ask) |
| Flag | --model-profile <name> |
start with a named profile activated |
The start-mode flag is
--permission-mode(not--mode) because pi already has a built-in--modefor output format (text/json/rpc).
Outside-cwd write tracking (v1.1.3)
In auto mode, edit and write calls to paths outside the working directory are auto-approved — but each one is snapshotted to <cwd>/.pi/projects/<project-id>/tmp/outside-writes/. Use /undo-outside-writes to roll back:
/undo-outside-writes— interactive selector (newest first)/undo-outside-writes all— restore all without prompting/undo-outside-writes --list— list only (alias for/outside-writes)/outside-writes— same as--list
Snapshots capture the file's pre-write content (or null if the file didn't exist). They persist across sessions until you undo them. The snapshot cap is 100 entries (oldest are evicted; you get a notification).
Per-mode skill filtering (v1.1.4)
When you're in plan mode, skills like systematic-debugging and executing-plans are irrelevant noise. Skill filtering lets you configure which skills get injected into the system prompt per mode — saving tokens and keeping the agent focused.
{
"active": "default",
"default": {
"ask": "anthropic/claude-sonnet-4-5",
"plan": {
"model": "anthropic/claude-sonnet-4-5",
"skills": ["brainstorming", "writing-plans"]
},
"auto": "openai/gpt-4o"
}
}
"skills": ["brainstorming", "writing-plans"]— only these two skills appear in the system prompt when in plan mode."skills": ["*"]or omittingskillsentirely — allow all skills (default, no filtering).- String shorthand (
"anthropic/claude-sonnet-4-5") still works — backward compatible. - Skills can still be invoked manually via
/skill:nameif needed — filtering only controls which skills are pre-loaded into the agent's context.
Resolution order: Active profile → default profile → hardcoded defaults (["*"]). The read tool is always mandatory in tool filters (stub for v1.1.5).
Plan mode flow
In plan mode the agent explores read-only and emits a numbered list under a Plan: header. On completion you choose:
- Execute the plan — switches to auto, restores edit/write, runs the steps; a
☐/☑widget advances as the agent emits[DONE:n]tags, and you get Plan Complete! ✓ at the end. - Stay in plan mode — keep iterating.
- Refine the plan — opens an editor; your notes are sent back as a follow-up.
UI
- A status pill and a custom footer showing mode · cwd [git-branch] · provider/model (or profile:name · provider/model when a profile is active).
- While the agent is streaming, the working indicator shows live token / tok-s / cost / % context stats; it reverts to the default loader when idle.
Current mode, the auto-follow-up depth, and the active profile name persist across /reload and session resume.
Install / run
# Install as a package (scoped npm name; or from a git remote / local path)
pi install npm:@georgedong32/permission-modes
pi list # verify it loaded
# Or run it directly for a quick try (no install)
pi -e ./extensions/permission-modes/index.ts
# During development, hot-reload after edits
/reload
Auto-discovery also works: drop this folder at ~/.pi/agent/extensions/permission-modes/ (global) or .pi/extensions/permission-modes/ (project) and pi loads index.ts automatically.
Testing
npm test # run all 144+ tests (vitest)
npm run test:watch # watch mode for development
Changelog
See CHANGELOG.md for the full release history.
Layout
permission-modes/ # @georgedong32/permission-modes
├── package.json # pi manifest + npm package metadata
├── index.ts # main extension (default-exported factory)
├── profiles.ts # NEW in v1.1.1: model-profile config helpers
├── profiles.test.ts # NEW in v1.1.1: unit tests for profiles
├── utils.ts # bash allowlist + Plan: + [DONE:n] helpers
├── index.test.ts # integration tests (vitest)
├── utils.test.ts # unit tests (vitest)
├── vitest.config.ts # vitest config
├── CHANGELOG.md # release history
├── LICENSE # MIT
├── .gitignore # excludes node_modules, lockfile, .pi/
└── docs/
├── PRD.md # product requirements
└── prompts/ # mode-specific prompt context
├── ask-mode-prompts.md
├── plan-mode-prompts.md
└── auto-mode-prompts.md
Third-party deps: none. Peer dependencies (bundled by pi): @earendil-works/pi-coding-agent, @earendil-works/pi-ai, @earendil-works/pi-tui, typebox. The model is switched only when the user opts in via ~/.pi/agent/model-profiles.json — without a profile config file, the model never changes and the extension behaves exactly as in v1.1.0.