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-status/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-status/SKILL.md')
| -rw-r--r-- | skills/ship-status/SKILL.md | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/skills/ship-status/SKILL.md b/skills/ship-status/SKILL.md new file mode 100644 index 0000000..f47e081 --- /dev/null +++ b/skills/ship-status/SKILL.md | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | --- | ||
| 2 | name: ship-status | ||
| 3 | description: Show what's running on a ship VPS. Derives state from the server — no local state file. Use when you want to know what apps are deployed, what ports they use, and whether they're running. | ||
| 4 | argument-hint: "[host-nickname]" | ||
| 5 | --- | ||
| 6 | |||
| 7 | # ship-status | ||
| 8 | |||
| 9 | Show the current state of all deployments on a ship VPS by reading directly from the server. | ||
| 10 | |||
| 11 | ## Read Config | ||
| 12 | |||
| 13 | Load the host from `~/.config/ship/config.json`. Use the default host unless a nickname was specified: | ||
| 14 | |||
| 15 | ```bash | ||
| 16 | python3 -c " | ||
| 17 | import json, os, sys | ||
| 18 | cfg = json.load(open(os.path.expanduser('~/.config/ship/config.json'))) | ||
| 19 | nick = sys.argv[1] if len(sys.argv) > 1 else cfg['default'] | ||
| 20 | h = cfg['hosts'][nick] | ||
| 21 | print(h['host']) | ||
| 22 | print(h['domain']) | ||
| 23 | " <nickname-or-blank> | ||
| 24 | ``` | ||
| 25 | |||
| 26 | ## Gather Server State | ||
| 27 | |||
| 28 | Run all of these in a single SSH session to minimize round trips: | ||
| 29 | |||
| 30 | **Systemd services (binary/docker apps):** | ||
| 31 | ```bash | ||
| 32 | ssh <host> "systemctl list-units --type=service --state=active --no-pager --no-legend | grep -v '@' | awk '{print \$1}' | xargs -I{} sh -c 'name=\$(echo {} | sed s/.service//); port=\$(cat /etc/ship/ports/\$name 2>/dev/null); env=\$(cat /etc/ship/env/\$name.env 2>/dev/null | grep SHIP_URL | cut -d= -f2); echo \"\$name|\$port|\$env\"' 2>/dev/null | grep '|'" | ||
| 33 | ``` | ||
| 34 | |||
| 35 | **Static sites:** | ||
| 36 | ```bash | ||
| 37 | ssh <host> "ls /var/www/ 2>/dev/null" | ||
| 38 | ``` | ||
| 39 | |||
| 40 | **Caddy configs (domains):** | ||
| 41 | ```bash | ||
| 42 | ssh <host> "ls /etc/caddy/sites-enabled/ 2>/dev/null | grep -v '^$'" | ||
| 43 | ``` | ||
| 44 | |||
| 45 | **Caddy status:** | ||
| 46 | ```bash | ||
| 47 | ssh <host> "systemctl is-active caddy" | ||
| 48 | ``` | ||
| 49 | |||
| 50 | **Disk usage for app data dirs:** | ||
| 51 | ```bash | ||
| 52 | ssh <host> "du -sh /var/lib/*/ 2>/dev/null" | ||
| 53 | ``` | ||
| 54 | |||
| 55 | ## Present Results | ||
| 56 | |||
| 57 | Format as a clean summary, for example: | ||
| 58 | |||
| 59 | ``` | ||
| 60 | HOST: prod (ubuntu@1.2.3.4) | ||
| 61 | |||
| 62 | SERVICES | ||
| 63 | foodtracker running :9013 https://foodtracker.example.com | ||
| 64 | myapi running :9014 https://api.example.com | ||
| 65 | |||
| 66 | STATIC SITES | ||
| 67 | mysite https://mysite.example.com | ||
| 68 | |||
| 69 | CADDY: running | ||
| 70 | |||
| 71 | DATA | ||
| 72 | /var/lib/foodtracker/ 48M | ||
| 73 | /var/lib/myapi/ 2M | ||
| 74 | ``` | ||
| 75 | |||
| 76 | If a service appears in `/etc/ship/ports/` but is not active in systemd, flag it as **stopped**. | ||
| 77 | |||
| 78 | If a Caddy config exists for a name but no service or static site matches, flag it as **orphaned config**. | ||
| 79 | |||
| 80 | ## Notes | ||
| 81 | |||
| 82 | - No local state file is consulted — everything comes from the server | ||
| 83 | - If `~/.config/ship/config.json` doesn't exist, tell the user to run `/ship-setup` first | ||
| 84 | - If a nickname is given that doesn't exist in config, list available nicknames | ||
| 85 | - Use default host if no argument given | ||
