diff options
| author | Clawd <ai@clawd.bot> | 2026-04-11 20:43:41 -0700 |
|---|---|---|
| committer | Clawd <ai@clawd.bot> | 2026-04-11 20:43:41 -0700 |
| commit | d0ae31c24c3c98ae89eebd67227c0c0d01606ed5 (patch) | |
| tree | c684469e0f7d3b65477cfc631ecdaafa3c6a218a /skills/ship-deploy/SKILL.md | |
| parent | 5548b36e0953c17dbe30f6b63c892b7c83196b20 (diff) | |
Add ship-* Claude skills and plan
Introduces a skills/ directory with 8 Claude skills that reimagine ship
as a set of composable, human-driven deployment tools backed by Claude's
reasoning rather than a rigid CLI.
Skills:
- ship-setup: one-time VPS config, saves host to ~/.config/ship/config.json
- ship-status: derives live state from server, no local state file
- ship-env: read/write env vars with merge semantics, never overwrites
- ship-binary: deploy Go binaries with SQLite backup, correct restart behavior
- ship-caddy: manage per-app Caddyfile with validate-before-reload
- ship-service: systemd management and log inspection
- ship-static: rsync static sites with SPA routing support
- ship-deploy: orchestration runbook tying the others together
Also adds SKILLS_PLAN.md documenting the architecture and rationale.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'skills/ship-deploy/SKILL.md')
| -rw-r--r-- | skills/ship-deploy/SKILL.md | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/skills/ship-deploy/SKILL.md b/skills/ship-deploy/SKILL.md new file mode 100644 index 0000000..60cc263 --- /dev/null +++ b/skills/ship-deploy/SKILL.md | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | --- | ||
| 2 | name: ship-deploy | ||
| 3 | description: Deploy an app to a ship VPS. Orchestrates ship-binary or ship-static depending on what you're deploying. Use when you want to deploy or redeploy an app and want Claude to guide the process. | ||
| 4 | argument-hint: "<app-name> [host-nickname]" | ||
| 5 | --- | ||
| 6 | |||
| 7 | # ship-deploy | ||
| 8 | |||
| 9 | Orchestration runbook for deploying apps to a ship VPS. Guides the full deployment | ||
| 10 | process by calling the appropriate ship skills in the right order. | ||
| 11 | |||
| 12 | ## Prerequisites | ||
| 13 | |||
| 14 | - `/ship-setup` must have been run at least once | ||
| 15 | - `~/.config/ship/config.json` must exist and contain at least one host | ||
| 16 | - The app must already be built locally (binary compiled or dist folder ready) | ||
| 17 | |||
| 18 | ## Read Config | ||
| 19 | |||
| 20 | ```bash | ||
| 21 | python3 -c " | ||
| 22 | import json, os | ||
| 23 | cfg = json.load(open(os.path.expanduser('~/.config/ship/config.json'))) | ||
| 24 | nick = '<nickname-or-default>' | ||
| 25 | h = cfg['hosts'].get(nick, cfg['hosts'][cfg['default']]) | ||
| 26 | print(h['host']) | ||
| 27 | print(h['domain']) | ||
| 28 | " | ||
| 29 | ``` | ||
| 30 | |||
| 31 | ## Step 1 — Understand what we're deploying | ||
| 32 | |||
| 33 | Ask the user (or infer from context): | ||
| 34 | |||
| 35 | - **What is the app name?** (e.g. `foodtracker`) | ||
| 36 | - **What type?** Binary or static site? | ||
| 37 | - **Where is the artifact?** Path to binary or dist folder | ||
| 38 | - **What host?** Default unless specified | ||
| 39 | - **Any env vars needed?** Especially for first-time deploys | ||
| 40 | - **Custom domain?** Or use `<app-name>.<base-domain>` | ||
| 41 | |||
| 42 | If any of these are unclear, ask before proceeding. | ||
| 43 | |||
| 44 | ## Step 2 — Check if app already exists | ||
| 45 | |||
| 46 | ```bash | ||
| 47 | ssh <host> "test -f /etc/ship/ports/<app-name> && echo exists || echo new" | ||
| 48 | ``` | ||
| 49 | |||
| 50 | Tell the user whether this is a fresh deploy or an update to an existing app. | ||
| 51 | |||
| 52 | ## Step 3 — Deploy | ||
| 53 | |||
| 54 | ### For a binary app → follow ship-binary | ||
| 55 | |||
| 56 | Key steps in order: | ||
| 57 | 1. Backup any SQLite databases in `/var/lib/<app-name>/` | ||
| 58 | 2. Allocate or retrieve port | ||
| 59 | 3. Upload binary via scp | ||
| 60 | 4. Write/merge env file | ||
| 61 | 5. Write systemd unit | ||
| 62 | 6. `systemctl restart` (existing) or `systemctl enable --now` (new) | ||
| 63 | 7. Write Caddy config and reload | ||
| 64 | |||
| 65 | ### For a static site → follow ship-static | ||
| 66 | |||
| 67 | Key steps in order: | ||
| 68 | 1. Validate `index.html` exists in dist folder | ||
| 69 | 2. Rsync dist folder to `/var/www/<app-name>/` | ||
| 70 | 3. Fix ownership to `www-data` | ||
| 71 | 4. Write Caddy config and reload | ||
| 72 | |||
| 73 | ## Step 4 — Verify | ||
| 74 | |||
| 75 | After deploying, confirm the service came up: | ||
| 76 | |||
| 77 | **Binary:** | ||
| 78 | ```bash | ||
| 79 | ssh <host> "sudo systemctl is-active <app-name>" | ||
| 80 | ``` | ||
| 81 | |||
| 82 | If not active, immediately check logs: | ||
| 83 | ```bash | ||
| 84 | ssh <host> "sudo journalctl -u <app-name> -n 30 --no-pager" | ||
| 85 | ``` | ||
| 86 | |||
| 87 | **Static:** | ||
| 88 | ```bash | ||
| 89 | ssh <host> "curl -sI https://<domain> | head -5" | ||
| 90 | ``` | ||
| 91 | |||
| 92 | ## Step 5 — Confirm to user | ||
| 93 | |||
| 94 | Report: | ||
| 95 | - App name and live URL | ||
| 96 | - Type (binary / static) | ||
| 97 | - New deploy or update | ||
| 98 | - Port (binary only) | ||
| 99 | - Any SQLite backups made | ||
| 100 | - Any env vars that were set | ||
| 101 | - Whether the service is running | ||
| 102 | |||
| 103 | ## Checklist (reference) | ||
| 104 | |||
| 105 | Use this to make sure nothing is missed: | ||
| 106 | |||
| 107 | - [ ] Config file read, host resolved | ||
| 108 | - [ ] App type confirmed (binary / static) | ||
| 109 | - [ ] Artifact path confirmed and exists locally | ||
| 110 | - [ ] App name and domain confirmed | ||
| 111 | - [ ] Existing app check done | ||
| 112 | - [ ] SQLite backed up (binary, if db files exist) | ||
| 113 | - [ ] Port allocated or retrieved | ||
| 114 | - [ ] Artifact uploaded | ||
| 115 | - [ ] Env file written with merge semantics | ||
| 116 | - [ ] Systemd unit written and service started/restarted (binary) | ||
| 117 | - [ ] Caddy config written and reloaded | ||
| 118 | - [ ] Service confirmed running | ||
| 119 | |||
| 120 | ## Notes | ||
| 121 | |||
| 122 | - Never skip the SQLite backup step for binary apps — always check even if you don't expect a db | ||
| 123 | - Always merge env vars — never overwrite the whole env file | ||
| 124 | - If anything fails mid-deploy, tell the user exactly where it failed and what state the server is in | ||
| 125 | - Use `systemctl restart` for existing apps, `enable --now` for new ones — not the other way around | ||
| 126 | - If the user says "deploy X" without more context, ask the minimum necessary questions before starting | ||
