ocaptain
O Captain! my Captain! our fearful Claude Code session is done, The repo has weather'd every rack, the prize we sought is won.
Minimalist multi-coding agent control plane built on sprites.dev VMs with Tailscale mesh networking. Orchestration is managed by Claude Code's built-in task list feature: work is distributed by the ocaptain CLI to cloud VMs ("ships") that work in parallel on a plan you generate with Claude.
No Kubernetes, no local sandboxes, no containers, no asking for permissions.
Table of Contents
What it does
Provisions a fleet of VMs on sprites.dev, each running an autonomous Claude Code agent. Ships sync files via Mutagen and coordinate through a shared task list—no central scheduler, just agents racing to complete work.
You (local) → ocaptain sail → sprites.dev VMs → Ships claim tasks → Code syncs back
Why?
- Deploy parallel, autonomous Claude Code instances with one command
- No container complexity: full Linux VMs with direct access
- Watch Claude Code sessions in real-time via tmux
- Task-based coordination means no conflicts, no merge hell
- Local storage with Mutagen sync—no storage VM required
- Built-in OpenTelemetry observability
Quickstart
Prerequisites
- sprites.dev account with
spriteCLI installed - Tailscale installed and running
- Mutagen installed (
brew install mutagen-io/mutagen/mutagen) - Claude Code long-lived OAuth token (subscription required, from
claude setup-token) - Tailscale OAuth secret for ephemeral auth keys
Install
# Clone and install
git clone https://github.com/smithclay/ocaptain.git
cd ocaptain
uv sync
Set credentials
# Claude Code OAuth token (from `claude setup-token`)
export CLAUDE_CODE_OAUTH_TOKEN="your-token-here"
# Tailscale OAuth secret (for ephemeral ship auth keys)
export OCAPTAIN_TAILSCALE_OAUTH_SECRET="tskey-client-xxxx"
# sprites.dev org
export OCAPTAIN_SPRITES_ORG="your-org"
# Optional: GitHub token for private repos
export GH_TOKEN="ghp_xxxx"
Check prerequisites
uv run ocaptain doctor
Make a plan
At the moment, you need to use Claude Code to create a detailed dependency plan to pass to ocaptain.
Use an existing plan
For convenience, example plans are available in the examples/generated-plans directory.
Create a custom plan
In Claude Code, run the following then restart:
/plugin marketplace add smithclay/skills
/plugin install ocaptain-skills@smithclay-skills
You're now ready to generate a detailed plan in Claude Code using /voyage-plan:
Plan a voyage with ocaptain: take an empty repository and make a to-do list app.
Launch a voyage
# A plan is required, see "Make a plan" above
uv run ocaptain sail ./examples/generated-plans/multilingual-readme
# Monitor status
uv run ocaptain status
# Attach to a ship's tmux session to watch Claude work
uv run ocaptain shell voyage-abc123 ship-0
# View aggregated logs
uv run ocaptain logs voyage-abc123 --follow
# Clone the workspace when done
uv run ocaptain clone voyage-abc123
# Scuttle the fleet
uv run ocaptain sink voyage-abc123
Architecture
flowchart TB
subgraph Local["Local Machine"]
CLI[ocaptain CLI]
Voyages[(~/voyages/)]
Telemetry[OTLP Collector]
end
subgraph Tailscale["Tailscale Mesh"]
TS[100.x.x.x]
end
subgraph Sprites["sprites.dev"]
subgraph Fleet["Ship VMs"]
S0[Ship 0<br/>Claude Code]
S1[Ship 1<br/>Claude Code]
S2[Ship N<br/>Claude Code]
end
end
CLI -->|Mutagen Sync| TS
TS -->|Workspace + Tasks| Fleet
Fleet -->|Telemetry| Telemetry
S0 & S1 & S2 -->|tmux sessions| CLI
Components
| Component | Description |
|---|---|
| Local Voyages | ~/voyages/<voyage-id>/ contains workspace, tasks, logs, and artifacts |
| Ship VMs | sprites.dev VMs running Claude Code autonomously in tmux sessions |
| Tailscale Mesh | Ships join tailnet with ephemeral keys for direct connectivity |
| Mutagen Sync | Two-way file sync between laptop and ships (workspace + tasks) |
| Task List | Shared JSON files in ~/.claude/tasks/. Ships race to claim pending tasks |
Voyage Lifecycle
- Setup — Local voyage directory created, repo cloned, tasks seeded
- Bootstrap — Ship VMs provisioned in parallel, join Tailscale, install Claude
- Sync — Mutagen sessions established for workspace and tasks
- Launch — Claude starts in tmux on each ship (autonomous operation)
- Work — Ships claim tasks, do work, changes sync back via Mutagen
- Complete — All tasks done, workspace ready to clone
- Sink — VMs destroyed, Tailscale nodes removed
CLI Reference
ocaptain sail <plan>
Launch a new voyage from a plan directory.
uv run ocaptain sail ./plans/add-auth --ships 5
| Option | Description |
|---|---|
--ships, -n |
Override recommended ship count |
--no-telemetry |
Disable OTLP telemetry collection |
ocaptain status [voyage_id]
Show voyage status derived from task list. Auto-selects if only one active voyage.
uv run ocaptain status
uv run ocaptain status voyage-abc123
ocaptain logs <voyage_id>
View aggregated logs from all ships.
uv run ocaptain logs voyage-abc123
uv run ocaptain logs voyage-abc123 --follow --grep "error"
| Option | Description |
|---|---|
--ship, -s |
Filter to specific ship |
--follow, -f |
Stream logs in real-time |
--grep, -g |
Filter log lines by pattern |
--tail, -n |
Show last N lines |
ocaptain tasks <voyage_id>
Display task list with status, assignees, and blockers.
uv run ocaptain tasks voyage-abc123
uv run ocaptain tasks voyage-abc123 --status pending
ocaptain shell <voyage_id> [ship_id]
Attach to a ship's tmux session to observe Claude working.
uv run ocaptain shell voyage-abc123 ship-0 # Attach to ship's tmux
uv run ocaptain shell voyage-abc123 ship-0 --raw # Direct SSH
ocaptain clone [voyage_id]
Clone the workspace from local voyage storage.
uv run ocaptain clone # Auto-select if one voyage
uv run ocaptain clone voyage-abc123 -d ./my-copy
ocaptain sink <voyage_id>
Destroy voyage VMs and clean up.
uv run ocaptain sink voyage-abc123 # Destroy ships
uv run ocaptain sink --all -f # Destroy ALL ocaptain VMs
| Option | Description |
|---|---|
--all |
Destroy ALL ocaptain VMs |
--force, -f |
Skip confirmation |
ocaptain doctor
Check system prerequisites and configuration.
uv run ocaptain doctor
ocaptain telemetry-start / telemetry-stop
Start or stop the local OTLP telemetry collector.
uv run ocaptain telemetry-start
uv run ocaptain telemetry-stop
Configuration
Environment Variables
| Variable | Required | Description |
|---|---|---|
CLAUDE_CODE_OAUTH_TOKEN |
Yes | Claude Code authentication token |
OCAPTAIN_TAILSCALE_OAUTH_SECRET |
Yes | Tailscale OAuth secret for ephemeral keys |
OCAPTAIN_SPRITES_ORG |
Yes | sprites.dev organization name |
GH_TOKEN |
No | GitHub token for private repos |
OCAPTAIN_DEFAULT_SHIPS |
No | Default ship count (default: 3) |
sprites.dev Setup
Install the sprite CLI and authenticate:
# Test connectivity
sprite list -o your-org
# Create a test sprite
sprite create -o your-org test-sprite
Tailscale Setup
- Create an OAuth client in the Tailscale admin console with
devices:writescope - Set
OCAPTAIN_TAILSCALE_OAUTH_SECRETto the client secret - Ensure your laptop is connected to the tailnet
Security
Token Handling
- OAuth tokens passed via environment variables, not command args
- Tailscale ephemeral keys expire automatically when ships are destroyed
Network Isolation
- Ships communicate only via Tailscale mesh (no public IPs)
- Each ship is a full Linux VM with its own filesystem
- Mutagen sync scoped to specific directories
Repository Access
- Private repos require
GH_TOKEN - Token validity checked before VM provisioning
- Clone failures surface immediately, not after fleet deploys
Metadata
Release files for ocaptain 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ocaptain-0.0.2.tar.gz | 9.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ocaptain-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.5 kB
Release files / ocaptain-0.0.2.tar.gz
| Download URL | ocaptain-0.0.2.tar.gz |
|---|---|
| Size | 9.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
13619d4373afe1ef839220d4c368264a99b4b3722decab01c41d73127e65a4b0
|
|
BLAKE2b-256 checksum How to use checksums |
3bc58a5b7ba9f2b5363467475085c947ebb9cc5346a90acee8d91aaa043633c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / ocaptain-0.0.2-py3-none-any.whl
| Download URL | ocaptain-0.0.2-py3-none-any.whl |
|---|---|
| Size | 10.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4bd1bd4f3d7a0e1413989869a5edcc81ed15b3809eb763f1eb0ecf2754a180d5
|
|
BLAKE2b-256 checksum How to use checksums |
11e3c5c0101e9329df6cf897f761855519bee872c8ee7189d830bd5af1c3a1f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|