pi (earendil-works) is a minimal, extensible terminal agent harness. It speaks the same agentskills.io skill format we use, carries personas as prompt templates, and runs local or hosted models — so for fully-local, privacy-preserving operation, point it at your own endpoint (step 2).
One caveat up front: pi intentionally ships no built-in MCP support. Our
value is the MCP servers, so we bridge them with the production-ready
pi-mcp-extension (step 3). No bridge
code is shipped from this repo — you install and configure the extension.
Prerequisite: finish getting started.
Install pi per its quickstart.
Add a local OpenAI-compatible provider in ~/.pi/agent/models.json:
{
"providers": {
"f0-local": {
"baseUrl": "http://localhost:8000/v1",
"api": "openai-completions",
"apiKey": "$OPENAI_API_KEY",
"models": [
{ "id": "your-model-name" }
]
}
}
}baseUrl— your local endpoint: vLLM (:8000), llama.cpp /llama-server(:8080by default — use whatever port your server listens on), or Ollama (http://localhost:11434/v1).api—"openai-completions"works for all of the above.apiKey— a literal,"$ENV_VAR", or"!command". Local servers (Ollama, llama.cpp, vLLM) accept any token; a dummy like"sk-local"or an env var is fine.id— the model id your endpoint reports atGET <baseUrl>/models(e.g.Qwen3.5-9Bfor a llama.cpp--alias, or the Ollama tag likeqwen3.5:latest).
Select the model with /model (the file reloads without a restart).
Install the MCP client extension:
pi install npm:pi-mcp-extensionThen declare our servers in ~/.pi/agent/mcp.json (or project-level
.pi/mcp.json). A ready copy lives at
integrations/pi/mcp.json — copy it and
replace the placeholder path with your checkout:
{
"settings": { "toolPrefix": "mcp", "requestTimeoutMs": 30000, "maxRetries": 5 },
"mcpServers": {
"f0-defender": {
"command": "uv",
"args": ["run", "--directory", "/ABSOLUTE/PATH/TO/sec-tools", "f0-defender-mcp"],
"transport": "stdio",
"lifecycle": "eager"
}
}
}(The shipped file wires all seven servers, including f0-pa-actions — the
gated-write ProjectAchilles companion, whose write tools stay inert without
PROJECTACHILLES_ALLOW_WRITE=true and a per-action confirmation token.)
Prefer the sync script over hand-copying. From the repo root:
uv run python scripts/sync_pi_config.pyIt renders the template into ~/.pi/agent/mcp.json (placeholder path → your
checkout, uv → its absolute path) and symlinks ~/.pi/agent/AGENTS.md to the
repo copy (making step 4 automatic). It is idempotent — re-run it after every
git pull so new servers appear in pi without manual edits, or make it
automatic with a local git hook:
echo 'uv run python scripts/sync_pi_config.py' >> .git/hooks/post-merge
chmod +x .git/hooks/post-mergeSkills and persona prompts never need syncing: step 5 points pi at the repo's
skills/ and integrations/pi/prompts/ directories in place, so they always
track your checkout. CI enforces the template itself can't drift from the
server list (integrations/test_integrations_valid.py).
lifecycle: "eager"connects the server at session start, so its tools are visible to the model immediately. With"lazy"(the extension's default) the server stays disconnected — and its tools stay hidden — until you run/mcp:start <name>, so the model can't call them. Useeagerfor servers you want the model to drive. Eager does spawn all six at startup (a few seconds); set rarely-used servers tolazyand/mcp:startthem on demand if you prefer.command— if pi can't finduvon the spawned process'sPATH, use its absolute path (fromwhich uv, e.g./home/you/.local/bin/uv).- No credentials here. Each server loads its own
.env.<platform>from the repo root — secrets never entermcp.json. - Bridged tools appear as
mcp_f0_<server>_<tool>—pi-mcp-extensionsanitizes the-in the server name to_, so e.g.mcp_f0_defender_list_incidents(underscores, unlike Hermes'mcp_f0-defender_…). Skills still work unchanged because they reference tools by base name (list_incidents), which the model maps via the descriptions. - Check server status anytime with
/mcp(or/mcp <name>for its stderr log).
pi has no SOUL.md; it auto-loads AGENTS.md context files. If you ran
scripts/sync_pi_config.py in step 3 this is already a symlink and you can
skip ahead. Manual alternative:
ln -s "$(pwd)/integrations/pi/AGENTS.md" ~/.pi/agent/AGENTS.mdIt carries the same read-only / never-fabricate principles as the Hermes
SOUL.md. (For a full system-prompt replacement instead, use .pi/SYSTEM.md.)
Load our skills unmodified by adding the directory to ~/.pi/agent/settings.json:
{
"skills": [
"/ABSOLUTE/PATH/TO/sec-tools/skills",
"-/ABSOLUTE/PATH/TO/sec-tools/skills/README.md"
]
}They're the same agentskills.io SKILL.md packages Hermes uses. pi loads names
and descriptions at startup and reads the full skill on demand; invoke one
explicitly with /skill:name, or pass --no-skills to disable discovery.
pi also scans root-level
.mdfiles in the skills dir as skill candidates, so it flagsskills/README.mdat startup (description is required). It's harmless — the 20 real skills still load — and the-…/skills/README.mdforce-exclude above silences it.
pi carries personas as prompt templates — one .md per lens, invoked as a
slash command. Point pi at ours in settings.json:
{ "prompts": ["/ABSOLUTE/PATH/TO/sec-tools/integrations/pi/prompts"] }This registers /ciso, /threat-hunter, /detection-engineer, and
/security-engineer — the same four lenses as Hermes, over the base AGENTS.md
identity. Invoke a lens with your request as its argument, e.g.
/ciso give me a posture summary.
Note the difference from Hermes: a pi prompt template is sent as a turn, not a
persistent overlay like Hermes' /personality. So /ciso on its own just adopts
the lens and asks what you need (it won't act until you give it a request), and
you re-invoke the lens on later turns to keep it.
/ciso give me a security posture summary
# → defender-posture-summary skill → mcp_f0_defender_get_secure_score +
# mcp_f0_defender_list_incidents, framed for an executive.
/threat-hunter hunt for PowerShell downloads today
# → defender-threat-hunt skill → mcp_f0_defender_run_hunting_query (KQL, bounded).
- Everything is read-only; no gated write actions are exposed.
- The
skills/are the same files Hermes and Claude Code use — no pi-specific copies. - pi extensions run with full permissions — install
pi-mcp-extensiononly from the trusted source linked above. - Wiring for this runtime lives in
integrations/pi/(mcp.json,AGENTS.md, and the four persona prompt templates).