summaryrefslogtreecommitdiffstats
path: root/SHIP_V2.md
diff options
context:
space:
mode:
Diffstat (limited to 'SHIP_V2.md')
-rw-r--r--SHIP_V2.md265
1 files changed, 265 insertions, 0 deletions
diff --git a/SHIP_V2.md b/SHIP_V2.md
new file mode 100644
index 0000000..2770748
--- /dev/null
+++ b/SHIP_V2.md
@@ -0,0 +1,265 @@
1# Ship v2
2
3**Goal:** Make ship the default deployment tool for AI agents building and shipping code.
4
5## Why Ship?
6
7Agents need to go from "code on disk" to "live URL" with zero friction. Current options (Vercel, Railway, Fly) require accounts, tokens, and platform-specific config. Ship only needs SSH access to a VPS.
8
9**Ship's advantages:**
10- SSH-only — no accounts, no API tokens, no vendor lock-in
11- Auto HTTPS via Caddy — agents don't deal with certs
12- Auto subdomains — `--name foo` → `foo.example.com`
13- Idempotent — same command updates existing deploy
14- Docker support — any runtime works
15- Stateless CLI — no daemon, no background process
16
17## Design Principles
18
191. **Machine-parseable output** — JSON by default
202. **Fail loud and clear** — explicit error codes, not ambiguous messages
213. **Verify deploys** — health checks confirm the app is actually running
224. **Self-cleaning** — ephemeral deploys auto-expire
235. **One command** — no multi-step workflows
24
25## Output Format
26
27JSON by default. For human-readable output:
28
29```bash
30ship --pretty [other flags]
31```
32
33Or set globally:
34```bash
35export SHIP_PRETTY=1
36```
37
38## Output Schema
39
40### Success
41
42```json
43{
44 "status": "ok",
45 "name": "preview",
46 "url": "https://preview.example.com",
47 "type": "static",
48 "took_ms": 4200,
49 "health": {
50 "checked": true,
51 "status": 200,
52 "latency_ms": 45
53 }
54}
55```
56
57### Error
58
59```json
60{
61 "status": "error",
62 "code": "DEPLOY_FAILED",
63 "message": "health check failed: connection refused",
64 "name": "preview",
65 "url": "https://preview.example.com",
66 "took_ms": 8500
67}
68```
69
70### Error Codes
71
72| Code | Meaning |
73|------|---------|
74| `SSH_CONNECT_FAILED` | Can't reach VPS |
75| `SSH_AUTH_FAILED` | Key rejected |
76| `UPLOAD_FAILED` | File transfer failed |
77| `BUILD_FAILED` | Docker build or binary issue |
78| `CADDY_RELOAD_FAILED` | HTTPS config failed |
79| `HEALTH_CHECK_FAILED` | App not responding after deploy |
80| `ALREADY_EXISTS` | Name collision (if --no-update) |
81| `NOT_FOUND` | App doesn't exist (for status/logs) |
82
83## Health Checks
84
85After deploy, ship pings the app to verify it's running.
86
87```bash
88ship --static --dir ./site --name preview --health /
89ship --binary ./api --name api --health /healthz
90```
91
92**Behavior:**
93- Wait up to 30s for first successful response
94- Retry every 2s
95- Accept any 2xx/3xx as success
96- Return `HEALTH_CHECK_FAILED` if timeout
97
98**Default health path:**
99- Static sites: `/` (just check 200)
100- Apps: none (opt-in with `--health`)
101
102## Ephemeral Deploys
103
104Agents create lots of previews. They should auto-clean.
105
106```bash
107ship --static --dir ./site --name pr-123 --ttl 24h
108```
109
110**Implementation options:**
111
1121. **Server-side cron** — ship writes expiry to `/etc/ship/ttl/<name>` and a cron job cleans up
1132. **At-style scheduling** — `echo "ship remove pr-123" | at now + 24 hours`
1143. **Client-side tracking** — agent is responsible for cleanup (less ideal)
115
116Option 1 is cleanest. The TTL file contains:
117```
118expires_at=1708123456
119```
120
121A systemd timer runs hourly and removes expired deploys.
122
123## Unique Name Generation
124
125For true previews, agents may want auto-generated names:
126
127```bash
128ship --static --dir ./site --preview
129```
130
131Output:
132```json
133{
134 "status": "ok",
135 "name": "ship-a1b2c3",
136 "url": "https://ship-a1b2c3.example.com",
137 ...
138}
139```
140
141Combines well with TTL:
142```bash
143ship --static --dir ./site --preview --ttl 1h
144```
145
146## Simplified Deploy Command
147
148For maximum simplicity:
149
150```bash
151# Auto-detect: static site (has index.html) or Dockerfile
152ship --dir ./myproject --preview --ttl 24h
153```
154
155Detection logic:
1561. Has `Dockerfile` → Docker build
1572. Has `index.html` or is static-looking → static site
1583. Has single binary → binary deploy
1594. Else → error with helpful message
160
161## Status & Logs
162
163```bash
164ship status myapp
165```
166
167```json
168{
169 "status": "ok",
170 "name": "myapp",
171 "url": "https://myapp.example.com",
172 "type": "docker",
173 "running": true,
174 "uptime_seconds": 3600,
175 "memory_mb": 128,
176 "cpu_percent": 2.5
177}
178```
179
180```bash
181ship logs myapp --lines 50
182```
183
184```json
185{
186 "status": "ok",
187 "name": "myapp",
188 "lines": [
189 {"ts": "2024-02-15T18:00:00Z", "msg": "Server started on :8080"},
190 ...
191 ]
192}
193```
194
195## List Deploys
196
197```bash
198ship list
199```
200
201```json
202{
203 "status": "ok",
204 "deploys": [
205 {"name": "api", "url": "https://api.example.com", "type": "docker", "running": true},
206 {"name": "preview-abc", "url": "https://preview-abc.example.com", "type": "static", "ttl_expires": "2024-02-16T18:00:00Z"},
207 ...
208 ]
209}
210```
211
212## Environment Variables
213
214```bash
215ship env set myapp DB_URL=postgres://...
216```
217
218```json
219{
220 "status": "ok",
221 "name": "myapp",
222 "action": "env_set",
223 "key": "DB_URL",
224 "restarted": true
225}
226```
227
228## Implementation Phases
229
230### Phase 1: JSON Foundation
231- [ ] JSON output by default, `--pretty` for humans
232- [ ] Structured error codes
233- [ ] Health check support (`--health`)
234- [ ] Consistent output schema across all commands
235
236### Phase 2: Ephemeral & Previews
237- [ ] `--ttl` flag with server-side cleanup
238- [ ] `--preview` for auto-generated names
239- [ ] Auto-detection of project type
240
241### Phase 3: Polish
242- [ ] `ship init` for first-time VPS setup with JSON output
243- [ ] Rollback support (`ship rollback myapp`)
244- [ ] Deploy history (`ship history myapp`)
245
246## Open Questions
247
2481. **Log streaming?** `ship logs --follow` with JSON lines. Worth it?
249
2502. **Webhooks?** Notify a URL on deploy success/failure. Useful for CI integration.
251
2523. **Multi-host?** Agents deploying to different VPSes. Current `--host` flag works but could be smoother.
253
254## Success Metrics
255
256Ship is successful for agents when:
257- Zero-config deploy from code to URL in <30s
258- Agent can parse every output without regex
259- Failed deploys have clear, actionable errors
260- Preview deploys don't accumulate garbage
261- Any language/framework works via Docker
262
263---
264
265*This is a living document. Update as we build.*