Skip to content
Agentmart
Submit a tool

pi-coding-agent

Operate the Pi coding agent CLI — install, extensions, Jev.

Skill by lukemcqueen

IndexedMIT★ 4
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/lukemcqueen-pi-coding-agent

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Operate the Pi coding agent CLI — install, extensions, Jev.

Use cases: agent-building

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Node.js package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/pi-coding-agent

What's inside

Skill name
pi-coding-agent
Description
Operate the Pi coding agent CLI — install, extensions, Jev.
License
MIT
Instructions
683 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts
  • Instructions call the network

Agent Skills spec issues

  • body: 683 lines (spec recommends under 500)

Files (3)

  • SKILL.md
  • extension-tool-api.md · references/
  • pi-skills-diagnostics.mjs · scripts/

SKILL.md (first lines)

# Pi Coding Agent

The coding-agent harness the fleet owner wants for steadfaste (replacing hermes).
`@earendil-works/pi-coding-agent` — a MANAGED install, not an npm global (see
Install below). The reference for pi + Jev
integration is `github.com/disler/ten-levels-of-jev` (30 tested Jev use cases in
10 levels; levels 6–10 put Jev inside pi).

## Install — a MANAGED install, NOT an npm global (corrected 2026-10-02)

Pi installs itself into its own agent directory and pins each release; there is no
`npm install -g`. Measured on a live host:

    ~/.pi/agent/bin/pi                        launcher (sh): reads the version, execs the release
    ~/.pi/agent/install/current-version       the authoritative version string (1.0.0 here)
    ~/.pi/agent/install/managed-install.json  {kind: pi-managed-install, layout: releases-v1,
                                               entrypoint: symlink -> <user bin dir>/pi}
    ~/.pi/agent/install/releases/<v>/node_modules/.bin/pi    the real executable
    ~/.local/share/pi-node/current/bin        Node.js that PI installs and manages

Consequences that cost time and must not be re-learned:

- **`command -v pi` is NOT a reliable probe.** The entrypoint is a symlink into the
  user's bin dir (a linuxbrew `bin/` on one measured host). When that
  dir is not on PATH, `pi` looks *missing* to every caller while being installed and
  working. Invoke the launcher directly — `~/.pi/agent/bin/pi` — or read
  `~/.pi/agent/install/current-version` without executing anything.
- **Pi's Node is deliberately NOT on shell profiles.** The launcher puts
  `~/.local/share/pi-node/current/bin` on PATH for itself and its children, so `node`
  and `npm` resolve correctly inside pi and nowhere else. Do not "fix" that by
  exporting it globally.
- **Extension type defs live in the release, not an npm root:**
  `V=$(cat ~/.pi/agent/install/current-version)` then
  `$HOME/.pi/agent/install/releases/$V/node_modules/@earendil-works/pi-coding-agent/dist/...`
- **Never infer the version from a doc or a package name** — read `current-version`
  (or the launcher's `--version`). A harness registry claiming a shipped version can
  be stale on any given host — MEASURE it: one host read 1.2.0 (with both 1.1.0 and
  1.2.0 present under `releases/`) while the registry's own `why:` prose still
  described 1.0.0. Read the type defs from the release you just measured, never from
  the prose about it.
- Verify: `~/.pi/agent/bin/pi --version` and `--help` (read/bash/edit/write tools, plus
  the `pi install/remove/list/config/auth` extension commands).

## Core
- Built-in tools: read, bash, edit, write.
- `pi install <source>` / `pi remove <source>` manage extension sources;
  `pi list` shows installed extensions.
- An extension is loaded as `pi -e extensions/<name>.ts --tools read,bash,edit,write[,<jev tools>]`
  — the `--tools` allowlist is explicit; only listed tools are available.

## stdout shape non-interactive — MEASURED, do not guess

A non-interactive pi turn writes EXACTLY the assistant's final answer to stdout and
nothing else — verified with a plain prompt and with a prompt that used the bash tool:

    $ ~/.pi/agent/bin/pi --model <m> "List three fruits, one per line, numbered 1. 2. 3."
     1. Apple
     2. Banana
     3. Cherry

- **Chatter goes to stderr and pi's own log, never to stdout.** So a wrapper that uses
  stdout verbatim is CORRECT, and one that takes "the last line" only TRUNCATES every
  multi-line answer down to its final line — a reply that arrives but is not complete.
  Verify stdout and stderr separately before choosing any output-shaping mode.
- **A fresh `--session-id` prints a benign stderr warning** — `Warning: No project session
  found with id '<id>'; creating a new session with that id.` — and still exits 0. That is
  how a per-chat session gets created, not a failure to report.
- **Call the launcher by absolute path from a service or wrapper.** `~/.pi/agent/bin/pi` is
  the launcher; the `pi` symlink in a user bin dir is not on a service PATH. Wrappers pass
  an ARGV LIST rather than a shell line, so nothing expands `~`/`$HOME` — a relative or
  guessed path becomes a silent per-message no-op. Pin the session identity too (e.g. a
  `CORTEX_SESSION_KEY`): a harness started outside a git repo cannot derive repo/branch and
  every chat otherwise collapses onto ONE session.

## Driving pi from another process — control calls go over RPC, never a prompt

A wrapper that only sends prompts is missing half the interface, and the missing half
fails in ways that read as pi being broken (working adapter to copy:
`ops/scripts/cortex_gateway/pi_control.py` in hermes-cortex).

- **A built-in slash command sent as a prompt is a NO-OP.** `/compact`, `/model`,
  `/new`, `/restart`, `/settings` are handled only in the interactive/RPC surfaces; as a
  prompt they become conversation (a forwarded `/new` is answered as prose while every
  bit of context stays). Session and state operations go over **RPC mode**:
  `pi --mode rpc` takes one JSON record per line on stdin (`{"type":"get_state"}`,
  `{"type":"compact"}`, `{"type":"set_model", …}`) and answers with a `response`
  record on stdout — correlate by the `id` you sent, never by response order.
- **Pass `--no-mcp` for a control call.** pi connects its MCP servers at RPC startup,
  and with them enabled the control call sat ALIVE and SILENT (no stdout, no stderr)
  for the whole deadline on ~40% of runs; the same call answered 8/8 in ~1.2 s with
  `--no-mcp`. A control call uses no MCP tool, so those servers are pure risk there.
- **Watch the process EXIT as well as EOF.** EOF is not the only end of an answer:
  pi's MCP children inherit its stdio, so a lingering grandchild holds the write end of
  the pipe open — no data, no EOF — and a reader waiting only for EOF blocks for its
  full deadline. Start pi in its own process group (`start_new_session=True`) and kill
  the GROUP on timeout, so a wedged control call does not also leak children.
- **`compact` never answers for a session whose transcript does not exist yet**
  (45 s+, repeated), while `get_state` on the same id answers in ~1.2 s and creates it.
  Ask for the state first and answer "no conversation yet" — a chat that has just
  started a fresh session is exactly this case, and it is the common one.
- **Give a check three outcomes, not two**: `0` ok · `1` a NEGATIVE answer · `3` could
  not verify. `--offline --list-models <pattern>` prints `No models matching "x"` and
  still **exits 0**, so a verdict read off the exit code is wrong in both directions —
  decide from the OUTPUT, and make "pi cannot be run at all" its own outcome rather
  than a failed check. The same split lets a caller refuse a bad model name instead of
  breaking every later turn with it.

## Extension API (the Jev-hook surface)

**Read the installed type defs before writing a hook — never infer the signature.**
```bash
V=$(cat ~/.pi/agent/install/current-version)
P="$HOME/.pi/agent/install/releases/$V/node_modules/@earendil-works/pi-coding-agent"
sed -n '1,60p' "$P"/dist/core/extensions/types.d.ts   # + grep the event interfaces
grep -n -A20 'registerTool' "$P"/dist/core/extensions/types.d.ts        # the tool registration contract
grep -n -A8  'interface ToolDefinition' "$P"/dist/core/extensions/types.d.ts
# AgentToolResult is NOT in this package — it comes from the agent core:
grep -rn -A12 'interface AgentToolResult' "$P"/../pi-agent-core/dist/types.d.ts
```

From lukemcqueen/hermes-cortex, MIT.

More from lukemcqueen/hermes-cortex

Signals

Stars
4
Forks
1
Open issues
1
Last commit (this folder)
Oct 22, 2026 (6 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from lukemcqueen

Cite this page

pi-coding-agent skill. Agent Mart. https://agentmart.dev/skills/lukemcqueen-pi-coding-agent (last updated 2026-10-24)