PilotSwarm can be up and running in a few minutes from a single Docker image.
This starter image gives you:
- a browser portal at
http://localhost:3001 - an SSH-accessible TUI at
ssh -o StrictHostKeyChecking=accept-new -p 2222 pilotswarm@localhost - two background PilotSwarm workers
- durable session state in PostgreSQL
- local filesystem artifacts by default, or Azure Blob storage if you wire it in
If you want the fastest path to seeing PilotSwarm do real work, start with the portal.
docker pull affandar/pilotswarm-starter:latestThe starter image is published for linux/amd64 and linux/arm64. Docker
automatically pulls the matching image for your machine, including Apple
Silicon.
If you want the exact released build instead of the moving latest tag, pull the versioned image:
docker pull affandar/pilotswarm-starter:0.4.0Set GITHUB_TOKEN in your shell to a GitHub Copilot-enabled token before you
run Docker. If you do not have one yet, jump to
How to get a GitHub token.
export GITHUB_TOKEN=your_github_token
docker run -d \
--name pilotswarm-starter \
-p 127.0.0.1:3001:3001 \
-p 127.0.0.1:2222:2222 \
-e GITHUB_TOKEN \
-v pilotswarm-data:/data \
affandar/pilotswarm-starter:latestThat is the simplest mode:
- portal exposed at
http://localhost:3001 - SSH TUI exposed at port
2222 - embedded PostgreSQL enabled automatically
- local filestore used automatically
The current starter image uses embedded PostgreSQL 17. If you previously ran an
older starter image with the same pilotswarm-data volume, the old PostgreSQL
15 data directory will not start under PostgreSQL 17. For a clean quickstart,
remove the old container and volume before rerunning Docker:
docker rm -f pilotswarm-starter
docker volume rm pilotswarm-dataOpen the portal:
http://localhost:3001
Optional SSH access:
ssh -o StrictHostKeyChecking=accept-new -p 2222 pilotswarm@localhostDefault SSH password:
pilotswarm
The first SSH connection records the starter container's host key in your local
~/.ssh/known_hosts. The starter stores its SSH host keys in the Docker volume
at /data/ssh, so recreating or upgrading the container with the same
pilotswarm-data volume keeps the same SSH identity.
If you intentionally delete the volume or switch to a fresh volume, SSH may warn
that the host key for localhost:2222 changed. That is expected after a full
reset; remove only the stale local entry and connect again:
ssh-keygen -R '[localhost]:2222'
ssh-keygen -R '[127.0.0.1]:2222'
ssh -o StrictHostKeyChecking=accept-new -p 2222 pilotswarm@localhostOnce the portal opens:
- Click
New - Let PilotSwarm use the starter image’s default model:
claude-sonnet-4.6 - Start chatting and give the agent a plain-English job
The point of the first run is to remove decisions, not add them. The starter image already defaults to claude-sonnet-4.6, which is a strong everyday model for chat, coding, and long-running orchestration.
If you want to explore other models later, the starter image also includes:
claude-sonnet-4.6gpt-5.4gpt-5.4-miniclaude-opus-4.6
These are intentionally designed to create durable, recurring sessions so you can watch PilotSwarm do more than one-shot chat.
Track the top Hacker News trends in AI agents, coding tools, inference infrastructure, and MCP-style tooling. Check every 5 minutes. Each cycle, summarize what changed, what stayed stable, and what looks like a meaningful new signal instead of noise. Use subagents when useful, and keep the recurring monitor running until I tell you to stop.
What this does:
- creates a long-running recurring session
- usually fans work out through subagents
- gives you periodic summaries instead of one giant dump
- lets you watch hydration, timers, worker movement, and artifacts over time
Monitor the PilotSwarm GitHub repository every 5 minutes for new commits, merged pull requests, release-related changes, and anything that looks like a significant change in orchestration, portal UX, or starter Docker behavior. Summarize deltas each cycle and keep the session running until I cancel it.
What this does:
- creates a recurring repo-monitor session
- turns the system into a live “change radar”
- produces a nice event stream in Activity and Sequence
Every 5 minutes, summarize the latest movement in AI agent tooling using multiple subagents. Have one subagent use Claude Sonnet for broad synthesis, one use GPT-5.4 for cross-checking and structured takeaways, and one lightweight model for quick surface scans. Merge their findings into one short executive update and keep the loop running until I stop it.
What this does:
- creates a parent session plus child sessions
- lets you see model-specific work fan out
- makes the session tree, node map, and artifact flow much more interesting immediately
┌──────────────────────────────┐
│ Your Browser │
│ http://localhost:3001 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ Portal Process │
│ browser UI + API server │
└──────────────┬───────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
│ │ │
┌────▼─────┐ ┌─────▼─────┐ ┌────▼─────┐
│ Worker A │ │ PostgreSQL│ │ Worker B │
│ runtime │ │ session │ │ runtime │
│ process │ │ catalog │ │ process │
└────┬─────┘ └─────┬─────┘ └────┬─────┘
│ │ │
└──────────────┬──────────────┴──────────────┬──────────────┘
│ │
┌────────▼────────┐ ┌────────▼────────┐
│ Local filestore │ │ Azure Blob │
│ default │ │ optional │
│ /data │ │ if configured │
└─────────────────┘ └─────────────────┘
┌──────────────────────────────┐
│ SSH TUI │
│ localhost:2222 + accept-new │
└──────────────────────────────┘
The important mental model is simple:
- the portal and TUI are clients
- the two workers do the actual orchestration work
- PostgreSQL stores the durable session state
- artifacts and dehydrated session files live in local storage by default, or Blob if configured
That means a session can pause, wake up, move between workers, and keep going without you babysitting it.
Once one of those prompts is running, the portal becomes much more than a chat window.
The left session tree shows:
- the root session you created
- any child/subagent sessions it spawned
- current status markers like running, waiting, compacting, or cron cadence
This is the best place to see whether your “one request” turned into a little swarm.
The Inspector is the main conversation view for the selected session.
It shows:
- your messages
- agent replies
- system updates
- tables and artifacts
- recurring summaries over time
If the session is long-running, this becomes the durable narrative of what happened across cycles.
Activity is the lower-level operational feed.
Use it when you want to see:
- turn starts and completions
- command dispatch
- tool calls
- session updates
- orchestration events landing in near real time
If the Inspector feels like the story, Activity feels like the engine room.
Sequence is where PilotSwarm starts to click for most people.
This pane shows the timeline across orchestration and worker nodes. Watch for:
- turns starting
- timers firing
- sessions waiting
- sessions rehydrating on a different worker
- subagents fanning out and completing
If a session idles, dehydrates, then wakes up later, Sequence shows the bounce clearly.
Node Map gives you the “where is this actually running?” view.
It helps answer:
- which worker currently holds the session
- where child agents landed
- whether work is balanced across
worker-aandworker-b - how sessions move after a wait, cron wake-up, or worker handoff
This is the pane that makes the runtime feel durable instead of fragile.
History is the recent event and session-flow memory for that selected session. Use it to quickly skim prior iterations without scrolling through the full chat transcript.
Files is where artifacts show up:
- saved notes
- reports
- markdown summaries
- any generated outputs the session or its child agents persisted
This is the “show me what it actually produced” tab.
PilotSwarm sessions are designed to survive long waits and recurring work.
A typical recurring session lifecycle looks like this:
- You send a prompt
- A worker runs the turn
- The agent sets a timer or recurring cron
- The session goes idle
- The session can dehydrate to durable storage
- A timer fires later
- The session rehydrates, possibly on another worker
- The next cycle continues
That is why PilotSwarm can keep doing useful work even when:
- the session waits for minutes or hours
- one worker goes away
- you disconnect your browser
- you reconnect later from either the portal or the SSH TUI
In practice, the fun thing to watch is the Sequence pane after a few timer cycles. You will see the session pause, wake, move, and resume without losing the thread.
In the starter image you have two workers.
That means:
- one worker can pick up work the other was not actively holding
- recurring sessions can continue on the other worker after rehydration
- if the whole container stops, the durable state still lives in PostgreSQL plus storage
If you restart the appliance against the same database and storage, long-running work can resume from there.
If you want the cleanest “show me why this is interesting” flow:
- Start the container
- Open the portal
- Create a generic session with
claude-sonnet-4.6 - Paste the Hacker News trend-monitor prompt
- Let it run for 10 to 15 minutes
- Open
Sequence,Node Map, andFiles - Watch child sessions, recurring timers, and summaries accumulate
That is usually enough to understand the core promise:
PilotSwarm is not just a chat shell. It is a durable multi-agent runtime with interfaces that let you actually see the work moving through the system.
Follow logs:
docker logs -f pilotswarm-starterStop the appliance:
docker stop pilotswarm-starterRemove the container but keep the data volume:
docker rm -f pilotswarm-starterWipe everything, including local persisted data:
docker rm -f pilotswarm-starter
docker volume rm pilotswarm-dataAfter you are comfortable in the portal:
- try the SSH TUI
- run the same long-lived session from both surfaces
- watch the same session tree, activity, and artifacts appear in both places
That is when the architecture really lands: two interfaces, one durable runtime, shared state underneath.
If you already have a shared PostgreSQL instance:
docker run -d \
--name pilotswarm-starter \
-p 127.0.0.1:3001:3001 \
-p 127.0.0.1:2222:2222 \
-e GITHUB_TOKEN \
-e DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/DBNAME \
-v pilotswarm-data:/data \
affandar/pilotswarm-starter:latestIf you also want shared blob-backed artifacts and dehydration:
docker run -d \
--name pilotswarm-starter \
-p 127.0.0.1:3001:3001 \
-p 127.0.0.1:2222:2222 \
-e GITHUB_TOKEN \
-e DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/DBNAME \
-e AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net" \
-v pilotswarm-data:/data \
affandar/pilotswarm-starter:latestStorage behavior is:
AZURE_STORAGE_CONNECTION_STRINGset: use Azure Blob storage- not set: use local filesystem storage under
/data
PilotSwarm starter expects a GitHub personal access token from a GitHub account that already has GitHub Copilot access.
The shortest path is usually:
- Sign in to GitHub with the account that has Copilot enabled
- Open
Settings - Open
Developer settings - Open
Personal access tokens - Create a new token
- Copy it immediately and keep it somewhere safe
- Export it in your shell before running Docker, for example:
export GITHUB_TOKEN=your_github_tokenGitHub currently recommends fine-grained personal access tokens when your scenario supports them. The usual path is:
- In GitHub, go to
Settings->Developer settings->Personal access tokens->Fine-grained tokens - Click
Generate new token - Give it a name like
pilotswarm-starter-local - Pick an expiration
- Choose the correct resource owner
- Select the minimum repository access you need for your use case
- Generate the token and copy it immediately
If your organization requires approval for fine-grained tokens, the token may show up as pending until an org admin approves it.
If your org policy or GitHub setup does not allow the fine-grained route for your workflow, you may need to create a classic personal access token instead:
- Go to
Settings->Developer settings->Personal access tokens->Tokens (classic) - Click
Generate new token (classic) - Name it, pick an expiration, generate it, and copy it immediately
Keep the token out of git, chat logs, screenshots, and committed .env files.
Treat it like a password.
Official GitHub docs:
- GitHub Docs: Managing your personal access tokens
https://docs.github.com/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token