Deployment Guide
Run Pathfinder anywhere — single container, full stack, or bare metal.
Docker (single container, bash-only)
The quickest Docker setup. No database needed — agents explore docs with shell commands only.
This mounts your config and local docs into the container. Agents get read-only access to your documentation via bash tools.
Docker Compose (full stack)
For semantic search, you need Postgres with pgvector. The production docker-compose.yml sets up everything:
Create a .env file with your secrets, then start:
Persistent volume required for workspaces
Without a persistent volume mounted at /data, agent workspaces are lost on every container restart. If you use workspaces, always mount a volume. The workspaces volume in the compose file above handles this.
Railway
Deploy to Railway with a Postgres plugin and persistent volume:
- Create a new project on Railway and add a PostgreSQL database (use the pgvector template if available).
- Add a new service from the Pathfinder GitHub repo or Docker image (
ghcr.io/copilotkit/pathfinder:latest). - Set environment variables:
DATABASE_URL(from Railway's Postgres),OPENAI_API_KEY,GITHUB_TOKEN(if needed). - Add a persistent volume mounted at
/datafor workspace storage. - Set
WORKSPACE_DIR=/data/workspacesin the service environment. - Deploy. The first boot auto-indexes your configured sources.
Generic VPS
Run Pathfinder directly on any Linux server with Node.js 20+.
systemd service
nginx reverse proxy
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | For search tools | - | PostgreSQL connection string (with pgvector) |
MCP_JWT_SECRET | Required in production | - | HMAC secret for signing OAuth access/refresh tokens. Generate with openssl rand -hex 32. Rotating this invalidates all issued tokens — clients will re-authenticate transparently. In any non-production environment (any NODE_ENV other than production) a random secret is generated per process and logged as a warning. |
OPENAI_API_KEY | When embedding.provider is "openai" (default) | - | OpenAI API key for computing embeddings. Not needed for ollama or local providers. |
GITHUB_TOKEN | For private repos | - | GitHub PAT for cloning private repositories |
GITHUB_WEBHOOK_SECRET | For webhooks | - | Secret for validating GitHub webhook payloads |
SLACK_BOT_TOKEN | When slack sources configured | - | Slack bot OAuth token (xoxb-...) |
SLACK_SIGNING_SECRET | When using emoji-trigger | - | For Slack webhook signature verification |
DISCORD_BOT_TOKEN | When discord sources configured | - | Discord bot token |
DISCORD_PUBLIC_KEY | When discord sources configured | - | For Discord webhook Ed25519 verification |
NOTION_TOKEN | When notion sources configured | - | Notion internal integration token |
PORT | No | 3001 | HTTP port the server listens on |
PATHFINDER_CONFIG | No | pathfinder.yaml | Path to the config file |
WORKSPACE_DIR | No | /tmp/pathfinder-workspaces | Directory for agent workspace storage |
NODE_ENV | No | development | Set to production for deployed instances |
LOG_LEVEL | No | info | Logging verbosity (debug, info, warn, error) |
CLONE_DIR | No | /tmp/mcp-repos | Directory for git repo clones |
ANALYTICS_TOKEN | For privileged surfaces | - | Shared admin-access bearer token for all privileged surfaces — analytics (/api/analytics/*), Atlas ratification (/api/atlas/*), and admin ops (/admin/*). See Admin control surface. |
MCP_JWT_SECRET must be set in production
MCP_JWT_SECRET MUST be set before NODE_ENV=production — the server will throw on startup if it's missing. See Authentication for how the OAuth flow uses this secret.
Optional dependencies
Some features require extra packages that are not bundled by default. Install only the ones your config needs:
| Package | When required | Install |
|---|---|---|
pdf-parse | Any source has type: document with *.pdf file patterns | npm install pdf-parse |
mammoth | Any source has type: document with *.docx file patterns | npm install mammoth |
@xenova/transformers | embedding.provider is local | npm install @xenova/transformers |
Run pathfinder validate to detect missing optional dependencies and get install instructions.
Health endpoint
Pathfinder exposes GET /health for monitoring. It returns JSON with uptime, indexing status, chunk counts per source, and index state (last indexed time, commit SHA, errors). Use it for load balancer health checks and deployment verification.
Webhook URLs
GitHub: Set your GitHub webhook's Payload URL to https://your-domain/webhooks/github.
Slack: Set your Slack app's Event Subscriptions Request URL to https://your-domain/webhooks/slack.
Discord: Set your Discord application's Interactions Endpoint URL to https://your-domain/webhooks/discord.
Admin control surface
Pathfinder exposes an authenticated control plane for operational tasks that would otherwise require database surgery and a redeploy — forcing a reindex, inspecting index state, and so on.
Authentication
All privileged surfaces — analytics (/api/analytics/*), Atlas ratification (/api/atlas/*), and admin ops (/admin/*) — share one admin-access bearer token: the ANALYTICS_TOKEN environment variable. Authenticate every request with an Authorization: Bearer $ANALYTICS_TOKEN header.
- 401 Unauthorized — the token is missing or does not match.
- 503 Service Unavailable — no token is configured. These surfaces fail closed: with no
ANALYTICS_TOKENset, they reject every request rather than running unauthenticated.
Force a reindex — POST /admin/reindex
Queues an indexing job and returns 202 Accepted. The body selects the scope:
{ "scope": "full" }— reindex every configured source.{ "scope": "source", "source": "<configured-source-name>" }— reindex a single named source.{ "scope": "repo", "repo": "<configured-repo-url>" }— incrementally reindex a single git-backed source by repo URL.
An unknown source name or repo URL returns 400 Bad Request so a typo fails loud instead of silently no-op-ing.
Inspect index state — GET /admin/index-stats
Returns 200 OK with current index statistics (a POST /admin/index-stats alias is also accepted):
The response body has the shape:
Volume Mounts
What you mount depends on your source configuration:
- Local docs — If your source uses a
pathwithout arepo, you need to mount the docs directory into the container (e.g.,-v ./docs:/app/docs:ro). - Git-backed sources — If your source specifies a
repo, Pathfinder clones it automatically. No volume mount needed for the docs themselves. - Config file — Always mount your
pathfinder.yaml(e.g.,-v ./pathfinder.yaml:/app/pathfinder.yaml:ro). - Workspace persistence — If agents use writable workspaces (
workspace: truein bash tools), mount a persistent volume at theWORKSPACE_DIRpath. Without this, workspace files are lost on restart. - Database persistence — The Postgres data directory should always be on a persistent volume.