Running pi-config in Docker
Run pi inside an isolated Docker container so the agent can only access your project directory and pi settings — nothing else on your host. This guide walks you through pulling the image, configuring mounts and environment variables, and customizing tool access for your workflow.
Prerequisites
- Docker installed and running on your host
- A project directory you want pi to work in
- API credentials for your LLM provider (Vertex AI, Gemini, etc.)
Quick start
docker pull ghcr.io/myk-org/pi-config:latest
docker run --rm -it \
--name "pi-config-$(basename $PWD)-$(date +%s)" \
--network host \
-v "$PWD":"$PWD":rw \
-v "$HOME/.pi":"$HOME/.pi":rw \
-v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
-v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
-v "$HOME/.ssh":"$HOME/.ssh":ro \
-v "$HOME/.config/gh":"$HOME/.config/gh":ro \
-v /tmp/pi-work:/tmp/pi-work:rw \
-w "$PWD" \
ghcr.io/myk-org/pi-config:latest
This starts an interactive pi session in your current project directory. The container is destroyed when you exit (--rm).
Setting up the environment file
Create a .env file (e.g., ~/.pi/.env) with your credentials and preferences:
# Timezone (for correct timestamps in logs and sessions)
TZ=America/New_York
# Host username — maps /home/<user> paths between host and container
PI_HOST_USER=youruser
# Google Cloud / Vertex AI
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-east5
GOOGLE_APPLICATION_CREDENTIALS=/home/youruser/.config/gcloud/application_default_credentials.json
VERTEX_PROJECT_ID=your-project-id
VERTEX_REGION=us-east5
VERTEX_CLAUDE_1M=true
# GitHub
GITHUB_TOKEN=ghp_xxx
GITHUB_API_TOKEN=ghp_xxx
GH_CONFIG_DIR=/home/youruser/.config/gh
# Gemini (optional)
GEMINI_API_KEY=xxx
# MCP Launchpad config (must match mount target path)
MCPL_CONFIG_FILES=/home/youruser/.config/mcpl/mcp.json
Warning: Paths in the environment file (like
GOOGLE_APPLICATION_CREDENTIALSandGH_CONFIG_DIR) must use your container home path (/home/<PI_HOST_USER>/...), not the host path. ThePI_HOST_USERsymlink mechanism makes this work.
Pass the file when starting the container:
docker run --rm -it \
--name "pi-config-$(basename $PWD)-$(date +%s)" \
--network host \
--env-file "$HOME/.pi/.env" \
-v "$PWD":"$PWD":rw \
-v "$HOME/.pi":"$HOME/.pi":rw \
-v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
-v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
-v "$HOME/.ssh":"$HOME/.ssh":ro \
-v "$HOME/.config/gh":"$HOME/.config/gh":ro \
-v /tmp/pi-work:/tmp/pi-work:rw \
-w "$PWD" \
ghcr.io/myk-org/pi-config:latest
Understanding the volume mounts
Every mount serves a specific purpose. Here's what each one does:
| Mount | Mode | Purpose |
|---|---|---|
$PWD:$PWD |
rw | Your project directory — the only writable workspace |
$HOME/.pi:$HOME/.pi |
rw | Pi settings, sessions, memory, and installed packages |
$HOME/.gitconfig:$HOME/.gitconfig |
ro | Git configuration (user name, email, aliases) |
$HOME/.gitignore-global:$HOME/.gitignore-global |
ro | Global gitignore patterns |
$HOME/.ssh:$HOME/.ssh |
ro | SSH keys for git operations |
$HOME/.config/gh:$HOME/.config/gh |
ro | GitHub CLI authentication |
/tmp/pi-work:/tmp/pi-work |
rw | Temp files that persist across container restarts |
Note: Read-only (
:ro) mounts prevent the agent from modifying your host configuration. The container automatically copies.gitconfigto a writable location internally so git operations still work.
How PI_HOST_USER works
When your host username isn't node (the container's default user), mounted paths like $HOME/.ssh resolve to /home/youruser/.ssh — but the container's home is /home/node. Setting PI_HOST_USER fixes this by creating symlinks between /home/youruser and /home/node so all paths resolve correctly.
Set it to your host username:
PI_HOST_USER=youruser
If you skip this variable, mounts that use $HOME expansion may not resolve inside the container.
Creating a shell alias
Add this to your ~/.bashrc or ~/.zshrc to start pi from any project directory with a single command:
alias pi-docker='docker pull ghcr.io/myk-org/pi-config:latest && \
docker run --rm -it \
--name "pi-config-$(basename $PWD)-$(date +%s)" \
--network host \
--env-file "$HOME/.pi/.env" \
-v "$PWD":"$PWD":rw \
-v "$HOME/.pi":"$HOME/.pi":rw \
-v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
-v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
-v "$HOME/.ssh":"$HOME/.ssh":ro \
-v "$HOME/.config/gh":"$HOME/.config/gh":ro \
-v /tmp/pi-work:/tmp/pi-work:rw \
-w "$PWD" \
ghcr.io/myk-org/pi-config:latest'
Then run from any project:
cd ~/projects/my-app
pi-docker
Tip: The alias pulls the latest image on every run. If you prefer faster startup, remove the
docker pullline and update manually withdocker pull ghcr.io/myk-org/pi-config:latest.
Filesystem isolation
The container enforces strict filesystem boundaries:
- Accessible (read-write): Your project directory (
$PWD) and pi settings (~/.pi) - Accessible (read-only): Git, GitHub, and SSH configuration
- Blocked: All other host directories, other git repos, system files
This means the agent cannot accidentally modify files outside your project or access sensitive data on your host.
Network mode
The --network host flag shares your host's network stack with the container. This is required for:
- Local MCP servers
- LiteLLM proxy
- File preview (agents serve generated HTML via HTTP)
- Pidash and Pidiff dashboards
If you only use cloud-based LLM providers and don't need any of the above, you can omit --network host.
Advanced Usage
Optional mounts
Add these mounts to enable additional features:
| Mount | Mode | Purpose |
|---|---|---|
$HOME/.config/gcloud/application_default_credentials.json:$HOME/.config/gcloud/application_default_credentials.json |
ro | Google Cloud ADC for Claude via Vertex AI |
$HOME/.config/mcpl/mcp.json:$HOME/.config/mcpl/mcp.json |
ro | MCP server configuration for mcpl |
$HOME/.agents:$HOME/.agents |
rw | User-level skills |
$HOME/.config/cursor/auth.json:$HOME/.config/cursor/auth.json |
ro | Cursor CLI auth for acpx cursor models |
$HOME/.config/glab-cli:$HOME/.config/glab-cli |
ro | GitLab CLI config |
$HOME/screenshots:$HOME/screenshots |
ro | Share screenshots with the agent |
/var/run/docker.sock:/var/run/docker.sock |
ro | Docker container inspection via docker-safe |
/var/run/podman/podman.sock:/var/run/podman/podman.sock |
ro | Podman container inspection via docker-safe |
Docker socket access
To let the agent inspect running containers (read-only), mount the Docker socket and add the Docker group:
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--group-add $(stat -c '%g' /var/run/docker.sock)
The agent uses a restricted docker-safe wrapper that only allows read-only commands: ps, logs, inspect, top, stats, port, diff, images, version, and info. All state-modifying commands (exec, run, rm, build, etc.) are blocked.
For Podman, mount the Podman socket instead:
-v /var/run/podman/podman.sock:/var/run/podman/podman.sock:ro
External agent providers (acpx)
To route prompts through external AI agents like Cursor or Gemini, set the ACPX_AGENTS variable in your .env file:
ACPX_AGENTS=cursor
You'll also need to mount the corresponding auth file. For Cursor:
-v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro
Dashboard ports
Two web dashboards run alongside your pi session:
| Dashboard | Default Port | Environment Variable | URL |
|---|---|---|---|
| Pidash | 19190 | PI_PIDASH_PORT |
http://localhost:19190 |
| Pidiff | 19290 | PI_PIDIFF_PORT |
http://localhost:19290 |
To use custom ports, add to your .env file:
PI_PIDASH_PORT=9999
PI_PIDIFF_PORT=9998
To disable either dashboard:
PI_PIDASH_ENABLE=false
PI_PIDIFF_ENABLE=false
Passing arguments to pi
Any arguments after the image name are forwarded to pi:
# Run a specific task non-interactively
docker run --rm -it ... ghcr.io/myk-org/pi-config:latest /implement add retry logic
# Start with a specific prompt
docker run --rm -it ... ghcr.io/myk-org/pi-config:latest "fix the failing tests"
Building from source
Note: The image is built for linux/amd64 only. On ARM hosts, build with
--platform linux/amd64.
git clone https://github.com/myk-org/pi-config.git
cd pi-config
docker build -t ghcr.io/myk-org/pi-config:latest .
Complete alias with all optional mounts
Here's a full alias including all optional mounts for a complete setup:
alias pi-docker='docker pull ghcr.io/myk-org/pi-config:latest && \
docker run --rm -it \
--name "pi-config-$(basename $PWD)-$(date +%s)" \
--network host \
--env-file "$HOME/.pi/.env" \
-v "$PWD":"$PWD":rw \
-v "$HOME/.pi":"$HOME/.pi":rw \
-v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
-v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
-v "$HOME/.ssh":"$HOME/.ssh":ro \
-v "$HOME/.config/gh":"$HOME/.config/gh":ro \
-v "$HOME/.config/mcpl/mcp.json":"$HOME/.config/mcpl/mcp.json":ro \
-v "$HOME/.agents":"$HOME/.agents":rw \
-v "$HOME/.config/gcloud/application_default_credentials.json":"$HOME/.config/gcloud/application_default_credentials.json":ro \
-v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro \
-v "$HOME/.config/glab-cli":"$HOME/.config/glab-cli":ro \
-v "$HOME/screenshots":"$HOME/screenshots":ro \
-v /tmp/pi-work:/tmp/pi-work:rw \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--group-add $(stat -c '%g' /var/run/docker.sock) \
-w "$PWD" \
ghcr.io/myk-org/pi-config:latest'
Pre-installed tools
The container image comes with all tools pre-installed:
| Tool | Purpose |
|---|---|
git, gh, glab |
Version control, GitHub CLI, GitLab CLI |
uv / uvx |
Python package management and execution |
go |
Go development |
node / npm |
JavaScript runtime |
kubectl / oc |
Kubernetes and OpenShift CLI |
mcpl |
MCP server access |
acpx |
Agent proxy for external AI models |
agent-browser |
Browser automation (Chromium pre-installed) |
docker-safe |
Read-only Docker/Podman inspection wrapper |
prek |
Pre-commit hook runner |
jq, curl |
JSON processing, HTTP requests |
Troubleshooting
Startup warning about cached packages
A WARNING on stderr during startup is normal when pi-config is already cached in ~/.pi. The container runs pi install and pi update on every start to stay current. If the warning persists or pi misbehaves, check your network connectivity.
Mounted paths don't resolve inside the container
Make sure PI_HOST_USER in your .env file matches your host username exactly. Without it, paths like /home/youruser/.ssh won't resolve because the container's default home is /home/node.
Permission denied on mounted files
The container runs as user node (UID 1000). If your host files are owned by a different UID, you may see permission errors. Ensure your host user's UID is 1000, or adjust file permissions accordingly.
Container can't reach local services
Make sure you included --network host in your docker run command. Without it, the container has its own network namespace and can't reach services on localhost.
Git push/pull hangs
The container sets SSH keepalive and connection timeouts automatically (15-second keepalive interval, 10-second connection timeout). If git operations still hang, check that your SSH keys are correctly mounted at $HOME/.ssh with :ro mode.