@ladbabynpm/picc-permission-modes
Claude Code style permission modes (default, acceptEdits, plan, bypassPermissions, auto) and user-defined permission rules for the pi coding agent. A more faithful port of Claude Code's harness than pi-permission-modes.
Package details
Install @ladbabynpm/picc-permission-modes from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@ladbabynpm/picc-permission-modes- Package
@ladbabynpm/picc-permission-modes- Version
0.1.2- Published
- Sep 18, 2026
- Downloads
- 407/mo · 176/wk
- Author
- ladbabynpm
- License
- MIT
- Types
- extension
- Size
- 648.7 KB
- Dependencies
- 2 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
picc-permission-modes
A Claude Code style permission-mode system for the pi coding agent.
Part of picc, a pi agent setup mirroring Claude Code's harness.
Mirrors upstream PermissionMode semantics across messages shown to the LLM, dialogs shown in the TUI, prompt strings, plan-mode flow, dangerous-path safety, and persistence.
Fork of pi-permission-modes, where we replicate Claude Code's harness more faithfully.
Modes
| Mode | Symbol | Behavior |
|---|---|---|
default |
— | Ask on edits/writes. Auto-allow reads inside cwd. Ask on bash outside the read-only allowlist. |
acceptEdits |
⏵⏵ | Auto-allow edits inside cwd. Ask otherwise. Auto-allow bash commands on the upstream allowlist (mkdir, touch, rm, rmdir, mv, cp, sed). |
plan |
⏸ | Read-only intent, but not hard-blocked: only the plan file is auto-allowed; every other edit/write flows through the normal permission prompt (matches Claude Code). Bash and reads defer to pi-permission-system. Plan file at <agentDir>/plans/<slug>.md (global dir + random 3-word adjective-verb-noun slug, e.g. ~/.pi/agent/plans/gleaming-brewing-phoenix.md). |
bypassPermissions |
⏵⏵ | Auto-allow everything except dangerous-path safety checks (.gitconfig, .bashrc, .git/, .claude/, etc.). |
auto |
⏵⏵ | Reads/search/plan/task tools are safe-allowlisted (no classifier call). Edits/writes inside cwd are fast-pathed like acceptEdits (dangerous paths excluded). Everything else goes through a separate LLM classifier that allows safe actions and blocks destructive/exfiltrating ones. If the classifier is unavailable (no provider, HTTP error, timeout), the call falls back to a normal user prompt instead of hard-blocking. The TUI surfaces each classifier decision inline (see below). |
Install
Install via pi install npm:@ladbabynpm/picc-permission-modes.
Configuration
All configuration lives in a single JSON file (the extension's config.json), with a few environment variables to override its location or supply the classifier's auth.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
PICC_PERMISSION_MODES_CONFIG_PATH |
<extension dir>/config.json |
Absolute path to the extension's config.json. Override to point at a config in a different location. |
PICC_PERMISSION_MODE |
(unset) | Initial permission mode for headless / SDK hosts (e.g. the picc-claude-shim driven by T3 Code). Set to one of default, acceptEdits, plan, bypassPermissions, auto (camelCase or kebab-case). Headless pi sessions never fire session_start, so the --permission-mode flag is never seen — this var is how a host tells the gate which mode to start in. Without it, a headless session stays on default and auto-rejects every non-allow tool call. |
CLAUDE_CONFIG_DIR |
~/.claude |
Directory the loader reads settings.json from when falling back to Claude Code's permissions block. |
ANTHROPIC_AUTH_TOKEN |
(unset) | API key for the auto mode LLM classifier. Used when autoMode.provider.apiKey is unset, and interpolated into "${ANTHROPIC_AUTH_TOKEN}" placeholders in config.json. |
Example config.json
{
"autoMode": {
"provider": {
"apiKey": "${ANTHROPIC_AUTH_TOKEN}",
"maxContextChars": 80000
},
"allow": [
"Standard read-only file inspection inside the working directory.",
"Standard search/grep/glob operations in the working directory.",
"Running tests, linters, and formatters.",
"Editing files inside the current working directory.",
"git add/commit/diff/log/status/fetch within the repository."
],
"softDeny": [
"Force pushes (git push -f, git push --force, git push --force-with-lease).",
"rm -rf outside the working directory.",
"Editing files outside the working directory without explicit authorization.",
"Network egress to non-trusted external endpoints.",
"git push to a branch that is not the session's working branch."
],
"hardDeny": [
"rm -rf /, rm -rf $HOME, or equivalent filesystem-wide destructive deletes.",
"Force push to main / master / the repository default branch.",
"DROP DATABASE / DROP SCHEMA without explicit user confirmation.",
"Disabling safety tooling, audit logs, or git hooks.",
"Systematic scanning of credential stores (.env, ~/.aws/, keychains, etc.).",
"Disabling or removing .claude/ settings, hooks, or rules."
],
"environment": [
"An autonomous coding agent running inside the user's pi session."
],
"classifyAllShell": false,
"denialLimits": {
"maxConsecutive": 3,
"maxTotal": 20
},
"transcriptMaxChars": 80000
},
"permissions": {
"allow": ["Read", "Bash(go)", "Bash(git commit *)"],
"deny": ["Bash(rm *)", "Bash(git push *)", "Bash(sudo *)"],
"ask": []
}
}
User permissions are explained in the next section.
User permissions
Add a permissions block to ~/.pi/agent/extensions/picc-permission-modes/config.json to seed session-allow, session-deny, and session-ask rules. The format is identical to Claude Code's permissions block in ~/.claude/settings.json (see code.claude.com/docs/en/permissions). Example:
{
"permissions": {
"allow": [
"WebFetch",
"Read(//**)",
"Bash(go)",
"Bash(git commit *)",
"Bash(git * main)"
],
"deny": [
"Bash(rm *)",
"Bash(rmdir *)",
"Bash(git push *)",
"Bash(sudo *)",
"Bash(shred *)",
"Bash(Restart-Computer *)",
"Bash(Format-Volume *)",
"Bash(Clear-Disk *)",
"Bash(Remove-Item *)"
],
"ask": []
}
}
Each rule is a string like Read, Bash(go), Bash(git commit *), or Read(//absolute/path/**). Bare tool names (no parens) auto-allow every call to that tool. Paren rules can carry an exact command, a wildcard, or a path glob.
Precedence: if the local permissions block in config.json has any entries in allow/deny/ask, those are used as-is. If the local block is empty (or the file is missing), the loader falls back to parsing ~/.claude/settings.json's permissions block so the same allow/deny rules you have in Claude Code apply to pi too.
Auto-persistence: when the loader falls back to ~/.claude/settings.json, it also writes the parsed rules back to config.json so the rules show up on disk where you can inspect or edit them. The write is idempotent — re-running when the local rules already match the claude settings is a no-op. Other top-level keys in config.json (e.g. autoMode) are preserved.
CLI
pi --permission-mode default # explicit default
pi --permission-mode acceptEdits # auto-approve edits
pi --permission-mode plan # start in plan mode
pi --permission-mode bypassPermissions
pi --permission-mode auto # auto-mode classifier routes every tool call
pi --permission-mode ask # alias for default
Slash commands
/default,/acceptEdits,/plan,/bypassPermissions,/auto/mode <name>— set mode by alias/mode— open an interactive selector