My personal setup to run the pi coding agent inside a Podman container, together with the extensions, skills, and system prompt rules I use every day.
This repo is shared as inspiration, not as a ready-to-use product. Paths, providers, and rules fit my machine and my workflow. Take what is useful and adapt it.
Branches: main contains the containerization. flutter builds on it and adds Flutter / Dart tooling.
| Part | Purpose |
|---|---|
pi |
Host launcher, deliberately without .sh: symlinked as pi, it feels like a native install. Mounts the current directory (or, after a prompt, the enclosing git repo) and starts the container. Mount rules are in the script comments. |
Dockerfile, compose.yaml |
Image: Node LTS, pi, and the assets of this repo. |
entrypoint.sh |
Runs on every container start: copies the assets into the persistent volume, installs / updates pi packages, sets env vars (Tavily key, my local llama.cpp server). |
APPEND_SYSTEM.md |
My rules, appended to the pi system prompt. |
keybindings.json |
Enter = new line, Alt+Enter = submit. |
web-search.json |
Provider routing for pi-web-access: Tavily first, Exa as fallback. |
docs/ |
Specs: container behavior, UI extension constraints. |
ui-extension.ts: replaces editor and footer with one bordered box (model, git branch, token / cost / context stats).cost-tracker.ts: records the cost of each message;/costshows the totals.prompt-duration.ts: measures the duration of each prompt.tokstats/:/tokstatsshows tok/s and token totals per model.load-files/:/load-files <@paths...>puts full file contents into the context.answer-plan/:/answerasks the questions of the lastplanturn one by one.lib/: shared helpers and tests. Not loaded as an extension.
ask/ask-with-project: Q&A without file changes.check-feasibility: checks a task and shows side effects before any edit.plan/implement-plan: interview, then TODOs in code plus a plan file, then implementation.lint: my Dart class conventions.ste100: explain or rewrite in ASD-STE100 Simplified Technical English.
- Create a symlink
/usr/local/bin/pithat points to this executablepi:ln -s /home/user/containerized-pi/pi /usr/local/bin/pi
- Make it executable
chmod +x /usr/local/bin/pi - Build the image:
podman compose build - Execute
pianywhere as if it were natively installed - Optional, web search: get an API key at tavily.com, start pi and store the key:
!! echo "api key" > /root/.pi/agent/tavily_api_key
- The agent sees only the mounted directory and the named volume
pi-agent-home(pi config, sessions, API keys). - The agent cannot push to a remote only because the container has no credentials (SSH keys, tokens). Nothing else prevents it.
- The container runs with
--network host. It shares the network stack of the host and can reach all services on the host'slocalhostand on the LAN. There is no network isolation. That's a bit lazy, but was necessary for debugging once and I just kept it.
- System prompt rules: edit
APPEND_SYSTEM.md, thenpodman compose build. The same applies to extensions, skills, and config files: they are part of the image and are copied into the volume on every start. - pi itself:
podman compose build --no-cache. - pi packages:
entrypoint.shinstalls / updates them on every start.