summaryrefslogtreecommitdiffstats
path: root/SHIP_V2.md
blob: 7b607cba4dae0d739028ff5e3a5466ddf9661091 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# Ship v2

**Ship is a deployment tool built for AI agents.**

Agents write code. Ship puts it on the internet. That's it.

## The Problem

AI agents can write code, but deploying it is a mess:
- Vercel/Railway/Fly require accounts, API tokens, platform-specific config
- Docker/K8s are overkill for "make this code accessible via URL"
- Most tools assume a human is reading the output

Agents need: code → URL. Nothing else.

## Ship's Approach

```bash
ship ./myproject
# {"status":"ok","url":"https://abc123.example.com","took_ms":4200}
```

**That's the entire interface.** Point ship at code, get a URL back as JSON.

### Core Principles

1. **JSON in, JSON out** — No human-formatted output. No spinners. No emoji. Agents parse JSON.

2. **One command** — No workflows. No "init then configure then deploy." One command does everything.

3. **Verify or fail** — Every deploy is health-checked. If the app isn't responding, ship returns an error. No silent failures.

4. **Self-cleaning** — Deploys can auto-expire. Agents create lots of previews; they shouldn't pile up forever.

5. **Zero config** — Point at a directory. Ship figures out if it's static, Docker, or a binary. No config files required.

6. **SSH-only** — No accounts. No API tokens. No vendor lock-in. Just SSH access to a VPS.

## Interface

### Deploy

```bash
ship ./myproject
ship ./myproject --name myapp
ship ./myproject --name preview --ttl 24h
ship ./site --static
ship ./api --health /healthz
```

Output:
```json
{
  "status": "ok",
  "name": "myapp",
  "url": "https://myapp.example.com",
  "type": "docker",
  "took_ms": 4200,
  "health": {"status": 200, "latency_ms": 45}
}
```

### Error

```json
{
  "status": "error",
  "code": "HEALTH_CHECK_FAILED",
  "message": "GET /healthz returned 503 after 30s",
  "name": "myapp",
  "url": "https://myapp.example.com"
}
```

### List

```bash
ship list
```

```json
{
  "status": "ok",
  "deploys": [
    {"name": "api", "url": "https://api.example.com", "type": "docker", "running": true},
    {"name": "preview-x7k", "url": "https://preview-x7k.example.com", "type": "static", "expires": "2024-02-16T18:00:00Z"}
  ]
}
```

### Status / Logs / Remove

```bash
ship status myapp
ship logs myapp
ship logs myapp --lines 100
ship remove myapp
```

All return JSON with `{"status": "ok", ...}` or `{"status": "error", "code": "...", ...}`.

## Error Codes

Machine-readable. No guessing.

| Code | Meaning |
|------|---------|
| `SSH_FAILED` | Can't connect to VPS |
| `UPLOAD_FAILED` | File transfer failed |
| `BUILD_FAILED` | Docker build or compile failed |
| `DEPLOY_FAILED` | systemd/Caddy setup failed |
| `HEALTH_CHECK_FAILED` | App not responding |
| `NOT_FOUND` | App doesn't exist |
| `CONFLICT` | Name already taken |

## Auto-Detection

Ship looks at the directory and figures out what to do:

| Directory contains | Deploy type |
|-------------------|-------------|
| `Dockerfile` | Docker build → systemd service |
| `index.html` | Static site → Caddy file_server |
| Single executable | Binary → systemd service |
| `go.mod` | Go build → systemd service |
| `package.json` + no Dockerfile | Error: "Add a Dockerfile" |

No config files. No `ship.json`. No `ship init`.

## TTL (Time-To-Live)

Agents create previews. Previews should auto-delete.

```bash
ship ./site --name pr-123 --ttl 1h
ship ./site --name pr-123 --ttl 7d
```

After TTL expires, the deploy is removed automatically. The `expires` field in JSON tells you when.

## Health Checks

Every deploy is verified. Ship waits for the app to respond before returning success.

- Static sites: `GET /` returns 2xx
- Apps: `GET /` by default, or specify `--health /healthz`
- Timeout: 30s
- If health check fails: `{"status": "error", "code": "HEALTH_CHECK_FAILED", ...}`

## Name Generation

No name? Ship generates one.

```bash
ship ./site
# {"name": "ship-a1b2c3", "url": "https://ship-a1b2c3.example.com", ...}
```

Provide a name to get a stable URL:

```bash
ship ./site --name docs
# {"name": "docs", "url": "https://docs.example.com", ...}
```

## Host Setup

One-time setup for a VPS:

```bash
ship host init user@my-vps.com --domain example.com
```

```json
{
  "status": "ok",
  "host": "my-vps.com",
  "domain": "example.com",
  "installed": ["caddy", "docker", "systemd"]
}
```

After this, the host is ready. Ship remembers it.

## Human Output

Humans are an afterthought, but they can use ship too:

```bash
ship ./site --pretty
```

```
✓ Deployed to https://ship-a1b2c3.example.com (4.2s)
```

Or set globally:
```bash
export SHIP_PRETTY=1
```

## Implementation Phases

### Phase 1: JSON Everything
- [ ] JSON output on all commands
- [ ] Structured error codes
- [ ] Exit codes match error states

### Phase 2: Smart Deploys
- [ ] Auto-detect project type
- [ ] Health checks on every deploy
- [ ] `--ttl` with server-side cleanup

### Phase 3: Zero Friction
- [ ] `ship ./dir` with no flags (auto name, auto detect)
- [ ] `ship host init` fully automated
- [ ] One binary, zero dependencies on client

## Non-Goals

- **Pretty output** — That's what `--pretty` is for
- **Interactive prompts** — Never. Agents can't answer prompts.
- **Config files** — Zero config. Detect everything.
- **Plugin system** — Keep it simple.
- **Multi-cloud orchestration** — One VPS at a time.

## Success Criteria

Ship is done when an agent can:

1. Build code
2. Run `ship ./code`
3. Parse the JSON response
4. Use the URL

No docs. No setup. No tokens. No accounts. Just `ship ./code`.

---

*Built for agents. Tolerated by humans.*