Skip to content
/

pi-steering-hooks

pi-steering-hooks · samfoy/pi-steering-hooks · ★ 5 · last commit 2026-05-14

Pre-tool regex guardrails for the pi coding agent — deterministic, zero-token enforcement of behavioral rules with a self-authorizing override escape hatch.

Best whenHooks work every time; prompts work most of the time — encode safety rules in code, not in natural language.
Skip ifprompt-based safety rules (unreliable), force push without --force-with-lease
vs seeds
pi-steering-hooks targets the pi coding agent (earendil-works/pi-mono) which no seed framework supports. Architecturally it's the …
Primitive shape 1 total
Hooks 1
00

Summary

pi-steering-hooks — Summary

pi-steering-hooks is a minimal TypeScript extension for the pi coding agent (earendil-works/pi-mono) that registers a tool_call hook intercepting bash, write, and edit tool calls before execution, evaluating configurable regex rules to block violations deterministically — zero tokens spent, 100% reliability. It ships 5 default rules (no-force-push, no-hard-reset, no-rm-rf-slash, conventional-commits, no-long-running-commands) and supports custom rules via steering.json in the project root or ~/.pi/agent/. Each blocked call returns a reason message to the agent for self-correction; an override escape hatch allows the agent to bypass non-hard rules with a # steering-override: rule-name — reason comment, logged for audit. Inspired explicitly by Strands Agents' "Steering Accuracy Beats Prompts" blog post. Compared to seeds: pi-steering-hooks is the most minimal guardrail framework in the batch — single-tool (pi agent), 5 default rules, zero framework beyond the extension API. No seed targets the pi agent specifically.

01

Overview

pi-steering-hooks — Overview

Origin

Repo: samfoy/pi-steering-hooks. Created April 2026, TypeScript, MIT. 5 stars. Author: samfoy.

Target Platform

The pi agent: earendil-works/pi-mono (a coding agent with extension API). pi-steering-hooks is installable via pi install @samfp/pi-steering-hooks.

Philosophy

From README:

"Prompt-based rules ('never force push') work most of the time. Steering hooks work every time. They intercept tool calls before execution and block violations deterministically, with an override escape hatch for when the agent has a good reason."

Explicit inspiration cited in README:

"Inspired by Strands Agents: Steering Accuracy Beats Prompts"

The core thesis: encoding behavioral rules in prompts is probabilistic (the model may forget or misapply them). Encoding them as code hooks is deterministic. The name "steering" signals this distinction — hooks steer the agent rather than instruct it.

Design Principles

  • Zero token cost for enforcement
  • 100% reliability (deterministic regex)
  • Override escape hatch — agent can provide a reason and bypass non-critical rules (but the override is logged)
  • noOverride: true for catastrophic cases (rm -rf /)
  • Minimal configsteering.json with simple field format
  • Gradual disclosure — 5 safe defaults that any project can use as-is
02

Architecture

pi-steering-hooks — Architecture

Distribution

  • pi extension registry: pi install @samfp/pi-steering-hooks
  • npm package (underlying): TypeScript, MIT
  • Repo: samfoy/pi-steering-hooks

Directory Structure (repo)

pi-steering-hooks/
  src/
    index.ts         Main extension entry point + all rule logic
  package.json
  tsconfig.json
  LICENSE
  README.md

Minimal codebase — essentially one file (src/index.ts).

Required Runtime

  • Node.js (TypeScript transpiled)
  • pi coding agent installed (earendil-works/pi-mono)

Extension API

Registers a tool_call hook via pi's extension API:

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";

Config Files

  • ./steering.json (project root) — project-scoped rules
  • ~/.pi/agent/steering.json — global rules

Config priority: project root wins over global (first found wins).

Target AI Tools

pi coding agent exclusively (earendil-works/pi-mono). Zero compatibility with Claude Code, Cursor, Codex, or any other agent.

Rule Matching Architecture

Each rule has:

  • tool: which tool to intercept (bash, write, edit)
  • field: which input field to test (command, path, content)
  • pattern: regex that triggers a violation if it matches
  • requires: optional AND condition
  • unless: optional exemption regex
  • reason: message returned to agent on block
  • noOverride: optional hard block flag
03

Components

pi-steering-hooks — Components

Core: One Extension File

src/index.ts — the entire framework in one TypeScript file (~200 lines).

Default Rules (5)

Rule Name Tool Field What it blocks
no-force-push bash command git push --force (not --force-with-lease)
no-hard-reset bash command git reset --hard
no-rm-rf-slash bash command rm -rf / (hard block — no override allowed)
conventional-commits bash command git commit -m messages not matching Conventional Commits format
no-long-running-commands bash command Dev servers and watchers (blocks agent-blocking commands)

Rule Format

interface Rule {
  name: string;
  tool: "bash" | "write" | "edit";
  field: "command" | "path" | "content";
  pattern: string;        // Regex — match = violation
  requires?: string;      // AND condition (optional)
  unless?: string;        // Exemption regex (optional)
  reason: string;         // Block message to agent
  noOverride?: boolean;   // Hard block if true
}

Config Format (steering.json)

{
  "disable": ["conventional-commits"],
  "rules": [
    {
      "name": "no-git-push",
      "tool": "bash",
      "field": "command",
      "pattern": "\\bgit\\s+push\\b",
      "reason": "Use `cr` instead of `git push`."
    }
  ]
}

Override Mechanism

Agent retry pattern:

git push --force origin main  # steering-override: no-force-push — deploying hotfix

The override comment is parsed, logged via appendEntry, and the call is allowed through.

Audit Logging

Override uses appendEntry (from pi's extension API) to log the override reason. No persistent DB — relies on pi's session log.

No Dashboard, No CLI Binary, No Skills, No Subagents

pi-steering-hooks ships nothing beyond src/index.ts + steering.json config format.

05

Prompts

pi-steering-hooks — Prompts

Verbatim Excerpt 1: src/index.ts (Default Rules)

const DEFAULT_RULES: Rule[] = [
  {
    name: "no-force-push",
    tool: "bash",
    field: "command",
    pattern: "\\bgit\\s+push\\b.*--force(?!-with-lease)",
    reason: "Force push rewrites remote history and can destroy teammates' work. Use `git push --force-with-lease` if you must, or better yet, create a new commit.",
  },
  {
    name: "no-hard-reset",
    tool: "bash",
    field: "command",
    pattern: "\\bgit\\s+reset\\s+--hard\\b",
    reason: "Hard reset discards uncommitted changes permanently. Use `git stash` to save work first, or `git reset --soft` to keep changes staged.",
  },
  {
    name: "no-rm-rf-slash",
    tool: "bash",
    field: "command",
    pattern: "\\brm\\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\\s+/(?:\\s|$)",
    reason: "Recursive force-delete from root is catastrophic. Specify a safe path.",
    noOverride: true,
  },
  {
    name: "conventional-commits",
    tool: "bash",
    field: "command",
    pattern: "\\bgit\\s+commit\\b.*-m\\s+[\"'](?!(feat|fix|style|refactor|docs|test|chore|perf|ci|build|revert)(\\(.+\\))?(!)?: )",
    reason: "Commit message must use Conventional Commits format: `type(scope): description`. Types: feat, fix, style, refactor, docs, test, chore, perf, ci, build, revert.",
  },

Technique: reason-as-documentation — each rule's reason field is not just an error message but a teaching moment explaining why the rule exists and what the safe alternative is. This enables agents to self-correct rather than just retry blindly.

Verbatim Excerpt 2: README (Override Mechanism)

When a rule fires, the agent can retry with an override comment:

```bash
git push --force origin main  # steering-override: no-force-push — deploying hotfix to unblock prod

The override is allowed through but logged to the session for audit. Rules with noOverride: true (like no-rm-rf-slash) cannot be overridden.


**Technique**: escape-hatch design — the override mechanism acknowledges that rules can have legitimate exceptions while preserving audit accountability. This is a key design choice: strict-by-default but pragmatic in exceptions. Unlike clauder (which requires human approval for some operations), pi-steering-hooks trusts the agent to self-authorize with a stated reason.
09

Uniqueness

pi-steering-hooks — Uniqueness & Positioning

Differs from Seeds

pi-steering-hooks targets the pi coding agent (earendil-works/pi-mono), which none of the 11 seeds supports. The closest seed in terms of design philosophy is spec-kit — both use a hook-based approach to enforce behavioral rules on AI tool calls. But spec-kit's 18 hooks enforce a spec-driven development workflow; pi-steering-hooks enforces a handful of git/filesystem safety rules. The override-with-reason mechanism (agent self-authorizes with a stated rationale) is not present in any seed framework — seeds either block absolutely or require human approval. The minimal footprint (~200 lines, no database, no dashboard) is philosophically closer to the "Markdown scaffold, zero primitives" archetype (claude-conductor) but applied to hooks rather than templates.

Positioning

Signal type: regex-based pre-tool guardrail Intervention point: before tool execution (all bash/write/edit calls) Unique features: self-authorizing override with audit, noOverride: true hard blocks, pi-agent-specific, minimal codebase Target user: pi agent users who want reliable behavioral guardrails without prompt engineering

Observable Failure Modes

  • Limited to pi agent — zero value for Claude Code, Cursor, Codex teams
  • Regex-only enforcement misses semantic violations (you can write a script that does git push --force via a variable)
  • No human-in-the-loop approval (unlike DashClaw) — agent self-authorizes overrides
  • 5 stars / 2 forks — very early adoption
  • Single author — bus factor of 1

Relationship to Batch 31

pi-steering-hooks is the conceptual minimum viable guardrail framework in the batch. Where DashClaw is a full governance platform and Sponsio is a formal-methods library, pi-steering-hooks is a single TypeScript file with 5 regex rules. The design philosophy (hooks > prompts for reliability) is shared across the batch, but the implementation is the simplest possible expression of that idea.

04

Workflow

pi-steering-hooks — Workflow

Install

pi install @samfp/pi-steering-hooks

After install, all tool calls from pi agent flow through the steering hook automatically.

Per-Call Flow

pi agent wants to execute bash/write/edit
          ↓
tool_call hook fires (from pi extension API)
          ↓
Rules evaluated (regex matching) in order
          ↓
If match found: return block message + reason
          ↓
Agent sees block, adjusts approach
          ↓
If agent has legitimate reason: retry with override comment
          # steering-override: rule-name — reason
          ↓
Override parsed, logged via appendEntry, call allowed through

Configuration

  1. Place steering.json in project root (or ~/.pi/agent/ globally)
  2. Disable unwanted default rules via "disable": ["rule-name"]
  3. Add custom rules in "rules": [...]

Approval Gates

Soft override mechanism (not a human approval gate — agent self-authorizes with reason). noOverride: true creates a hard gate with no escape.

Phases

Phase Artifact
Install extension registered with pi
Rule evaluation block message or pass
Override audit log entry

Execution Mode

Event-driven — fires on every tool call during pi agent session.

06

Memory Context

pi-steering-hooks — Memory & Context

State Storage

Minimal. No persistent database.

Audit Log

Override events are logged via pi's appendEntry API — these entries are part of pi's own session log. pi-steering-hooks does not maintain an independent audit store.

Rule Config

steering.json — read on extension load, held in memory for the session. No dynamic updates during session.

No Cross-Session Memory

Each pi session starts fresh. Rule evaluation is stateless per call.

No Context Injection

pi-steering-hooks does not inject any context into the agent's conversation or modify the agent's prompt. It only intercepts tool calls.

Compaction

Not applicable.

07

Orchestration

pi-steering-hooks — Orchestration

Multi-Agent

No. Single pi agent session.

Orchestration Pattern

None.

Isolation Mechanism

None.

Execution Mode

Event-driven — fires on every tool call during pi agent session.

Multi-Model

No.

Cross-Tool Portability

Single-tool — pi agent exclusively. The extension API is specific to @earendil-works/pi-coding-agent.

Consensus

None.

Prompt Chaining

Not applicable.

Minimalism Note

pi-steering-hooks is intentionally the most minimal framework in Batch 31. Its entire codebase is ~200 lines of TypeScript. The design decision is clarity over features — the fewer moving parts, the more trust users can place in its behavior.

08

Ui Cli Surface

pi-steering-hooks — UI & CLI Surface

CLI Binary

None. pi-steering-hooks is an extension, not a CLI tool. Install via pi install @samfp/pi-steering-hooks.

Local UI

None.

IDE Integration

Via pi agent's extension system. No separate IDE integration.

Observability

  • Override events logged via appendEntry to pi's session log
  • No separate dashboard or monitoring surface

Configuration

Flat JSON file (steering.json):

{
  "disable": ["rule-name"],
  "rules": [
    { "name": "...", "tool": "bash", "field": "command", "pattern": "...", "reason": "..." }
  ]
}

Two locations checked in order:

  1. ./steering.json (project root)
  2. ~/.pi/agent/steering.json (global)

Minimal Surface Note

pi-steering-hooks has the smallest surface area of any framework in Batch 31:

  • 1 TypeScript file
  • 1 JSON config format
  • 5 default rules
  • 0 CLIs, 0 dashboards, 0 hooks beyond its own extension registration

Related frameworks

same archetype · same primary tool · same memory type

OpenHarness ★ 13k

Open-source Python agent runtime providing complete harness infrastructure: tools, memory, governance, swarm coordination, and…

Trae Agent ★ 12k

Research-friendly open-source CLI coding agent by ByteDance, designed for academic ablation studies and modular LLM provider…

Sweep AI ★ 7.7k

Autonomous GitHub bot that converts issues to pull requests using a sequential multi-agent pipeline.

Agent Governance Toolkit (microsoft) ★ 2.3k

Enterprise-grade AI agent governance: YAML policy enforcement, 12-vector prompt injection defense, zero-trust identity,…

TDD Guard ★ 2.1k

Mechanically enforces the Red-Green-Refactor TDD cycle by blocking file writes that violate TDD principles via a PreToolUse hook…

Agentic Coding Flywheel Setup (ACFS) ★ 1.5k

Take a complete beginner from laptop to three AI coding agents running on a VPS in 30 minutes via an idempotent manifest-driven…