Files
harness-tools/extensions/native-hooks

pi-native-hooks

A native Pi extension that coordinates trusted personal policies after workspace mutations. It shares one ast-grep analysis snapshot across diagnostic policies and gates settlement until exact, current verification evidence exists or the agent records a reasoned waiver.

Requirements

  • Node.js 22.19 or newer
  • Pi 0.84.4 or compatible
  • ast-grep 0.45 or newer for diagnostics

Install

Installation is a separate, user-level mutation and is not performed by this repository's tests:

pi install npm:@_jb/pi-native-hooks

For monorepo development, use the curated link policy or load extensions/native-hooks/extensions/pi-native-hooks/index.ts directly.

Then use:

/hooks-init --dry-run
/hooks-init --apply
/hooks-doctor
/reload

--apply displays every destination and asks for interactive confirmation. Existing files are preserved; newly created files are rolled back after a partial failure.

Trust model

Files under ~/.config/pi-native-hooks/policies/*.ts are trusted executable code. Importing them runs with Pi's filesystem, process, network, credentials, and outer sandbox authority. Structural validation is not a sandbox. The loader accepts only sorted direct-child .ts files and requires the config root, policies, ast-grep configuration, and rules to be owned by the current OS user, non-symlinked, regular files/directories, and not group/other writable.

Personal policies use Node's erasable TypeScript subset: type-only syntax, interfaces, and satisfies work; enums, namespaces, parameter properties, JSX, and tsconfig transforms do not. Policies reload only with /reload or session replacement.

Diagnostics

The starter policies flag TypeScript/TSX non-null assertions and dynamic imports. Both use ast-grep:personal, so one mutation wave runs one scan and fans the immutable snapshot to both policies. A justified exception uses the exact rule ID:

const plugin = await import(path); // ast-grep-ignore: typescript-no-dynamic-import-ts -- runtime-selected plugin

Analyzer failures are visible and never turn a successful mutation into a tool error. Unchanged findings are not repeatedly delivered.

Verification gate

Starter project policies require these exact standalone commands from the matched Git project root:

bun run test
bun run typecheck

Focused, combined, altered, wrong-directory, failed, aborted, concurrent, or stale commands do not count. A state-free session treats existing dirty files as its baseline; requirements arm only after an observed relevant mutation or restoration of armed branch state. At agent_settled, outstanding checks trigger another Pi turn.

The agent may call pi_hooks_waive_verification with a non-empty reason. A waiver is auditable, revision-scoped, distinguishable from a pass, and expires after the next relevant mutation.

Pi exposes foreground bash completion as isError rather than a numeric exit code. If a shell is externally signaled but Pi reports success, this extension cannot independently disprove completion. The settlement gate also cannot prevent a user or external client from closing Pi.

Commands

  • /hooks-status — policy digests and paths, trust/load failures, project identity, workspace revision, analyzer health, findings, verification revisions, evidence, waivers, and failures
  • /hooks-init --dry-run — preview external config writes
  • /hooks-init --apply — request authorization and initialize missing starter files
  • /hooks-doctor — validate policy loading and ast-grep availability

Development

bun run typecheck
bun run test

Architecture and acceptance details are in docs/implementation-plan.md. Event payload and project identity assumptions are pinned in docs/event-contract.md.