From c9b5ecd66b1da7c5b578d2fa51db3019de624f4b Mon Sep 17 00:00:00 2001 From: Clawd Date: Sun, 15 Feb 2026 18:13:38 -0800 Subject: docs: add agent mode design document --- AGENT_MODE.md | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 AGENT_MODE.md (limited to 'AGENT_MODE.md') diff --git a/AGENT_MODE.md b/AGENT_MODE.md new file mode 100644 index 0000000..1f00d61 --- /dev/null +++ b/AGENT_MODE.md @@ -0,0 +1,271 @@ +# Ship Agent Mode + +**Goal:** Make ship the default deployment tool for AI agents building and shipping code. + +## Why Ship for Agents? + +Agents 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. + +**Ship's advantages:** +- SSH-only — no accounts, no API tokens, no vendor lock-in +- Auto HTTPS via Caddy — agents don't deal with certs +- Auto subdomains — `--name foo` → `foo.example.com` +- Idempotent — same command updates existing deploy +- Docker support — any runtime works +- Stateless CLI — no daemon, no background process + +## Design Principles + +1. **Machine-parseable output** — JSON by default in agent mode +2. **Fail loud and clear** — explicit error codes, not ambiguous messages +3. **Verify deploys** — health checks confirm the app is actually running +4. **Self-cleaning** — ephemeral deploys auto-expire +5. **One command** — no multi-step workflows + +## Agent Mode Flag + +```bash +ship --agent [other flags] +``` + +When `--agent` is set: +- Output is JSON (no need for separate `--json`) +- Errors include machine-readable codes +- Health checks are enabled by default +- Progress is suppressed (no spinners, no "Uploading...") + +Alternatively, detect via environment: +```bash +SHIP_AGENT=1 ship --static --dir ./site --name preview +``` + +## Output Schema + +### Success + +```json +{ + "status": "ok", + "name": "preview", + "url": "https://preview.example.com", + "type": "static", + "took_ms": 4200, + "health": { + "checked": true, + "status": 200, + "latency_ms": 45 + } +} +``` + +### Error + +```json +{ + "status": "error", + "code": "DEPLOY_FAILED", + "message": "health check failed: connection refused", + "name": "preview", + "url": "https://preview.example.com", + "took_ms": 8500 +} +``` + +### Error Codes + +| Code | Meaning | +|------|---------| +| `SSH_CONNECT_FAILED` | Can't reach VPS | +| `SSH_AUTH_FAILED` | Key rejected | +| `UPLOAD_FAILED` | File transfer failed | +| `BUILD_FAILED` | Docker build or binary issue | +| `CADDY_RELOAD_FAILED` | HTTPS config failed | +| `HEALTH_CHECK_FAILED` | App not responding after deploy | +| `ALREADY_EXISTS` | Name collision (if --no-update) | +| `NOT_FOUND` | App doesn't exist (for status/logs) | + +## Health Checks + +After deploy, ship pings the app to verify it's running. + +```bash +ship --agent --static --dir ./site --name preview --health / +ship --agent --binary ./api --name api --health /healthz +``` + +**Behavior:** +- Wait up to 30s for first successful response +- Retry every 2s +- Accept any 2xx/3xx as success +- Return `HEALTH_CHECK_FAILED` if timeout + +**Default health path:** +- Static sites: `/` (just check 200) +- Apps: none (opt-in with `--health`) + +## Ephemeral Deploys + +Agents create lots of previews. They should auto-clean. + +```bash +ship --agent --static --dir ./site --name pr-123 --ttl 24h +``` + +**Implementation options:** + +1. **Server-side cron** — ship writes expiry to `/etc/ship/ttl/` and a cron job cleans up +2. **At-style scheduling** — `echo "ship remove pr-123" | at now + 24 hours` +3. **Client-side tracking** — agent is responsible for cleanup (less ideal) + +Option 1 is cleanest. The TTL file contains: +``` +expires_at=1708123456 +``` + +A systemd timer runs hourly and removes expired deploys. + +## Unique Name Generation + +For true previews, agents may want auto-generated names: + +```bash +ship --agent --static --dir ./site --preview +``` + +Output: +```json +{ + "status": "ok", + "name": "ship-a1b2c3", + "url": "https://ship-a1b2c3.example.com", + ... +} +``` + +Combines well with TTL: +```bash +ship --agent --static --dir ./site --preview --ttl 1h +``` + +## Simplified Deploy Command + +For maximum simplicity: + +```bash +# Auto-detect: static site (has index.html) or Dockerfile +ship --agent --dir ./myproject --preview --ttl 24h +``` + +Detection logic: +1. Has `Dockerfile` → Docker build +2. Has `index.html` or is static-looking → static site +3. Has single binary → binary deploy +4. Else → error with helpful message + +## Status & Logs + +```bash +ship --agent status myapp +``` + +```json +{ + "status": "ok", + "name": "myapp", + "url": "https://myapp.example.com", + "type": "docker", + "running": true, + "uptime_seconds": 3600, + "memory_mb": 128, + "cpu_percent": 2.5 +} +``` + +```bash +ship --agent logs myapp --lines 50 +``` + +```json +{ + "status": "ok", + "name": "myapp", + "lines": [ + {"ts": "2024-02-15T18:00:00Z", "msg": "Server started on :8080"}, + ... + ] +} +``` + +## List Deploys + +```bash +ship --agent list +``` + +```json +{ + "status": "ok", + "deploys": [ + {"name": "api", "url": "https://api.example.com", "type": "docker", "running": true}, + {"name": "preview-abc", "url": "https://preview-abc.example.com", "type": "static", "ttl_expires": "2024-02-16T18:00:00Z"}, + ... + ] +} +``` + +## Environment Variables + +```bash +ship --agent env set myapp DB_URL=postgres://... +``` + +```json +{ + "status": "ok", + "name": "myapp", + "action": "env_set", + "key": "DB_URL", + "restarted": true +} +``` + +## Implementation Phases + +### Phase 1: Core Agent Mode +- [ ] `--agent` flag for JSON output +- [ ] Structured error codes +- [ ] Health check support (`--health`) +- [ ] Fix JSON output for all commands (list, status, logs, env) + +### Phase 2: Ephemeral & Previews +- [ ] `--ttl` flag with server-side cleanup +- [ ] `--preview` for auto-generated names +- [ ] Auto-detection of project type + +### Phase 3: Polish +- [ ] `ship --agent init` for first-time VPS setup with JSON output +- [ ] Rollback support (`ship --agent rollback myapp`) +- [ ] Deploy history (`ship --agent history myapp`) + +## Open Questions + +1. **Should `--agent` be the default eventually?** Human-readable output could move to `--human` or `--pretty`. + +2. **Log streaming?** Agents might want `ship logs --follow` with JSON lines. Worth it? + +3. **Webhooks?** Notify a URL on deploy success/failure. Useful for CI integration. + +4. **Multi-host?** Agents deploying to different VPSes. Current `--host` flag works but could be smoother. + +## Success Metrics + +Ship is successful for agents when: +- Zero-config deploy from code to URL in <30s +- Agent can parse every output without regex +- Failed deploys have clear, actionable errors +- Preview deploys don't accumulate garbage +- Any language/framework works via Docker + +--- + +*This is a living document. Update as we build.* -- cgit v1.2.3