# damage-control-continue

Safety auditing — blocks destructive tool calls, but lets the agent **adapt and keep working**.

> Ported from [`pi-vs-claude-code`](https://github.com/disler/pi-vs-claude-code) by [disler](https://github.com/disler) (MIT). See the [extension catalog](../../../docs/pi-extensions.md).

## What it does

It loads `.pi/damage-control-rules.yaml` (`bashToolPatterns`, `zeroAccessPaths`,
`readOnlyPaths`, `noDeletePaths`) and checks every tool call against it.

On a match, `damage-control-continue` replaces the tool result with **actionable
feedback** that distinguishes destructive from non-destructive intent and tells
the agent how to adapt. It does **not** call `ctx.abort()`: the blocked operation
fails closed, but the turn continues so the agent can report the block or take a
safe alternative. Protected-path calls may proceed only through the explicit
approval/exemption paths below; inherently dangerous command patterns never can.

## Version footer and provenance

This persistent-UI harness shows `agent fleet v<version>` below the prompt. It shares one common-key
status with `agent-hub` and `coms`, so a stack renders the version once. Its
version remains separate from the mutable `damage-control` status: active-rule and
last-violation feedback never replaces it. The root `package.json` is canonical;
`bin/sync-harness-versions.js` synchronizes its value into this adjacent manifest. The local
`version.ts` reader supports copied or symlinked harness directories by resolving that adjacent
stamp, but those targets still require the pre-existing full `.pi/harnesses/` dependency
installation.

The `agent fleet` half of the label is an OSC 8 terminal hyperlink to the project homepage —
clickable in terminals that support hyperlinks, ignored (rendered as plain text) elsewhere, and
free of footer columns because pi strips OSC sequences before measuring width. It opens the
repository in a browser, not a TUI panel: pi has no mouse tracking, so a click never reaches the
harness. `AGENT_FLEET_NO_LINKS=1` restores the plain label on multiplexers that mangle OSC 8
(GNU screen, tmux before 3.4).

## Exemptions — allow access per turn or per session

Runtime allowances layered on top of the rules file (which is never modified).
They apply to the **path categories only** — `zeroAccessPaths`, `readOnlyPaths`,
`noDeletePaths`. Destructive `bashToolPatterns` (`rm -rf`, `git push --force`,
`DROP TABLE`, …) can never be exempted.

**Pre-authorize** (when you know the agent will need it):

```
/af-allow .env            # exempt for the rest of the session (default)
/af-allow .env turn       # exempt until the end of the current/next turn
/af-allowed               # list active exemptions
/af-revoke .env           # remove an exemption
```

**Block-time dialog** (when you forgot): in an interactive session a path block
opens a selector — *Keep blocked / Allow once / Allow for this turn / Allow for
this session*. An approved call proceeds immediately (the agent never sees the
block); *Keep blocked* is remembered for the rest of the turn so the agent can't
re-prompt you; no answer within 60s fails closed.

**Escalation from headless children**: when this harness runs inside a subagent
spawned by agent-hub (no UI, `AGENT_HUB_ASK_ENDPOINT` set), a path block sends an
`access_request` to the hub's coms socket instead. The dispatcher session shows
who is asking, for what, and why it was blocked. Ordinary protected reads/writes
offer *Deny / Allow once / Allow for this agent / Allow for all agents (session)*.
A protected deletion offers only *Deny / Allow once*, so approving one file does
not grant its parent directory. The child waits up to 60s and fails closed on
timeout. At most 3 escalations per child run; denials are cached.

**Shared exemptions file**: agent-hub keeps one session-scoped file
(`~/.pi/coms/exemptions/<session>.json`, deleted on shutdown) and passes it to
every spawned child via `AGENT_HUB_EXEMPTIONS_FILE`. `/af-allow <pattern> session`
in the hub lands there, so it covers the whole team. Every native specialist,
research helper, and nested delegate uses this harness and re-reads the file on
every block, so mid-session grants reach already-running children. Everything
(grants, revokes, escalation
outcomes) is logged to the `damage-control-log` session entries.

## When it's used (this repo)

Every `just fleet` Pi mode loads this harness: the default interactive session,
standalone peers, Hub, and Herdr Pi peers. Agent Hub additionally re-loads it into
every native **specialist, research helper, and nested delegate**. If the harness cannot be resolved, Agent Hub
refuses guarded child dispatch rather than launching an unprotected process.

## Commands & tools

- `/af-allow <pattern> [turn|session]` — exempt a protected path pattern
- `/af-allowed` — list active exemptions
- `/af-revoke <pattern>` — remove an exemption

Blocking itself runs passively on the `tool_call` event.

## Requires

- `.pi/damage-control-rules.yaml` — the rule set (shipped in this repo)
- Optional, injected by agent-hub into spawned children: `AGENT_HUB_ASK_ENDPOINT`
  (escalation socket), `AGENT_HUB_EXEMPTIONS_FILE` (shared grants),
  `AGENT_HUB_AGENT_ID` (requester identity). Without them the harness behaves
  standalone: dialog when a UI is present, plain block+feedback otherwise.

## Usage

```bash
# standalone continue-mode guardrail session
just fleet
pi -e .pi/harnesses/damage-control-continue/index.ts

# Hub variants
just fleet hub
just fleet hub --solo

# direct continue-guarded hub launch
pi -e .pi/harnesses/damage-control-continue/index.ts -e .pi/harnesses/agent-hub/index.ts
```

## Upstream changes

- Theme integration removed — the `themeMap.ts` import and the `applyExtensionDefaults()`
  call were stripped (this repo does not ship pi themes).
- The `find` tool's `pattern` is matched against `zeroAccessPaths`, closing a gap
  where `find` could still locate secret files.
- Exemption layer added (not in upstream): `/af-allow`/`/af-allowed`/`/af-revoke`,
  block-time approval dialog, and escalation from headless agent-hub children to
  the dispatcher — see the Exemptions section above. Shared plumbing lives in
  [`../lib/damage-control-shared.ts`](../lib/damage-control-shared.ts).
