Infrastructure for AI Coding Agents
An extremely lightweight infrastructure CLI for provisioning, deploying, tailing logs, and destroying servers.
One binary. Zero dashboards. A minimal cloud control layer that agents can drive reliably.
Install • Quick Start • Agent Skill • GitHub • Releases
ship is a minimal infrastructure primitive for AI coding agents.
There are too many moments where an agent is working inside the terminal, then suddenly has to break context to provision a server, deploy code, fetch logs, or tear infrastructure down. That context switch is wasteful. ship keeps the entire flow inside the CLI so deployment can be handled directly by cloud-capable agents without leaving the terminal.
The goal is simple: give agents a tiny, deterministic interface for infrastructure operations.
How it works:
- Create a server with
ship server create - Deploy the current project with
ship deploy - Inspect and operate with
ship status,ship logs, andship exec - Manage secrets and releases with
ship secrets,ship release list, andship rollback - List locally tracked servers with
ship server list - Destroy the server with
ship server destroy
Key features:
- Operator commands: status, exec, secrets, release history, rollback, bootstrap, and domain setup
- Single binary: build once with
go build -o ship - Provider support: DigitalOcean, Hetzner, and Vultr
- Deterministic output: machine-friendly
KEY=VALUEresponses - Structured JSON mode: pass
--jsonfor machine-readable output - No dashboard required: everything happens from the terminal
- Configurable deploy flow: use
ship.jsonfor project-specific deploy steps - Local state tracking: server metadata stored in
.ship/server.json
go build -o shipcurl -fsSL https://raw.githubusercontent.com/basilysf1709/ship/main/install.sh | shDownload the reusable skill file directly:
curl -O https://raw.githubusercontent.com/basilysf1709/ship/main/Skills.mdThis file is intended to be dropped into an agent workflow as a concise instruction sheet for using ship.
export DIGITALOCEAN_TOKEN=...
ship server create --provider digitalocean
ship deploy
ship logs
ship server destroyProvider selection:
ship server create --provider digitalocean
ship server create --provider hetzner
ship server create --provider vultrship uses provider tokens from environment variables:
DIGITALOCEAN_TOKENHCLOUD_TOKENVULTR_API_KEY
You only need to set the token for the provider you are using.
Before creating a server, make sure this machine has an SSH key available. ship will use a local SSH public key and automatically register it with the provider if needed.
Recommended default setup:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
ssh-add ~/.ssh/id_ed25519If a matching local private key is not available, server creation can succeed but SSH bootstrap and deploy steps will fail.
- Go
- A local SSH key on this machine, either in
~/.ssh/or loaded inssh-agent - Docker installed locally if you use the default deploy flow
- A
Dockerfilein the current project if you use the default deploy flow
ship server create
ship deploy
ship status
ship logs
ship exec -- uname -a
ship secrets list
ship release list
ship server destroy| Command | Description |
|---|---|
ship server create |
Create a server, install Docker, and track it locally |
ship server list |
Show a table of locally tracked servers on this machine |
ship deploy |
Run the project's configured deploy flow, or the default Docker deploy if no config is present |
ship status |
Show SSH reachability, app status, healthcheck result, and last release |
ship exec |
Run a remote command on the current server |
ship secrets |
Manage local secrets and sync them to the current server |
ship release list |
Show tracked release history for the current project |
ship rollback |
Restore a previous uploaded release and rerun its remote commands |
ship bootstrap |
Apply bootstrap packages, proxy, and remote setup commands to the current server |
ship domain setup |
Configure Caddy reverse proxy and automatic TLS for domains |
ship init |
Generate a starter ship.json template |
ship logs |
Fetch the last 100 log lines from the app container |
ship server destroy |
Destroy the current server and remove local state |
| Flag | Description |
|---|---|
--provider <name> |
Choose provider: digitalocean, hetzner, or vultr |
--region <region> |
Override the provider region or location |
--size <size> |
Override the provider size, plan, or server type |
--image <image> |
Override the provider image |
Default create settings by provider:
| Provider | Region | Size | Image |
|---|---|---|---|
| DigitalOcean | nyc3 |
s-2vcpu-4gb |
ubuntu-22-04-x64 |
| Hetzner | nbg1 |
cx22 |
ubuntu-22.04 |
| Vultr | ewr |
vc2-2c-4gb |
Ubuntu 22.04 x64 |
Examples:
ship server create --provider digitalocean --region sfo3 --size s-1vcpu-2gb --image ubuntu-22-04-x64
ship server create --provider hetzner --region fsn1 --size cpx21 --image ubuntu-24.04
ship server create --provider vultr --region ord --size vc2-1c-2gb --image "Ubuntu 24.04 x64"ship deploy looks for a ship.json file in the current directory. If it finds a deploy block, it runs that deploy recipe. If ship.json is missing, it falls back to the default Docker-based flow.
Example ship.json:
{
"deploy": {
"local_commands": [
"npm ci",
"npm run build",
"tar -czf release.tar.gz dist package.json"
],
"uploads": [
{
"source": "release.tar.gz",
"destination": "/opt/app/release.tar.gz",
"mode": "0644"
}
],
"remote_commands": [
"mkdir -p /opt/app",
"cd /opt/app && tar -xzf release.tar.gz",
"cd /opt/app && npm ci --omit=dev",
"cd /opt/app && pm2 restart app || pm2 start npm --name app -- start"
],
"cleanup_local": [
"release.tar.gz"
]
}
}Fields:
local_commands: shell commands run on the local machine before uploaduploads: files to copy to the server, withsource,destination, and optional quoted octalmoderemote_commands: shell commands run on the server in ordercleanup_local: local files removed after deploy finishes
Additional top-level config blocks:
bootstrap: packages and remote commands to apply duringship server createorship bootstrapproxy: domains andapp_portforship domain setupand default reverse-proxy deploysstatus:healthcheck_urlorhealthcheck_pathforship status
If no ship.json deploy config exists, ship deploy assumes a Dockerfile exists and runs:
docker build -t app .
docker save app -o app.tarThen it uploads the image to the server and runs:
docker load -i /root/app.tar
docker stop app || true
docker rm app || true
docker run -d --name app -p 80:80 appExample output:
STATUS=DEPLOY_COMPLETE
SERVER_IP=1.2.3.4
Server metadata is stored locally in:
.ship/server.json
Machine-wide server inventory is stored in:
~/.ship/servers.json
Project release history is stored in:
.ship/releases.json
Local secrets are stored in:
.ship/secrets.env
Example:
{
"provider": "digitalocean",
"server_id": "12345",
"ip": "1.2.3.4",
"ssh_user": "root"
}All command output is designed to stay clean and machine-parseable:
STATUS=SERVER_CREATED
SERVER_ID=12345
SERVER_IP=1.2.3.4
ship is for the gap between coding and infrastructure.
When an AI coding agent is already operating in a terminal, it should not need a browser, a dashboard, or a separate deployment toolchain just to ship code. Provisioning, deployment, log access, and teardown should all be available as a small CLI primitive that agents can call directly and predictably.