aboutsummaryrefslogtreecommitdiffstats
path: root/skills/ship-deploy
diff options
context:
space:
mode:
Diffstat (limited to 'skills/ship-deploy')
-rw-r--r--skills/ship-deploy/SKILL.md126
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---
2name: ship-deploy
3description: 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.
4argument-hint: "<app-name> [host-nickname]"
5---
6
7# ship-deploy
8
9Orchestration runbook for deploying apps to a ship VPS. Guides the full deployment
10process 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
21python3 -c "
22import json, os
23cfg = json.load(open(os.path.expanduser('~/.config/ship/config.json')))
24nick = '<nickname-or-default>'
25h = cfg['hosts'].get(nick, cfg['hosts'][cfg['default']])
26print(h['host'])
27print(h['domain'])
28"
29```
30
31## Step 1 — Understand what we're deploying
32
33Ask 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
42If any of these are unclear, ask before proceeding.
43
44## Step 2 — Check if app already exists
45
46```bash
47ssh <host> "test -f /etc/ship/ports/<app-name> && echo exists || echo new"
48```
49
50Tell 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
56Key steps in order:
571. Backup any SQLite databases in `/var/lib/<app-name>/`
582. Allocate or retrieve port
593. Upload binary via scp
604. Write/merge env file
615. Write systemd unit
626. `systemctl restart` (existing) or `systemctl enable --now` (new)
637. Write Caddy config and reload
64
65### For a static site → follow ship-static
66
67Key steps in order:
681. Validate `index.html` exists in dist folder
692. Rsync dist folder to `/var/www/<app-name>/`
703. Fix ownership to `www-data`
714. Write Caddy config and reload
72
73## Step 4 — Verify
74
75After deploying, confirm the service came up:
76
77**Binary:**
78```bash
79ssh <host> "sudo systemctl is-active <app-name>"
80```
81
82If not active, immediately check logs:
83```bash
84ssh <host> "sudo journalctl -u <app-name> -n 30 --no-pager"
85```
86
87**Static:**
88```bash
89ssh <host> "curl -sI https://<domain> | head -5"
90```
91
92## Step 5 — Confirm to user
93
94Report:
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
105Use 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