co-mono/packages/coding-agent/examples/hooks
Mario Zechner 575c875475 Remove allowDuringStreaming flag - commands always run immediately
Hook commands now always execute immediately, even during streaming.
If a command needs to interact with the LLM, it uses pi.sendMessage()
which handles queueing automatically.

This simplifies the API and eliminates the issue of queued slash
commands being sent to the LLM instead of executing.
2025-12-30 22:42:22 +01:00
..
auto-commit-on-exit.ts Move exec to HookAPI, sessionManager/modelRegistry to HookEventContext 2025-12-30 22:42:19 +01:00
confirm-destructive.ts Move exec to HookAPI, sessionManager/modelRegistry to HookEventContext 2025-12-30 22:42:19 +01:00
custom-compaction.ts WIP: Major cleanup - move Attachment to consumers, simplify agent API 2025-12-30 22:42:20 +01:00
dirty-repo-guard.ts Move exec to HookAPI, sessionManager/modelRegistry to HookEventContext 2025-12-30 22:42:19 +01:00
file-trigger.ts Hook API: replace send() with sendMessage(), add appendEntry() and registerCommand() 2025-12-30 22:42:18 +01:00
git-checkpoint.ts Move exec to HookAPI, sessionManager/modelRegistry to HookEventContext 2025-12-30 22:42:19 +01:00
permission-gate.ts WIP: Remove global state from pi-ai OAuth/API key handling 2025-12-25 01:01:03 +01:00
protected-paths.ts Custom tools with session lifecycle, examples for hooks and tools 2025-12-17 16:03:23 +01:00
README.md Improve compaction hooks: add signal, no timeout, SessionManager cleanup, docs 2025-12-24 13:54:05 +01:00
snake.ts Remove allowDuringStreaming flag - commands always run immediately 2025-12-30 22:42:22 +01:00

Hooks Examples

Example hooks for pi-coding-agent.

Examples

permission-gate.ts

Prompts for confirmation before running dangerous bash commands (rm -rf, sudo, chmod 777, etc.).

git-checkpoint.ts

Creates git stash checkpoints at each turn, allowing code restoration when branching.

protected-paths.ts

Blocks writes to protected paths (.env, .git/, node_modules/).

file-trigger.ts

Watches a trigger file and injects its contents into the conversation. Useful for external systems (CI, file watchers, webhooks) to send messages to the agent.

confirm-destructive.ts

Prompts for confirmation before destructive session actions (clear, switch, branch). Demonstrates how to cancel before_* session events.

dirty-repo-guard.ts

Prevents session changes when there are uncommitted git changes. Blocks clear/switch/branch until you commit.

auto-commit-on-exit.ts

Automatically commits changes when the agent exits (shutdown event). Uses the last assistant message to generate a commit message.

custom-compaction.ts

Custom context compaction that summarizes the entire conversation instead of keeping recent turns. Uses the before_compact hook event to intercept compaction and generate a comprehensive summary using complete() from the AI package. Useful when you want maximum context window space at the cost of losing exact conversation history.

Usage

# Test directly
pi --hook examples/hooks/permission-gate.ts

# Or copy to hooks directory for persistent use
cp permission-gate.ts ~/.pi/agent/hooks/

Writing Hooks

See docs/hooks.md for full documentation.

Key Points

Hook structure:

import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";

export default function (pi: HookAPI) {
  pi.on("session", async (event, ctx) => {
    // event.reason: "start" | "before_switch" | "switch" | "before_clear" | "clear" |
    //               "before_branch" | "branch" | "shutdown"
    // event.targetTurnIndex: number (only for before_branch/branch)
    // ctx.ui, ctx.exec, ctx.cwd, ctx.sessionFile, ctx.hasUI

    // Cancel before_* actions:
    if (event.reason === "before_clear") {
      return { cancel: true };
    }
    return undefined;
  });

  pi.on("tool_call", async (event, ctx) => {
    // Can block tool execution
    if (dangerous) {
      return { block: true, reason: "Blocked" };
    }
    return undefined;
  });

  pi.on("tool_result", async (event, ctx) => {
    // Can modify result
    return { result: "modified result" };
  });
}

Available events:

  • session - lifecycle events with before/after variants (can cancel before_* actions)
  • agent_start / agent_end - per user prompt
  • turn_start / turn_end - per LLM turn
  • tool_call - before tool execution (can block)
  • tool_result - after tool execution (can modify)

UI methods:

const choice = await ctx.ui.select("Title", ["Option A", "Option B"]);
const confirmed = await ctx.ui.confirm("Title", "Are you sure?");
const input = await ctx.ui.input("Title", "placeholder");
ctx.ui.notify("Message", "info"); // or "warning", "error"

Sending messages:

pi.send("Message to inject into conversation");