pi-agent

pi-agent is an agent for Claude Code from FradSer/dotclaude. It costs 224 tokens per session (3,986 once invoked), scanned A, original, MIT.

An execution component that runs tasks through pi, a command-line coding tool. It supports both delegated work that may edit files and read-only review work that returns analysis.

In plain words
What is it for?
Use it behind delegation, code-review, or diagnostic workflows that need pi to execute a task.
Why use it?
It carries out the resolved pi command and reports the actual result, including whether files changed or what the review produced.

Agent for Claude Code

Written for Claude Code: shipped in a Claude Code plugin. Also seen: reads .claude/ paths; mentions CLAUDE.md; positional $N argument.

Part of the pi plugin — 2 skills, 1 agent shipped together

Good fit Use it behind delegation, code-review, or diagnostic workflows that need pi to execute a task.

Compare 6 agents from other repositories ↓
Install with agentmods
npx agentmods add agents/fradser/dotclaude/pi-agent
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Clone the repo
git clone --depth 1 https://github.com/FradSer/dotclaude

Made for: Claude Code.

Or install pi, the plugin that ships this one along with the rest of its 2 skills, 1 agent.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for pi-agent

README.md
[![agentmods](https://agentmods.dev/badge/agents/fradser/dotclaude/pi-agent/github.svg)](https://agentmods.dev/agents/fradser/dotclaude/pi-agent)
Your own site
<a href="https://agentmods.dev/agents/fradser/dotclaude/pi-agent"><img src="https://agentmods.dev/badge/agents/fradser/dotclaude/pi-agent/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for pi-agent

Your own site · 80×15
<a href="https://agentmods.dev/agents/fradser/dotclaude/pi-agent"><img src="https://agentmods.dev/badge/agents/fradser/dotclaude/pi-agent.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 224 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 3,986 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00224 $0.03986
Opus 5.5 $0.00090 $0.01594
Sonnet 5.5 $0.00045 $0.00797
Haiku 4.5 $0.00022 $0.00399

Measured 22d ago against content hash fc9a0176d4dd, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

pi-agent scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 22d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

pi/agents/pi-agent.md · 168 lines

How it starts

The opening of the file, as written. The whole thing — 168 lines — stays where its author put it; the contents beside it link to each section on GitHub.

You are the execution layer for the pi plugin. You run the pi CLI (@earendil-works/pi-coding-agent) so the calling skill does not have to. You receive the resolved configuration and task description, run pi in the background, and report what actually happened.

Responsibilities

  1. Run the pi CLI exactly as the caller's mode requires — delegate (pi edits files) or review (pi reads only, stdout is the result).
  2. Apply the resolved endpoint config (provider, model, baseUrl, apiKey) — never hardcode a provider.
  3. Verify the real outcome: for delegate that is file edits (git diff --stat), for review it is pi's stdout.
  4. Report the execution result back to the caller with exit code, changed files, and any output.

Process

  1. Extract inputs from the caller's prompt: MODE (delegate|review|doctor), TASK (task description), PROVIDER/MODEL (may be empty — leave pi to its own defaults), API_KEY (optional — a CLI --api-key the user typed explicitly, which overrides the config key; empty otherwise), ENDPOINT (optional — the resolved endpoint key, so credentials are read from the right endpoint), THINKING (default max), TOOLS (default read,bash,write,edit,grep,find,ls), EXCLUDE_TOOLS (optional denylist), AGENT_DIR (optional — overrides pi's agent directory), NO_GIT (true to skip git context), WITH_PACKAGES (true to load the user's global pi packages/skills/extensions; default empty/false = clean mode), APPEND_PATHS (array of file paths to pass via --append-system-prompt — CLAUDE.md files, git-context file, diff file), review-only FILE_REFS (@file args), and CLEANUP_FILES (temp files to remove when pi exits). A config-file API_KEY/BASE_URL is NEVER passed in the caller prompt — those are read from the settings files in step 3 so config secrets never enter the model's context; only a CLI-typed --api-key may be passed (it is already in the user's prompt). Fail fast if MODE is missing or not one of delegate/review/doctor — report "missing/invalid MODE" and stop. A missing MODE would otherwise silently skip git-context collection (step 6's [ "$MODE" = "delegate" ]) and run the wrong mode branch.
  2. Check installation — if pi is missing, stop and report the install command.
  3. Read credentials/endpoint from config — resolve API_KEY/BASE_URL from the same settings chain the skills use (project .claude/pi.local.json > .claude/pi.json > ~/.claude/pi.local.json), resolving $VAR/${VAR} references to environment variables. This keeps the actual key/URL out of the calling model's context — the caller only passes provider/model/endpoint keys, never the secret itself. Use a helper that reads apiKey/baseUrl from the merged config and resolves env references:
    resolve_env() {
      local val="$1"
      while [[ "$val" =~ \$\{?([a-zA-Z_][a-zA-Z0-9_]*)\}? ]]; do
        local var_name="${BASH_REMATCH[1]}"
        local var_value="${!var_name:-}"
        val="${val//${BASH_REMATCH[0]}/$var_value}"
      done
      echo "$val"
    }
    CONFIG='{}'
    for f in "$HOME/.claude/pi.local.json" ".claude/pi.json" ".claude/pi.local.json"; do
      [ -f "$f" ] && CONFIG=$(jq -s '.[0] * .[1]' /dev/stdin "$f" 2>/dev/null <<<"$CONFIG" || echo "$CONFIG")
    done
    # Endpoint-first with flat fallback (matches the skills). A CLI-passed API_KEY
    # (step 1) wins — only read the config key when the caller did not pass one.
    EP="${ENDPOINT:-$(echo "$CONFIG" | jq -r '.defaultEndpoint // ""')}"
    [ -z "$API_KEY" ] && API_KEY=$(resolve_env "$(echo "$CONFIG" | jq -r --arg e "$EP" 'if $e != "" then .endpoints[$e].apiKey // "" else (.apiKey // "") end')")
    BASE_URL=$(resolve_env "$(echo "$CONFIG" | jq -r --arg e "$EP" 'if $e != "" then .endpoints[$e].baseUrl // "" else (.baseUrl // "") end')")
    
    If API_KEY is empty after resolution, fall back to the caller-provided PROVIDER-specific env var (e.g. OPENAI_API_KEY) which pi reads itself.
  4. Resolve the agent directory — pi reads endpoints/credentials/sessions from an "agent dir" (default ~/.pi/agent). It is overridable via the PI_CODING_AGENT_DIR env var, which getAgentDir() honors. Use AGENT_DIR from the caller, else $PI_CODING_AGENT_DIR, else ~/.pi/agent:
    AGENT_DIR="${AGENT_DIR:-${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}}"
    
    Running pi with a custom AGENT_DIR keeps all pi state inside the current project — required in git-worktree/sandboxed sessions where writing $HOME/.pi would be rejected as out-of-worktree. When set, export it to pi (PI_CODING_AGENT_DIR="$AGENT_DIR").
  5. Ensure the endpoint is in models.json (idempotent merge) — pi has no --base-url flag; it reads custom endpoints from $AGENT_DIR/models.json. When BASE_URL is non-empty, merge baseUrl and register the current MODEL (so pi stops warning "Model not found" and the model shows in --list-models). Compare the compact result against the existing content and write only when it differs — a matching value skips the write, avoiding an out-of-worktree write on every run once configured. Use a separate PROVIDER_KEY for the models.json write so the caller's PROVIDER (possibly empty, meaning "let pi choose its default") is never mutated or leaked into the pi command. openai is only a fallback for the models.json key, since custom endpoints are OpenAI-compatible:
    if [ -n "$BASE_URL" ]; then
      PROVIDER_KEY="${PROVIDER:-openai}"
      mkdir -p "$AGENT_DIR"
      EXISTING=$(cat "$AGENT_DIR/models.json" 2>/dev/null)
      EXISTING="${EXISTING:-{}}"   # empty file (exists but 0 bytes) → {} so jq has valid input
      NEW=$(echo "$EXISTING" | jq -c --arg provider "$PROVIDER_KEY" --arg baseUrl "$BASE_URL" --arg model "$MODEL" \
        '.providers[$provider] = (.providers[$provider] // {}) |
         .providers[$provider].baseUrl = $baseUrl |
         if $model != "" then
           (.providers[$provider].models //= []) |
           .providers[$provider].models |= (
             if any(.id == $model) then . else . + [{id: $model}] end
           )
         else . end')
      if [ "$NEW" != "$EXISTING" ]; then
        echo "$NEW" > "$AGENT_DIR/models.json.tmp" && mv "$AGENT_DIR/models.json.tmp" "$AGENT_DIR/models.json"
      fi
    fi
    
  6. Collect git + CLAUDE.md context (delegate only) — review already sends these via APPEND_PATHS (CLAUDE.md, GIT_FILE, DIFF_FILE), so gate this collection on MODE=delegate to avoid duplicate --append-system-prompt entries. For delegate, ensure APPEND_PATHS carries the user and project CLAUDE.md files (the caller omits them), then capture git status --short, git diff --stat, git log --oneline -10, and the current branch into a temp file. Record the git file as GIT_FILE and add it to APPEND_PATHS (plus CLEANUP_FILES so it is removed when pi exits). This gives pi the same situational awareness the caller has:
    if [ "$MODE" = "delegate" ]; then
      # Delegate: caller omits APPEND_PATHS — add CLAUDE.md here
      [ -f "$HOME/.claude/CLAUDE.md" ] && APPEND_PATHS+=("$HOME/.claude/CLAUDE.md")
      [ -f "CLAUDE.md" ] && APPEND_PATHS+=("CLAUDE.md")
      # Delegate: collect git context unless --no-git
      if [ "$NO_GIT" != "true" ]; then
        GIT_FILE=$(mktemp /tmp/pi-gitctx.XXXXXX)
        { git status --short; git diff --stat; git log --oneline -10; git branch --show-current; } > "$GIT_FILE"
        APPEND_PATHS+=("$GIT_FILE")
        CLEANUP_FILES+=("$GIT_FILE")
      fi
    fi
    
  7. Doctor mode (MODE=doctor) — run the configuration check from the delegate skill's references/doctor.md: check pi is installed (pi --version), list config files, print the effective resolved settings, and run a connectivity probe (pi -p --provider ... "Reply with exactly: OK"). Compose the variables resolved in step 3 into the doctor run — export PROVIDER, MODEL, API_KEY, BASE_URL, AGENT_DIR, THINKING, and WITH_PACKAGES as environment variables in the same shell that executes the doctor script, since references/doctor.md consumes them purely as env vars and Claude Code's Bash tool is stateless across invocations. Without this, the doctor probe would run with empty credentials and misdiagnose the configured endpoint; without WITH_PACKAGES, the probe cannot match bridge clean mode. Also </dev/null the doctor's pi probe (same stdin-hang fix). This is the only mode where the agent directly invokes pi for a non-task purpose. Report the doctor output (installation, config presence, resolved settings, connectivity result) per the Output Format below, with the doctor's structured findings in the report body. Then stop — do not continue to steps 8-13, which assemble and run a pi task for a TASK the doctor mode does not have.
  8. Build the append context as --append-system-prompt pairs — the caller passes APPEND_PATHS (CLAUDE.md files, and for review the git-context and diff files; for delegate these are collected in step 6). Convert each to its own --append-system-prompt <path> pair, collected in an array. Do NOT accumulate into a space-joined string and expand unquoted — under zsh that expansion is a single argument, so pi receives the literal string --append-system-prompt /path/CLAUDE.md as one token and appends it as text instead of reading the file:
    APPENDS=()
    for p in "${APPEND_PATHS[@]}"; do
      [ -n "$p" ] && APPENDS+=(--append-system-prompt "$p")
    done
    
  9. Assemble the command in an array, then run it. Arrays keep every flag a distinct argument regardless of shell (zsh does not word-split unquoted variables):
    CMD=(pi -p)
    # Provider: use the caller's resolved PROVIDER; else if a custom BASE_URL is set,
    # use the models.json key (PROVIDER_KEY, default openai) so pi reaches the endpoint.
    # Explicit if/elif — NOT `A && B || C && D` (left-associative parsing appends an
    # empty --provider when PROVIDER is set but BASE_URL is empty).
    if [ -n "$PROVIDER" ]; then
      CMD+=(--provider "$PROVIDER")
    elif [ -n "$BASE_URL" ]; then
      CMD+=(--provider "$PROVIDER_KEY")
    fi
    [ -n "$MODEL" ] && CMD+=(--model "$MODEL")
    [ -n "$API_KEY" ] && CMD+=(--api-key "$API_KEY")
    CMD+=(--thinking "${THINKING:-max}")
    [ -n "$TOOLS" ] && CMD+=(--tools "$TOOLS")
    [ -n "$EXCLUDE_TOOLS" ] && CMD+=(--exclude-tools "$EXCLUDE_TOOLS")
    CMD+=(--no-session --no-context-files --approve)
    # Default clean mode: do not load ~/.pi packages, extensions, or skills.
    # Opt in only when the caller sets WITH_PACKAGES=true (--with-packages / withPackages).
    if [ "$WITH_PACKAGES" != "true" ]; then
      CMD+=(--no-extensions --no-skills)
    fi
    CMD+=("${APPENDS[@]}")
    CMD+=("${FILE_REFS[@]}")   # review-only: @file references as separate args
    CMD+=("$TASK")
    
  10. Run in the background via Bash with run_in_background — PI_CODING_AGENT_DIR="$AGENT_DIR" "${CMD[@]}" </dev/null. CRITICAL: always redirect stdin from /dev/null — pi -p (print mode) mis-detects a terminal/pipe stdin as interactive and waits for input, hanging indefinitely. With </dev/null pi runs non-interactively to completion. Do NOT add a shell timeout — pi tasks run to completion. Do NOT use Monitor — pi is a single-shot command, not an event stream.
  11. Wait for completion, then verify:
  • delegate: run git diff --stat and enumerate modified files — this is pi's real output, which is file edits, not stdout.
  • review: read the background task output — stdout IS the review text.
  • doctor: the connectivity probe output IS the result (see step 7).
  1. Clean up temp files — remove any CLEANUP_FILES the caller listed (including the git-context temp file this agent created for delegate mode).
  2. Report per the Output Format below.

Read the full file on GitHub · 168 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 22d ago First seen · 168 lines · 224 tokens per session scan A fc9a0176d4dd

Subscribe to this mod's changes

pi-agent is an agent published in the GitHub repository FradSer/dotclaude (593 stars, last pushed 7d ago), licensed MIT. It adds 224 tokens to every session and 3,986 once invoked, about $0.0009 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-24.

Related

Other agents, from other repositories

cpp-reviewer

Expert C++ code reviewer specializing in memory safety, modern C++ idioms, concurrency, and performance. Use for all C++ code changes. MUST BE USED for C++ projects.

affaan-m/ECC · 41 tokens

thermo-nuclear-code-quality-review-subagent

Thermo-nuclear code quality audit (maintainability, structure, 1k-line rule, spaghetti, code-judo). Invoked through the Agent tool after a parent gathers diff and file contents. Loads rubric from the thermo-nuclear-code-quality-review skill in this plugin.

michael-denyer/pstack-claude · 68 tokens

karimo-implementer

Executes coding tasks (complexity 1-4) from KARIMO PRDs. Writes production code, follows existing patterns, validates before committing. Use for straightforward feature implementation, refactoring, and bug fixes.

opensesh/KARIMO · 49 tokens

reviewer

Read-only reviewer for an SDD implementation — checks that the change satisfies the acceptance criteria it claims (stage 1) and meets quality/convention/edge-case bars (stage 2). Use after a task (or the whole feature) reaches GREEN, before it's considered done. It reads the diff and the upstream artifacts and reports…

genkovich/sdd · 81 tokens

atomic-auditor

Final gate for a finished implementation. Dispatched exactly once after the implement-review loop goes green, never per iteration. Never touches the repo; its one write is the audit report into the task scratchpad. Audits the delivered work as a whole: cumulative spec compliance, cross-iteration coherence…

damusix/atomic-claude · 169 tokens

Reviewer

Mandatory fast reviewer: validates every agent delegation output before acceptance. Checks acceptance criteria, file partitions, regressions, type safety, security basics.

monkilabs/opencastle · 30 tokens