Installation Guide¶
This guide walks through installing Pynchy on macOS or Linux, for both desktop and headless server deployments.
Prerequisites¶
Required Software¶
- macOS or Linux (tested on macOS 14+ and Ubuntu 24.04)
- Python 3.13+
- uv - Python package manager
- Claude Code - AI development assistant
- Container runtime:
- macOS: Apple Container (preferred) or Docker Desktop
- Linux: Docker
System Dependencies¶
macOS:
brew install libmagic # Required by neonize (WhatsApp) for MIME detection
brew install container # Apple Container (recommended) — or install Docker Desktop
Linux (Debian/Ubuntu):
sudo apt-get install libmagic1 # Required by neonize (WhatsApp) for MIME detection
# Install Docker + BuildKit - https://docs.docker.com/engine/install/
sudo apt-get install docker-buildx # Required for container image builds
Linux (Fedora/RHEL):
sudo dnf install file-libs # Required by neonize (WhatsApp) for MIME detection
# Install Docker + BuildKit - https://docs.docker.com/engine/install/
sudo dnf install docker-buildx-plugin # Required for container image builds
Note: On macOS, if Apple Container is not installed, Pynchy automatically falls back to Docker.
Installation Steps¶
1. Clone and Install Dependencies¶
2. Configure¶
To customize configuration, copy the example and edit it:
Enable WhatsApp (requires optional dependency):
Common configurations:
- API key authentication: Set
[secrets].anthropic_api_keyinstead of Claude Code OAuth - OpenAI instead of Claude: Set
[agent] core = "openai"and[secrets].openai_api_key
Note: For most desktop setups, you can skip this step and authenticate using Claude Code OAuth (see step 4 in Headless Server Deployment).
LiteLLM Gateway (recommended)¶
Pynchy uses a LiteLLM proxy as the LLM gateway. This runs in a Docker container and handles model routing, load balancing, and credential isolation — containers never see real API keys.
To enable it, add these settings to your config.toml:
[gateway]
litellm_config = "litellm_config.yaml"
port = 4000
master_key = "your-master-key-here" # required — used for LiteLLM UI and API auth
# Optional: LiteLLM admin UI credentials
ui_username = "admin"
ui_password = "your-ui-password-here" # pragma: allowlist secret
Then configure your models and API keys in litellm_config.yaml (see config-examples/litellm_config.yaml.EXAMPLE for a starting point):
cp config-examples/litellm_config.yaml.EXAMPLE litellm_config.yaml
# Edit litellm_config.yaml with your model providers and API keys
Pynchy starts the LiteLLM container automatically on boot. The admin UI is available at http://localhost:4000/ui (login with the ui_username/ui_password you configured).
MCP Server Access (optional)¶
To give agents access to external MCP tool servers (e.g., Playwright for web browsing), add definitions to config.toml:
[mcp_servers.playwright]
type = "docker"
image = "mcp/playwright:latest"
args = ["--headless", "--port", "8931", "--host", "0.0.0.0"]
port = 8931
transport = "sse"
idle_timeout = 600
[workspaces.my-workspace]
mcp_servers = ["playwright"]
# Optional: per-workspace restrictions (passed as Docker flags)
[workspaces.my-workspace.mcp.playwright]
allowed-origins = "github.com;stackoverflow.com"
Docker MCP containers start on-demand and stop after idle_timeout. See MCP servers for configuration details.
3. Build Container Image¶
4. Authenticate WhatsApp¶
- Open WhatsApp on your phone
- Go to Settings > Linked Devices > Link a Device
- Scan the QR code displayed in the terminal
- Wait for "Successfully authenticated" before pressing Ctrl+C
5. Run Pynchy¶
On first run, Pynchy will:
- Create a private WhatsApp group for your admin channel (admin control)
- Set up local directories for group isolation
- Connect to WhatsApp and start listening for messages
Headless Server Deployment¶
Step-by-step guide to deploying Pynchy on a headless Linux server with systemd, accessible over Tailscale.
For macOS desktop setup, see the Installation Steps above.
Prerequisites¶
On the server:
- Ubuntu/Debian Linux (tested on Ubuntu 24.04)
- Tailscale connected to your tailnet
- Node.js 18+ (for installing Claude Code)
- A phone with WhatsApp (for QR code authentication)
On your local machine (for remote setup):
- SSH access to the server (Tailscale SSH or standard)
- GitHub CLI authenticated (
gh auth login)
1. Install Server Dependencies¶
SSH into your server and install the required packages:
# System packages
sudo apt-get update && sudo apt-get install -y docker.io docker-buildx sqlite3
sudo usermod -aG docker $USER
# Log out and back in, or use `sg docker -c "docker ps"` to test
# uv (Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env # or restart your shell
# GitHub CLI (for cloning private repos)
sudo apt-get install -y gh
# Node.js + npm (for installing Claude Code)
sudo apt-get install -y npm
2. Clone and Build¶
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
git clone [email protected]:crypdick/pynchy.git ~/src/pynchy
cd ~/src/pynchy
# Install Python dependencies
uv sync
# Build the agent container image
sg docker -c './container/build.sh'
3. Authenticate WhatsApp¶
This step requires scanning a QR code with your phone. The QR code renders as Unicode text and pipes cleanly over SSH.
- Open WhatsApp on your phone
- Go to Settings > Linked Devices > Link a Device
- Scan the QR code displayed in the terminal
Wait for "Successfully authenticated" before pressing Ctrl+C.
4. Authenticate Claude Code¶
Pynchy runs agents using the Claude Agent SDK, which requires Claude Code installed and authenticated. Pynchy auto-discovers credentials at startup — no manual config needed.
Pro/Max subscribers (recommended): Generate a long-lived token (~1 year):
- Run
claude setup-tokenon the server - It prints a URL — paste it into a browser (can be on any machine)
- Authorize in the browser and copy the code it gives you
- Paste the code back into the
setup-tokenprompt - Copy the long-lived token it outputs (starts with
sk-ant-oat01-...) - Create the credentials file on the server:
mkdir -p ~/.claude
cat > ~/.claude/.credentials.json << 'EOF'
{"claudeAiOauth": {"accessToken": "sk-ant-oat01-YOUR_TOKEN_HERE"}}
EOF
chmod 600 ~/.claude/.credentials.json
To route LLM requests through the LiteLLM gateway using this token, add it to .env as CLAUDE_OAUTH_TOKEN=sk-ant-oat01-YOUR_TOKEN_HERE and reference it in litellm_config.yaml (see config-examples/litellm_config.yaml.EXAMPLE for the OAuth entry). LiteLLM auto-detects the sk-ant-oat* prefix and handles auth headers.
API key (pay-as-you-go): Get a key from console.anthropic.com, then set it in config.toml:
cp ~/src/pynchy/config-examples/config.toml.EXAMPLE ~/src/pynchy/config.toml
# Set [secrets].anthropic_api_key in config.toml
Warning: Without credentials, Pynchy will start and connect to WhatsApp, but all messages to the agent will fail. The boot notification will warn you if credentials are missing.
5. First Run¶
On first run, Pynchy will:
- Create a private WhatsApp group for your admin channel
- Install a systemd user service (
~/.config/systemd/user/pynchy.service) - Enable the service for auto-start on boot
- Enable user lingering (so the service runs without an active login session)
Verify it's working, then press Ctrl+C.
6. Start as a Service¶
The first run already installed and enabled the systemd service. Start it now:
For a reference unit file template, see config-examples/pynchy.service.EXAMPLE.
Check status:
View logs:
The service auto-restarts on crashes (RestartSec=10) and starts on boot.
7. Connect the TUI (optional)¶
From any machine on your Tailscale network:
Replace your-server with the Tailscale hostname of your server (visible in tailscale status).
8. Daily Maintenance (recommended, Linux only)¶
Set up automatic security updates and a daily reboot to clear zombie processes and keep the server fresh. Pynchy auto-starts on boot.
Automatic security updates — unattended-upgrades is usually pre-installed on Ubuntu. Configure it to apply updates daily and reboot when kernel updates are pending:
sudo cp config-examples/20auto-upgrades.EXAMPLE /etc/apt/apt.conf.d/20auto-upgrades
sudo cp config-examples/50unattended-upgrades.EXAMPLE /etc/apt/apt.conf.d/50unattended-upgrades
Daily reboot + Docker cleanup — a systemd timer that prunes Docker resources older than 48 hours, then reboots the machine:
sudo cp config-examples/pynchy-maintenance.service /etc/systemd/system/
sudo cp config-examples/pynchy-maintenance.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now pynchy-maintenance.timer
The timer fires at 4 AM daily (with up to 5 minutes of randomized jitter). Verify with systemctl list-timers pynchy-maintenance*.
Note: Reference copies of all server configs are version controlled in
config-examples/. The live copies on the server are the source of truth.
9. Deploying Updates¶
After pushing changes to the repo, trigger a remote deploy:
This pulls the latest code, validates the import, and restarts the service. If the import fails, Pynchy automatically rolls back.
Troubleshooting¶
"No API credentials found" in boot message¶
Run claude setup-token on the server to generate a long-lived token, or set [secrets].anthropic_api_key in config.toml. Then restart: systemctl --user restart pynchy
OAuth token expired (401 authentication_error)¶
Short-lived OAuth tokens from claude login expire every ~8 hours. Generate a long-lived token (~1 year) instead — follow the claude setup-token steps in section 4, then restart:
WhatsApp QR code not scanning¶
- Ensure your phone and server can reach each other over the network (or use SSH tunneling)
- The QR code renders as Unicode text in the terminal — scan it directly from the SSH session
- If the QR code doesn't render properly, try a different terminal emulator
Container build fails¶
macOS:
- Ensure Apple Container or Docker is running
- Check that you have the latest version:
brew upgrade containeror update Docker Desktop
Linux:
- Ensure Docker is running:
sudo systemctl start docker - Verify you're in the docker group:
groups | grep docker - If not, run
sudo usermod -aG docker $USERand log out/in - "BuildKit is enabled but the buildx component is missing": Install the buildx plugin:
sudo apt-get install docker-buildx(Debian/Ubuntu) orsudo dnf install docker-buildx-plugin(Fedora/RHEL). BuildKit is required for container builds.
Then rebuild: ./container/build.sh
Port 8484 not reachable over Tailscale¶
- Verify Tailscale is connected:
tailscale status - The HTTP server binds to
0.0.0.0:8484by default, which is accessible over Tailscale without any additional configuration - Check firewall rules if on a cloud provider
Service won't start after reboot¶
Check that lingering is enabled: loginctl show-user $USER | grep Linger. If not, run sudo loginctl enable-linger $USER.
WhatsApp disconnects¶
WhatsApp linked devices expire after ~30 days of inactivity. Re-run uv run pynchy-whatsapp-auth to re-authenticate, then restart the service.
First run doesn't create systemd service¶
On first run, the systemd service is only created if you start Pynchy without the --tui flag. Run uv run pynchy (not uv run pynchy --tui) for the initial setup.
Next Steps¶
After installation:
- Send a test message - Message yourself in WhatsApp with
@Pynchy helloto verify it's working - Read the docs - Understand the philosophy at index.md and architecture at architecture/
- Customize - Tell Pynchy to add channels, integrations, or change behavior directly in the codebase
- Set up scheduled tasks - Ask Pynchy to run recurring tasks:
@Pynchy send me a summary of Hacker News every morning at 9am
For development and testing workflow, see .claude/skills/pynchy-dev/SKILL.md in the repository.