aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorClawd <ai@clawd.bot>2026-04-11 22:46:28 -0700
committerClawd <ai@clawd.bot>2026-04-11 22:46:28 -0700
commit0ec6d9cb739a4357c5e168855296ce2389d23a27 (patch)
tree18483a50880a3cded0f4b091e5afb83fc17822cc /README.md
parentd712f8696ac264544b903ec002f4ebd435042377 (diff)
Rewrite README for skills-based approach
Replaces outdated v1 git-push/CLI docs with accurate description of the Claude skills system. Covers install, quick start, config format, server layout, and skill reference table. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'README.md')
-rw-r--r--README.md174
1 files changed, 56 insertions, 118 deletions
diff --git a/README.md b/README.md
index c440c49..27ed219 100644
--- a/README.md
+++ b/README.md
@@ -1,167 +1,105 @@
1# Ship 1# Ship
2 2
3Ship turns a VPS into a self-hosted git server with a web frontend — similar to running cgit on your own domain. Visiting your base domain in a browser shows a cgit repo index; clicking through shows trees, commit logs, diffs, and blame. Public repos are cloneable over HTTPS. If you host Go code, `go get` works with your domain out of the box. This is the read-only, public-facing side, and it works exactly the way cgit users expect. 3Deploy Go binaries and static sites to a VPS with automatic HTTPS. No agent on the server — just SSH, systemd, and Caddy.
4 4
5The difference is what happens on the write side. When you `git push` over SSH, Ship doesn't just update the bare repo — it builds and deploys your code. A post-receive hook checks out the repo, runs `docker build`, installs a systemd service and Caddy reverse-proxy config, and restarts the app. Your deployment config (the systemd unit, the Caddyfile) lives in `.ship/` in your repo and is versioned alongside your code. Push to main and it's live; push to any other branch and nothing happens. 5## How it works
6 6
7Not every repo needs to be a running service. If there's no Dockerfile, the push is accepted but the deploy step is skipped — the repo just sits there as a browsable, cloneable library. This makes Ship useful for Go modules that only need vanity imports and a public source view, alongside apps that need the full build-and-deploy pipeline. The same base domain serves both. 7Ship is a set of Claude skills. Instead of a rigid CLI that bakes in assumptions, Claude reasons about what to do using a family of narrow, composable skills. The server is the source of truth — no local state file that can go stale.
8 8
9Ship also supports direct deploys (SCP a binary or rsync a static directory) for cases where git push isn't the right fit. 9## Skills
10 10
11Ship is a client-side CLI. All state lives on your laptop at `~/.config/ship/state.json`. The VPS is configured entirely over SSH — no agent or daemon runs on the server. 11| Skill | What it does |
12|-------|-------------|
13| `/ship-setup` | One-time VPS config. Installs Caddy, creates directories, saves host to `~/.config/ship/config.json` |
14| `/ship-status` | Show all running apps, ports, domains, and disk usage — derived live from server |
15| `/ship-deploy` | Deploy a binary or static site — orchestrates the skills below |
16| `/ship-binary` | Upload a pre-built binary, configure systemd + Caddy, back up SQLite |
17| `/ship-static` | Rsync a dist folder, configure Caddy to serve it |
18| `/ship-env` | Read/write env vars with merge semantics — never wipes existing vars |
19| `/ship-caddy` | Manage per-app Caddyfile — validates before reloading |
20| `/ship-service` | systemd control: start, stop, restart, logs |
12 21
13## Install 22## Install
14 23
15``` 24Copy the `skills/` directory into `~/.claude/skills/`:
16go install github.com/bdw/ship/cmd/ship@latest
17```
18
19Or build from source:
20 25
21``` 26```bash
22go build -o ship ./cmd/ship 27cp -r skills/ship-* ~/.claude/skills/
23``` 28```
24 29
25## Quick start 30## Quick start
26 31
27### 1. Set up the VPS 32### 1. Set up your VPS
28
29```
30ship host init --host user@your-vps --base-domain example.com
31```
32
33This installs Caddy, Docker, git, fcgiwrap, and cgit. It creates a `git` user for push access, configures sudoers for deploy hooks, and enables automatic HTTPS. The host becomes the default for subsequent commands.
34
35### 2. Deploy
36
37**Git push (Docker-based app):**
38
39```
40ship init myapp
41git add .ship/ Dockerfile
42git commit -m "initial deploy"
43git push origin main
44```
45
46**Git push (static site):**
47 33
48``` 34```
49ship init mysite --static 35/ship-setup
50git add .ship/ index.html
51git commit -m "initial deploy"
52git push origin main
53``` 36```
54 37
55**Git push (library / Go module):** 38Claude asks for SSH host, domain, and nickname. Saves to `~/.config/ship/config.json`. Installs Caddy on the server.
56 39
57``` 40Or run the script directly:
58ship init mylib --public
59git add .
60git commit -m "initial"
61git push origin main
62```
63
64No Dockerfile, so nothing is deployed — the repo is just browsable and cloneable at `https://example.com/mylib`.
65 41
66**Direct (pre-built binary):** 42```bash
67 43bash ~/.claude/skills/ship-setup/setup.sh ubuntu@1.2.3.4 example.com prod --default
68```
69GOOS=linux GOARCH=amd64 go build -o myapp
70ship --binary ./myapp --domain api.example.com
71``` 44```
72 45
73On first deployment, Ship creates a `.ship/` directory in your current working directory containing: 46### 2. Deploy
74- `.ship/service` - systemd unit file
75- `.ship/Caddyfile` - Caddy reverse proxy config
76
77These files are uploaded on each deployment. You can edit them locally to customize your deployment (add extra Caddy routes, adjust systemd settings). The systemd service is regenerated when you update resource limits with `--memory`, `--cpu`, or `--args` flags. The Caddyfile is never regenerated, so your custom routes won't be overwritten.
78
79You can version control `.ship/` or add it to `.gitignore` — it's your choice.
80
81## Commands
82
83### `ship init <name>`
84
85Create a bare git repo on the VPS and generate local `.ship/` config files.
86 47
87``` 48```
88ship init myapp # Docker-based app 49/ship-deploy
89ship init mysite --static # static site
90ship init myapp --domain custom.example.com # custom domain
91ship init mylib --public # publicly cloneable (for go get)
92``` 50```
93 51
94### `ship deploy <name>` 52Claude asks what you're deploying (binary or static site), where it is, what to call it, and any env vars. Handles the rest.
95
96Manually rebuild and deploy a git-deployed app.
97
98### `ship [deploy flags]`
99 53
100Deploy a pre-built binary or static directory directly. 54### 3. Check status
101 55
102``` 56```
103ship --binary ./myapp --domain api.example.com 57/ship-status
104ship --binary ./myapp --domain api.example.com --env DB_HOST=localhost
105ship --static --dir ./dist --domain example.com
106ship --name myapi --memory 512M --cpu 50%
107``` 58```
108 59
109Flags: `--binary`, `--static`, `--dir`, `--domain`, `--name`, `--env`, `--env-file`, `--args`, `--file`, `--memory`, `--cpu` 60Shows all running apps, ports, URLs, and disk usage — no local state file, reads directly from server.
110
111### `ship list`
112
113List all deployments on the default host.
114 61
115### `ship status/logs/restart/remove <name>` 62## Config
116 63
117Manage a deployment's systemd service. 64`~/.config/ship/config.json` — created by `/ship-setup`. Supports multiple hosts:
118 65
119### `ship env` 66```json
120 67{
121``` 68 "default": "prod",
122ship env list myapp 69 "hosts": {
123ship env set myapp KEY=VALUE 70 "prod": {
124ship env unset myapp KEY 71 "host": "ubuntu@1.2.3.4",
72 "domain": "example.com"
73 },
74 "staging": {
75 "host": "ubuntu@5.6.7.8",
76 "domain": "staging.example.com"
77 }
78 }
79}
125``` 80```
126 81
127### `ship host` 82Deploy to a specific host: "deploy foodtracker to staging"
128
129```
130ship host init --host user@vps --base-domain example.com
131ship host status
132ship host update
133ship host ssh
134```
135 83
136### `ship ui` 84## Server layout
137
138Launch a local web UI for viewing deployments.
139
140## VPS file layout
141 85
142``` 86```
143/srv/git/<name>.git/ # bare git repos 87/usr/local/bin/<name> # binary
144/srv/git/<name>.git/hooks/post-receive # auto-deploy hook 88/var/lib/<name>/ # work directory
145/var/lib/<name>/src/ # checked-out source (for docker build) 89/var/lib/<name>/data/ # persistent data (SQLite lives here)
146/var/lib/<name>/data/ # persistent data volume 90/var/lib/<name>/backups/ # SQLite backups (made before each binary swap)
147/var/www/<name>/ # static site files 91/var/www/<name>/ # static site files
148/etc/systemd/system/<name>.service # systemd unit 92/etc/systemd/system/<name>.service # systemd unit
149/etc/caddy/sites-enabled/<name>.caddy # per-app Caddy config 93/etc/caddy/sites-enabled/<name>.caddy # per-app Caddy config
150/etc/caddy/sites-enabled/ship-code.caddy # base domain Caddy config
151/etc/cgitrc # cgit configuration
152/etc/ship/env/<name>.env # environment variables 94/etc/ship/env/<name>.env # environment variables
153/etc/sudoers.d/ship-git # sudo rules for git user 95/etc/ship/ports/<name> # allocated port number
154/opt/ship/vanity/index.html # vanity import template
155/home/git/.ssh/authorized_keys # SSH keys for git push
156``` 96```
157 97
158## Supported platforms 98## Requirements
159
160VPS: Ubuntu 20.04+ or Debian 11+
161
162## Security
163 99
164See [SECURITY.md](SECURITY.md) for the threat model, mitigations, and known gaps. 100- VPS running Ubuntu 20.04+ or Debian 11+
101- SSH access
102- Claude Code with skills support
165 103
166## License 104## License
167 105