@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.

Packages

Package details

extension

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

npm version License

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 --mode for 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 omitting skills entirely — 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:name if 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.