pi
pi’s user settings are managed by this repo: dotfiles/pi/.pi/agent/settings.json is
stowed to ~/.pi/agent/settings.json, so the default provider/model, theme, and the
packages list (extensions) are all reproducible. Sessions, auth, and installed
package artifacts stay local.
Footer
Section titled “Footer”The stowed statusline extension replaces pi’s stock footer with the status line
Claude Code and Grok show (see Claude Code): it sends
pi’s model, thinking level, context use, folder and branch to
~/.local/bin/agent-statusline. Status text from other extensions (the standby
badge, ponytail, MCP) shows on a second row. It does nothing in RPC mode, which is
how OpenRig runs pi seats.
Footer standby
Section titled “Footer standby”There is no built-in footer setting for “the captain is waiting on a crew.” When this pane is
idle and another named Herdr agent is working or blocked, the stowed
standby-status extension writes standby · <crew> into the footer. No badge
means this session is idle and no sibling crew is running.
The badge is display only. On the captain pane (FIRSTMATE_ROLE=captain, or label
firstmate:coordinator / firstmate:launcher) a sibling going working/blocked
to idle/done, or newly blocked, also calls pi.sendUserMessage (as a follow-up
if this session is streaming) and herdr notification show --sound done. The first
poll seeds state and does not fire.
/standby prints the same state. /reload after stow. Herdr pane titles still
show a check when idle and a spinner when that pane is working.
Home layout
Section titled “Home layout”~/.pi itself must be a real directory under $HOME. Do not replace it with a
symlink onto ~/work/store/pi (or any other volume). That breaks two things:
- Stow writes relative links for the theme and extensions. Those resolve from the
real path of
~/.pi, so a store symlink makesrose-pine-moondangle and pi falls back to the dark theme. - Pi package and session paths are resolved below the real agent directory. Moving only runtime-heavy children keeps those paths stable across machines.
make stow-install and make stow-pi run scripts/pi-home-layout.sh on Linux and
macOS. The script is idempotent: a fresh home gets a real ~/.pi, a wholesale
~/.pi symlink is unwrapped, and a second run is a no-op besides restow. It never
creates a runtime store. Nested npm / sessions / git links are added only when
the old symlink target already holds them, when $HOME/work/store/pi already has
that runtime, or when PI_STORE is set. On Linux, relocate-stores also moves only
those children onto the 970; it must not symlink the whole ~/.pi tree.
make stow-pi# or, with an explicit runtime store:PI_STORE="$HOME/work/store/pi" make stow-piInstall
Section titled “Install”make stow-pipi does not auto-install user-level packages on a fresh machine - the stowed
packages list declares them, but each artifact needs one pi install to download.
Re-running the installs is idempotent and keeps the settings entries unchanged:
pi install npm:pi-web-accesspi install npm:pi-mcp-adapterpi install npm:pi-langfuse# ...one per entry in the stowed "packages" listThe subagent extension is owned directly in
dotfiles/pi/.pi/agent/extensions/subagent/index.ts; no package install is needed.
Its four agent prompts live in dotfiles/pi/.pi/agent/agents/. It intentionally keeps
only fresh foreground runs, one call or up to four parallel tasks, and the
scout/worker/reviewer/oracle roles. Dependent stages are sequenced by the parent.
Run /reload after changing the extension or an agent prompt.
Structured MCP
Section titled “Structured MCP”Pi has no built-in MCP. The stowed package list includes npm:pi-mcp-adapter, which
bridges remote MCP servers into Pi as a single mcp proxy tool.
Structured (the daily planner) is configured in the stowed
dotfiles/pi/.pi/agent/mcp.json → ~/.pi/agent/mcp.json:
{ "mcpServers": { "Structured": { "url": "https://mcp.structured.app/mcp", "oauth": { "scope": "email", "clientName": "Pi" } } }}The same file holds every pi MCP server, so there is no separate mcp-adapter.json: also rex-community (the read-only Rex community MCP, signed in with the Rex Beta Discord account) and ticket. Each server signs in once per machine with mcp({ action: "auth-start", server: "<name>" }); tokens stay in ~/.pi/agent/mcp-auth.json, which is not tracked.
OAuth uses Structured Cloud (email OTP). Tokens live in the OS credential store,
not in this repo. scope must stay email - extra scopes fail on Structured’s
Supabase authorization server. No clientId is pinned: the adapter registers a
public client at auth time (DCR). Structured does not list Pi as a first-party
host; if DCR tokens are rejected, fall back to a documented client ID from
Structured’s MCP setup and set
oauth.redirectUri to that client’s exact callback.
Do not import Claude Code MCP wholesale (imports: ["claude-code"]). That host
file also carries secret-bearing servers.
After pi install npm:pi-mcp-adapter and a Pi restart:
/mcp-auth Structured/mcpmcp({ search: "timeline inbox task" })Recurring-task tools need Structured Pro. Logout with /mcp logout Structured.
Mac and Linux use the same files. After pulling main:
make stow-pipi install npm:pi-mcp-adapterRestart Pi, then /mcp-auth Structured. OAuth tokens live in the OS store, so a
working Mac login does not travel with git. Linux must sign in again.
On Linux the store is Secret Service (libsecret). If it is missing, or the
session keyring is locked, /mcp-auth fails closed with no plaintext fallback:
# Debian/Ubuntusudo apt install libsecret-1-0 gnome-keyring
# Fedorasudo dnf install libsecret gnome-keyringUnlock the keyring with a graphical login. Headless SSH/tmux sessions that inherited a revoked session keyring need a fresh login before auth will stick.
Langfuse tracing
Section titled “Langfuse tracing”Observability follows the official integration:
Trace Pi Agent with Langfuse.
The community pi-langfuse extension traces in-process: one trace per prompt, a root
agent observation, a generation per model request (tokens + cost), tool observations,
and trace-level scores. It also redacts common secrets and hashes local paths.
pi install npm:pi-langfuseCredentials
Section titled “Credentials”No config file is used - ~/.pi/agent/pi-langfuse/config.json would hold the keys in
plaintext, so credentials come from the environment instead. They live in ~/.envrc
(direnv, private, not in this repo):
export LANGFUSE_PUBLIC_KEY=pk-lf-...export LANGFUSE_SECRET_KEY=sk-lf-...export LANGFUSE_BASE_URL="https://us.cloud.langfuse.com" # must match the key's regionLaunch pi from a direnv-loaded shell and it prints
📊 Langfuse: Tracing enabled → https://us.cloud.langfuse.com at startup.
Resolution order (verified in the extension source): config.json wins, but only
when it contains both publicKey and secretKey - a partial file is ignored.
Otherwise env vars are used. Two consequences:
- Never run
/langfuse-setup- it writes the keys to~/.pi/agent/pi-langfuse/config.jsonin plaintext, and that file then takes precedence over the environment. Keeping creds env-only is what makes this setup trackable in dotfiles without exposing secrets. - The extension does not read
~/.envrcitself (direnv must have loaded it). pi launched outside a direnv shell (GUI app, launchd) runs untraced silently.
Capture policy
Section titled “Capture policy”Default preset is full-debug (full inputs/outputs/tool I/O). Restrict with
LANGFUSE_PRIVACY_PRESET (metadata-only, prompts-only, conversations) for
sensitive sessions, or fine-grained LANGFUSE_CAPTURE_* flags.
Verify
Section titled “Verify”# inside pi/langfuse-status # host, masked key, capture policy/langfuse-test # checks host + keys
# from the shell, via the Langfuse skill's CLIexport LANGFUSE_HOST="$LANGFUSE_BASE_URL"npx langfuse-cli api observations list --limit 5History
Section titled “History”Before pi-langfuse, pi was traced by a custom extension in the skills repo
(hooks/pi/langfuse-trace) that spawned the shared Python exporter on
agent_settled. That lane is retired for pi - the official extension is richer -
but the exporter still handles Claude Code and Codex, and its --agent pi adapter
remains for backfilling old sessions. Don’t register both for pi: every turn would
be traced twice.