pi-cwd-guard0.6.0
Small Pi safety extension for cwd access, protected paths, application configuration guidance, and common destructive bash commands.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-cwd-guard
A small Pi safety extension package for cwd access, protected paths, application configuration guidance, and common destructive bash commands.
Upgrading to 0.6.0
This release changes path permissions:
- Existing
allowedDestructiveBashPathsentries now also permit protectedwriteandeditcalls, including secret files and vendor or generated paths. Review and narrow these entries before upgrading. Outside-cwd permission remains separate. - Plain directories named
secretsorcredentialsno longer block edits by name alone. Use.secrets/or.credentials/for directory-level protection. Explicit protected secret filenames and extensions still block edits by default.
What it guards
The extension intercepts these built-in tools:
readwriteeditbash
Pi's optional Windows powershell tool is not intercepted. Destructive-command checks apply only to bash.
Current working directory guard
Before read, write, or edit runs, the extension normalizes the tool's path like Pi's built-in file tools, then resolves it against the current working directory. This includes Unicode spaces, a leading @, tilde expansion, and file URL decoding. On Windows, shell drive paths are converted only with Pi 0.84.0 or newer, matching the installed Pi version. The cwd and protected-path checks use this normalized path.
- If the resolved path is inside the current working directory, the tool continues to the next checks.
- If the resolved path is outside the current working directory and is not covered by
allowedOutsideCwdPaths, Pi asks for confirmation. - If no UI is available, outside-cwd access is blocked by default unless the path is covered by
allowedOutsideCwdPaths.
Configuring path exceptions
You can allow specific outside-cwd paths with JSON config files:
- Project-local:
.pi/pi-cwd-guard.json - Global:
~/.pi/agent/extensions/pi-cwd-guard.json
Example:
{
"allowedOutsideCwdPaths": [
"/tmp",
"/var/tmp",
"~/shared-workspace",
"../sibling-project"
],
"allowedDestructiveBashPaths": [
"/tmp/pi-web-video2"
]
}
Notes:
- Multiple paths are supported.
- Matching is recursive: allowing
/tmpallows/tmp/foo/bar.txt. ~expands to your home directory.- Absolute paths are used as-is.
- Relative paths in project config resolve against the current working directory.
- Relative paths in global config resolve against
~/.pi/agent/extensions. - Project and global path lists are merged independently.
allowedOutsideCwdPathsonly skips outside-cwd confirmation. It does not bypass hard-protected path blocks or destructive bash confirmation.allowedDestructiveBashPathsdefines trusted mutation locations. It skips hard-protectedwrite/editblocks for recursively covered targets, including existing and missing files or directories. Tool paths receive normal normalization, and relative tool paths resolve against the cwd.- The mutation exception requires both lexical and canonical containment. The guard resolves the full target and existing ancestors through symlinks. A target symlink, ancestor symlink, or dangling symlink that escapes the trusted directory does not receive the exception. Unresolved filesystem errors fail closed. An explicitly allowed root that is itself a symlink defines its canonical trusted root.
- Outside-cwd permission remains separate.
allowedDestructiveBashPathsdoes not grant outside-cwd read access or skip outside-cwd confirmation forwrite/edit. Add the path toallowedOutsideCwdPathstoo if outside-cwd access should proceed without confirmation. allowedDestructiveBashPathsalso skips destructive bash confirmation for recognizedrmcommands when every static absolute or~/...target is recursively covered.- Only for
rm, relative, dynamic, or ambiguous targets, mixed allowed/disallowed targets, redirections, pipes, background execution, and unrecognized prior commands still require confirmation. Unrelated destructive operations are not exempt. These rm-specific restrictions do not apply to normalized file-tool paths. - These exceptions do not change application-configuration guidance. Path checks remain a heuristic preflight check, not a sandbox or protection against filesystem races.
You can also inspect or update the config from Pi with the /cwd-guard command:
/cwd-guard
/cwd-guard show
/cwd-guard allow /tmp --project
/cwd-guard allow /tmp --global
/cwd-guard allow /tmp /var/tmp ~/shared-workspace --project
/cwd-guard allow "/tmp/my folder" --project
/cwd-guard allow-destructive /tmp/pi-web-video2 --project
Command notes:
/cwd-guardopens an interactive menu for showing config or adding exceptions. Without UI, it displays the merged active configuration./cwd-guard showdisplays the merged active configuration.- Typing
/cwd-guardin interactive mode autocompletes subcommands; both allow commands autocomplete--project/--global. allow <path...> --project|--globalupdatesallowedOutsideCwdPaths.allow-destructive <path...> --project|--globalupdatesallowedDestructiveBashPaths, trusting paths for protectedwrite/editand recognizedrmexceptions. It does not grant outside-cwd access.- Global updates write
~/.pi/agent/extensions/pi-cwd-guard.jsonand ask for confirmation first. - Paths added by the command are written as absolute resolved paths.
- Command arguments support shell-style single quotes, double quotes, and backslash escapes for paths with spaces.
Hard-protected paths
write and edit are blocked for sensitive, vendor, or generated paths such as:
.env,.env.*.secrets/,.credentials/.npmrc,.pypirc,id_rsa,id_ed25519, kubeconfig files- common credential JSON files such as
secrets.json,credentials.json,client_secret.json, service-account JSON files *.pem,*.key,*.p12,*.pfxnode_modules/- generated/build output dirs like
dist/,build/,coverage/,.next/,.nuxt/,generated/
These are hard-blocked rather than confirmed unless the target is covered by the trusted mutation exception in allowedDestructiveBashPaths. Ordinary source directories named secrets or credentials, such as src/components/secrets/, are not protected by their directory names alone. Explicit credential filenames inside them remain protected by default.
Application configuration guidance
The extension adds semantic guidance asking the agent to get permission before changing actual application configuration, runtime configuration, or deployment configuration—including configured values, defaults, endpoints, feature flags, ports, or provider settings—unless the user's current request already explicitly authorizes that exact change.
Configuration is not classified from path or content patterns. A file, directory, or symbol containing config, settings, or env does not by itself require permission. Configuration UIs, models, schemas, validation, tests, documentation, and refactors are treated as ordinary application code. For example, editing src/features/settings/page.tsx or src/config/user-preferences.ts does not trigger a tool-level confirmation merely because of its path.
This policy is advisory because the agent can use task context to distinguish an actual configuration change from code implementing a configuration feature. Hard-protected credential and secret paths remain blocked unless covered by the trusted mutation exception. Tool hooks still enforce the separate cwd and destructive-command checks.
Permission prompt notifications
The extension queues its confirmation dialogs so concurrent file-tool, destructive bash, and global-config requests show one confirmation at a time. Each decision goes to the request that opened the dialog. A rejected dialog does not stop later requests.
If pi-cmux is installed, pi-cwd-guard sends a best-effort cmux notification/status update whenever it opens a permission confirmation. This is optional and no-ops when pi-cmux is not present.
Common destructive bash confirmation
bash asks for confirmation before common destructive commands such as:
- recursive/forced
rm sudo- dangerous
chmod - recursive
chown git reset --hardgit clean -fd
This is intentionally heuristic and small. It does not parse shell scripts, inspect script files, or sandbox Python/Node.js/other scripts. Recognized forced or recursive rm commands skip confirmation when every static absolute or home-relative target is under an allowedDestructiveBashPaths entry. A compound command may precede the exempted rm only with recognized mkdir -p operations under the same allow-list. Commands with relative, dynamic, ambiguous, mixed, or symlink-escaping targets remain confirm-by-default. Other destructive patterns such as sudo and Git operations are never path-exempted.
The extension also adds advisory prompt guidance telling the agent to inspect both active merged exception lists before requesting permission. It identifies allowedOutsideCwdPaths as recursive exceptions for outside-cwd access and allowedDestructiveBashPaths as trusted locations for protected write/edit and recognized forced or recursive rm exceptions. Relative file-tool paths resolve against the cwd. Restrictions on relative, dynamic, ambiguous, or mixed targets apply only to rm exemptions, not file-tool matching. Outside-cwd permission and application-configuration guidance remain separate. Uncovered scripted access and unrelated destructive commands still require confirmation.
Install
From npm:
pi install npm:pi-cwd-guard
From a local checkout:
pi install /absolute/path/to/pi-cwd-guard
Or test for one run:
pi -e /absolute/path/to/pi-cwd-guard
The package also includes a root index.ts shim, so direct extension-directory configuration such as "extensions": ["/absolute/path/to/pi-cwd-guard"] works too.
Compatibility
pi-cwd-guard uses Pi's extension API via a peer dependency and requires @earendil-works/pi-coding-agent 0.80.3 or newer. Tests and type checks pass against Pi 1.0.2 and the minimum supported 0.80.3 release with matching Pi core packages. Development uses Pi 1.0.2. Loader tests cover both the package manifest and root index.ts entry point.
On Pi releases with structured prompt options, the guard adds guidance through appendSystemPrompt so later extensions can still change prompt sections. Older releases and existing forced prompts use the whole-prompt append fallback.
Compatibility checks with pi-agent-suite 2.13.5 cover loading all suite extensions, retaining guard guidance with the suite's default system-prompt template in either load order, and blocking built-in file and bash calls. The suite requires Pi 1.0.2. It is not a dependency of this package. Custom suite templates must retain {{appendSystemPrompt}} when the guard loads before the suite's system-prompt extension.
Subagent sessions must also load the guard. Suite extension modes that disable extensions or omit the guard do not inherit its protection. The checks do not exercise live model calls or child RPC permission dialogs. A child RPC client must answer confirmation requests, or a guarded call can wait for approval.
Use a current Pi release. Pi 0.80.3 remains API-compatible, but its pinned undici dependency has known security vulnerabilities. The Pi 1.0.2 development dependency tree passes npm audit with no known vulnerabilities.
Development
npm install
npm test
npm run typecheck
npm run pack:dry-run
To run the optional suite integration checks without adding it to this project's dependencies:
suite_dir=$(mktemp -d)
npm install --prefix "$suite_dir" --ignore-scripts pi-agent-suite@2.13.5
PI_CWD_GUARD_SUITE_PATH="$suite_dir/node_modules/pi-agent-suite" npm test
Package manifest
This package exposes its extension through:
{
"pi": {
"extensions": ["./src/index.ts"]
}
}