@ghoseb/pi-damage-control

AST-based Damage Control extension for Pi

Packages

Package details

extension

Install @ghoseb/pi-damage-control from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@ghoseb/pi-damage-control
Package
@ghoseb/pi-damage-control
Version
0.11.2
Published
May 29, 2026
Downloads
679/mo · 17/wk
Author
0xbg
License
MIT
Types
extension
Size
153.4 KB
Dependencies
2 dependencies · 5 peers
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-damage-control

npm

About

pi-damage-control is an AST-based Damage Control extension for Pi. It blocks or asks before destructive shell/file tool calls while avoiding false positives from inert prose, markdown, heredocs, and task descriptions.

Installation

pi install npm:@ghoseb/pi-damage-control
# OR
# pi install git:github.com/ghoseb/pi-damage-control

How it works

  • Parses Bash with just-bash; no regex fallback.
  • Evaluates semantic command rules from config/default-policy.yaml.
  • Extracts file intents from Bash and Pi file tools.
  • Applies path policies for zero-access, read-only, no-delete, and outside-$CWD writes.
  • Asks for confirmation when policy action is ask; blocks fail-closed when UI is unavailable.

How to configure

Create a project policy at:

.pi/damage-control.yaml

or a global policy at:

~/.pi/agent/damage-control.yaml

Project policy wins over global policy; otherwise the bundled default is used.

See the bundled default policy: config/default-policy.yaml. For the full policy language reference, see docs/policy.md.

Config language

Top-level policy shape:

version: 2
settings:
  defaultAction: ask
  parseFailure: ask
  showStatus: true
rules: []

Path policy

Path rules live in the same top-level rules list as command rules. Their type encodes the path policy subtype:

  • path:zeroAccess — blocks read, write, delete, and move.
  • path:readOnly — applies to write, delete, and move; reads are allowed.
  • path:noDelete — applies to delete and move.

Each path rule has:

- id: path-secrets-env
  type: path:zeroAccess
  action: block
  reason: environment files may contain secrets
  match:
    path:
      any: .env*
      except: [.env.example]

match.path.any can be a string or a list of strings:

match:
  path:
    any: [LICENSE, LICENSE.*, COPYING, COPYING.*]

Supported path pattern forms:

  • exact/basename: README.md, .env
  • directory: .git/, node_modules/
  • glob-ish *: *.pem, docker-compose.*.yml
  • current-working-directory macros: $CWD, !$CWD

Example outside-project write confirmation:

- id: path-outside-project-write
  type: path:readOnly
  reason: writes outside the project require confirmation
  match:
    path:
      outside: $CWD
      except: [/tmp/, /dev/null]

Command rules

Command rules use type: command:

- id: git-reset-hard
  type: command
  action: block
  reason: git reset --hard discards worktree changes
  match:
    command: git
    subcommand: reset
    flags:
      any: [--hard]

Common matcher fields:

  • command: exact command name.
  • commandAny: one of several command names.
  • subcommand: first non-option command operand.
  • subcommandAny: one of several subcommands.
  • argsAny: any listed argument must be present.
  • argsAll: all listed arguments must be present.
  • argsNone: none of the listed arguments may be present.
  • argsContainAny / argsContainAll: substring matching over arguments.
  • flags.any / flags.all / flags.none: semantic flag matching.
  • optionsBeforeSubcommand.value: value-taking global options before subcommand detection, useful for git -C repo ....
  • visibleTextAny / visibleTextAll / visibleTextNone: match visible static text, useful for SQL executors.

Rules have enabled: true by default. Runtime /dc:block and /dc:unblock temporarily toggle that enabled state by rule id.

Actions:

  • allow
  • ask
  • block

action is optional on any rule. When omitted it falls back to settings.defaultAction (which defaults to ask).

Disabled-by-default rules are opt-in at runtime:

- id: git-commit
  type: command
  enabled: false
  action: block
  reason: git commit blocked by active rule
  match:
    command: git
    subcommand: commit

Example:

version: 2
settings:
  defaultAction: ask
  parseFailure: ask
  showStatus: true
rules:
  - id: path-secrets-env
    type: path:zeroAccess
    action: block
    reason: environment files may contain secrets
    match:
      path:
        any: .env*
        except: [.env.example]
  - id: path-outside-project-write
    type: path:readOnly
    reason: writes outside the project require confirmation
    match:
      path:
        outside: $CWD
        except: [/tmp/, /dev/null]
  - id: git-commit
    type: command
    enabled: false
    action: block
    reason: git commit blocked by active rule
    match:
      command: git
      subcommand: commit

Commands available

  • /dc:block [rule-id ...] — enables rules at runtime; all enables all rules; with no args, resets to config defaults.
  • /dc:unblock <rule-id ...> — disables rules at runtime; all disables all rules.
  • /dc:yolo — toggles bypass of all Damage Control checks.
  • /dc:reload — reloads policy.
  • /dc:status — shows active policy and runtime state.

Acknowledgements

License

MIT © Baishampayan Ghose