prizmkit 1.1.39 → 1.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +1 -1
- package/bundled/dev-pipeline/run-bugfix.sh +74 -0
- package/bundled/dev-pipeline/run-feature.sh +74 -0
- package/bundled/dev-pipeline/run-refactor.sh +74 -0
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +0 -6
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +118 -1
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +123 -8
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +0 -23
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +0 -23
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +0 -23
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +22 -3
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +56 -0
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +64 -4
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +22 -3
- package/bundled/dev-pipeline/tests/test-deploy-safety.sh +223 -0
- package/bundled/skills/_metadata.json +3 -3
- package/bundled/skills/app-planner/SKILL.md +0 -3
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +34 -6
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +42 -18
- package/bundled/skills/prizmkit-committer/SKILL.md +0 -1
- package/bundled/skills/prizmkit-deploy/SKILL.md +491 -209
- package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +93 -0
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +147 -0
- package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +62 -0
- package/bundled/skills/prizmkit-deploy/references/docker-deploy.md +31 -0
- package/bundled/skills/prizmkit-deploy/references/nginx-blue-green.md +59 -0
- package/bundled/skills/prizmkit-init/SKILL.md +0 -2
- package/bundled/skills/prizmkit-plan/SKILL.md +0 -3
- package/bundled/skills/recovery-workflow/SKILL.md +96 -7
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +40 -9
- package/package.json +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +0 -31
- package/bundled/skills/prizmkit-deploy/assets/deploy-template.md +0 -187
|
@@ -1,214 +1,496 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "prizmkit-deploy"
|
|
3
|
-
description: "
|
|
3
|
+
description: "Universal deployment gateway for any PrizmKit project. Discovers project type and target (SSH server, Vercel, Docker, etc.), then routes: full automation for SSH Linux with PM2 + Nginx + blue/green switching, guided setup for cloud platforms, or safe documentation fallback for unsupported targets. Also operates existing deployments: status, logs, restart, rollback, health checks, history. Trigger on: 'deploy', 'deploy my app', 'help me deploy', 'ship it', 'take this live', 'deploy to Vercel', 'deploy to my server', 'how do I deploy this', any deployment or hosting question."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# PrizmKit Deploy
|
|
6
|
+
# PrizmKit Deploy — Universal Deployment Gateway
|
|
7
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
|
-
|
|
8
|
+
`/prizmkit-deploy` is the single entry point for all deployment work. When a user asks to deploy anything — any project type, any target — this skill handles it.
|
|
9
|
+
|
|
10
|
+
Three possible outcomes depending on what's supported:
|
|
11
|
+
1. **Full automation** (SSH Linux server): configure, bootstrap, deploy, verify, operate — complete AI takeover.
|
|
12
|
+
2. **Guided setup** (cloud platforms like Vercel, Netlify, Docker): generate config, walk through CLI steps, verify.
|
|
13
|
+
3. **Documented fallback** (unsupported targets): detect what's possible, produce deploy.md, record the adapter gap.
|
|
14
|
+
|
|
15
|
+
When invited, behave as a deployment engineer. Ask until you understand what is being deployed, where it runs, how it is built, how it starts, what secrets it needs, how traffic reaches it, and how health is checked.
|
|
16
|
+
|
|
17
|
+
## Deployment Discovery
|
|
18
|
+
|
|
19
|
+
Before doing anything else, discover what you're deploying and where. This phase routes the request to the right adapter or fallback. It runs regardless of mode (interactive or headless), but interactive mode may ask questions; headless mode reads from existing config and exits with `NEEDS_INPUT` if critical details are missing.
|
|
20
|
+
|
|
21
|
+
### Step 1: Project Detection
|
|
22
|
+
|
|
23
|
+
Scan the project root for build/package files and classify:
|
|
24
|
+
|
|
25
|
+
| File found | Language/Framework | Build command | Start command |
|
|
26
|
+
|------------|-------------------|---------------|---------------|
|
|
27
|
+
| `package.json` with `next` dep | Next.js | `next build` | `next start -p <port>` |
|
|
28
|
+
| `package.json` with `vite` dep | Vite (React/Vue) | `vite build` | `vite preview` |
|
|
29
|
+
| `package.json` (generic) | Node.js | `npm run build` | `npm run start` |
|
|
30
|
+
| `go.mod` | Go | `go build` | `./<binary>` |
|
|
31
|
+
| `Cargo.toml` | Rust | `cargo build --release` | `./target/release/<binary>` |
|
|
32
|
+
| `requirements.txt` / `pyproject.toml` | Python | — | `python -m uvicorn` or similar |
|
|
33
|
+
| `Dockerfile` | Containerized | `docker build` | `docker run` |
|
|
34
|
+
| `docker-compose.yml` | Docker Compose | `docker compose build` | `docker compose up` |
|
|
35
|
+
| `Makefile` only | C/C++/generic | `make` | `make run` or binary |
|
|
36
|
+
|
|
37
|
+
Also scan for:
|
|
38
|
+
- **Environment variables**: grep for `process.env.`, `os.environ`, `os.Getenv`, `env::var` — catalog every reference
|
|
39
|
+
- **Port usage**: grep for port numbers, `listen()`, `PORT` env var
|
|
40
|
+
- **Database dependencies**: check package.json/requirements.txt/go.mod for database drivers
|
|
41
|
+
|
|
42
|
+
### Step 2: Deployment Target Detection
|
|
43
|
+
|
|
44
|
+
Determine WHERE the user wants to deploy. Check in order:
|
|
45
|
+
|
|
46
|
+
**A. User-specified target** (highest priority):
|
|
47
|
+
- "deploy to Vercel" / "deploy to my server" / "deploy with Docker" → use what the user says.
|
|
48
|
+
|
|
49
|
+
**B. Detect from project files** (if user hasn't specified):
|
|
50
|
+
- `vercel.json` → Vercel
|
|
51
|
+
- `netlify.toml` → Netlify
|
|
52
|
+
- `fly.toml` → Fly.io
|
|
53
|
+
- `Dockerfile` or `docker-compose.yml` → Docker
|
|
54
|
+
- `.github/workflows/deploy.yml` → check what it targets
|
|
55
|
+
- `app.yaml` → GCP App Engine
|
|
56
|
+
- `serverless.yml` → Serverless Framework
|
|
57
|
+
|
|
58
|
+
**C. Ask the user** (interactive only):
|
|
59
|
+
- "Where should this project be deployed?"
|
|
60
|
+
- Options to suggest based on detected files + common choices:
|
|
61
|
+
- "My own Linux server (SSH access) — full AI automation"
|
|
62
|
+
- "Vercel / Netlify — guided CLI setup"
|
|
63
|
+
- "Docker — guided container deployment"
|
|
64
|
+
- "Other — generate deployment documentation"
|
|
65
|
+
|
|
66
|
+
If headless mode and no target can be determined, exit with `NEEDS_INPUT` listing the missing target information.
|
|
67
|
+
|
|
68
|
+
**D. Check for existing deployment**:
|
|
69
|
+
- Does `.prizmkit/deploy/deploy.config.json` already exist? If yes, read the configured target.
|
|
70
|
+
- Does the user mention a server IP or hostname? Check if it's already reachable.
|
|
71
|
+
|
|
72
|
+
### Step 3: Route to Adapter
|
|
73
|
+
|
|
74
|
+
Based on detected target, route the rest of the session:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
SSH Linux server → §SSH Deployment Path (full automation)
|
|
78
|
+
bootstrap, configure, deploy, operate
|
|
79
|
+
First-version: PM2 + Nginx + blue/green
|
|
80
|
+
|
|
81
|
+
Vercel / Netlify → §Cloud Platform Deployment Path (guided)
|
|
82
|
+
detect CLI tools, walk through deploy commands,
|
|
83
|
+
generate deploy.md with platform-specific steps
|
|
84
|
+
|
|
85
|
+
Docker → §Docker Deployment Path (guided)
|
|
86
|
+
detect Dockerfile/Compose, build image,
|
|
87
|
+
container lifecycle (run, stop, logs, restart)
|
|
88
|
+
|
|
89
|
+
Unsupported → §Unsupported Deployment Fallback
|
|
90
|
+
generate deploy.md with detected info,
|
|
91
|
+
record missing adapter gap,
|
|
92
|
+
provide manual deployment checklist
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The SSH path is fully documented in the sections below. Cloud and Docker paths follow the same discovery and documentation patterns but use platform CLIs instead of SSH + PM2.
|
|
96
|
+
|
|
97
|
+
**Compatibility check before routing to SSH**: The SSH adapter (PM2 + Nginx + blue/green) requires a Node.js project — verify `package.json` exists. Non-Node.js projects (Go, Rust, Python) targeting a Linux server route to Unsupported Fallback with a note: "Adapter gap: PM2 adapter requires Node.js."
|
|
98
|
+
|
|
99
|
+
### Step 4: Unsupported Deployment Fallback
|
|
100
|
+
|
|
101
|
+
When the deployment target or project type isn't covered by any adapter, don't fail silently. Instead:
|
|
102
|
+
|
|
103
|
+
1. **Detect what you can**: project language, framework, build/start commands, env vars, port usage, database dependencies.
|
|
104
|
+
2. **Generate `.prizmkit/deploy/deploy.md`**: human-readable deployment guide with:
|
|
105
|
+
- Prerequisites (tools, accounts, versions)
|
|
106
|
+
- Environment variables table (detected from code scan)
|
|
107
|
+
- Build and start instructions
|
|
108
|
+
- Health check suggestions
|
|
109
|
+
- Platform-specific tips if the target is partially recognized
|
|
110
|
+
3. **Record the adapter gap**: write a note in deploy.md and deploy-history identifying what's missing (e.g., "Adapter needed: Python/FastAPI on systemd", "Adapter needed: Go binary deployment").
|
|
111
|
+
4. **Provide a manual checklist**: concrete steps the user can follow to deploy manually.
|
|
112
|
+
5. **Offer to generate CI/CD config**: if `.github/workflows/` exists or the user wants one, generate a basic deploy workflow.
|
|
113
|
+
|
|
114
|
+
This ensures every deployment request produces useful output, even when full automation isn't available yet.
|
|
115
|
+
|
|
116
|
+
## Mode Detection
|
|
117
|
+
|
|
118
|
+
Detect invocation mode from the user's initial message. The mode determines what you're allowed to do:
|
|
119
|
+
|
|
120
|
+
**Interactive mode** (user typed `/prizmkit-deploy` or asked directly):
|
|
121
|
+
- May ask as many questions as needed to fill in missing deployment details.
|
|
122
|
+
- May request approvals for privileged, destructive, or traffic-impacting actions.
|
|
123
|
+
- May deploy to any environment (dev/test/production).
|
|
124
|
+
- Production requires explicit user confirmation before execution.
|
|
125
|
+
|
|
126
|
+
**Headless mode** (invoked via `--headless` flag, pipeline, or script):
|
|
127
|
+
- Must never wait for user input or prompt — unattended shells timing out on a prompt blocks pipelines silently.
|
|
128
|
+
- May ONLY target `dev` or `test` environments.
|
|
129
|
+
- If `--env production` in headless mode: exit immediately with `ENVIRONMENT_DENIED — production deployment requires interactive mode`.
|
|
130
|
+
- If required info is missing, exit with `NEEDS_INPUT` and write pending questions to `.prizmkit/deploy/pending-input.json`.
|
|
131
|
+
- May only perform actions already authorized by `deploy.config.json`.
|
|
132
|
+
|
|
133
|
+
## Command Routing
|
|
134
|
+
|
|
135
|
+
When the user invokes `/prizmkit-deploy`, determine intent from the first word after the command:
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
/prizmkit-deploy → deploy (if config exists) or configure (if not)
|
|
139
|
+
/prizmkit-deploy configure → first-run or repair configuration wizard
|
|
140
|
+
/prizmkit-deploy deploy → full deployment pipeline
|
|
141
|
+
/prizmkit-deploy status → show PM2 process status for all apps
|
|
142
|
+
/prizmkit-deploy logs --app <id> → tail PM2 logs for the given app
|
|
143
|
+
/prizmkit-deploy restart --app <id> → PM2 restart for the given app
|
|
144
|
+
/prizmkit-deploy rollback --app <id> [--to <releaseId>] → rollback to previous or specified release
|
|
145
|
+
/prizmkit-deploy health --app <id> → run configured health checks
|
|
146
|
+
/prizmkit-deploy history → list recent deployment events from deploy-history/
|
|
147
|
+
/prizmkit-deploy validate → run validation checks without deploying
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### No-arg behavior
|
|
151
|
+
|
|
152
|
+
- If `.prizmkit/deploy/deploy.config.json` does not exist → start first-run configuration wizard.
|
|
153
|
+
- If config exists and validates → show deployment summary (active release, app status, last deploy time) and ask which environment, then proceed to deploy.
|
|
154
|
+
- If config exists but required fields are missing or validation is stale → enter repair flow.
|
|
155
|
+
|
|
156
|
+
## File Structure
|
|
157
|
+
|
|
158
|
+
All artifacts live under `.prizmkit/deploy/`:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
.prizmkit/deploy/
|
|
162
|
+
deploy.md # human-readable documentation
|
|
163
|
+
deploy.config.json # machine-readable config & validation state
|
|
164
|
+
pending-input.json # pending questions for headless mode resume
|
|
165
|
+
deploy-history/
|
|
166
|
+
<deployment-id>.json # one per deploy/rollback/event
|
|
167
|
+
deploy-scripts/ # future — currently unused, place for PrizmKit-managed deploy scripts and templates
|
|
168
|
+
secrets.enc.json # optional, encrypted local secrets
|
|
169
|
+
secrets.local.json # optional, plaintext secrets (must be gitignored)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The full `deploy.config.json` schema is documented in `references/deploy-config-schema.md`. Read it when writing or validating config.
|
|
173
|
+
|
|
174
|
+
## SSH Deployment Path (Full Automation)
|
|
175
|
+
|
|
176
|
+
The following sections — Server Model through Multi-App Coordination — define the SSH deployment adapter. This is the only fully-automated path in the first version. Route here when Discovery determines the target is a Linux server with SSH access.
|
|
177
|
+
|
|
178
|
+
### SSH: Server Model
|
|
179
|
+
|
|
180
|
+
Servers are generic SSH targets. A server is valid if it:
|
|
181
|
+
- Can be reached over SSH.
|
|
182
|
+
- Provides a Linux shell.
|
|
183
|
+
- Can install or has Node.js, npm, PM2, Nginx, Git.
|
|
184
|
+
- Can access the configured Git repository.
|
|
185
|
+
|
|
186
|
+
Server-side directory layout:
|
|
187
|
+
```
|
|
188
|
+
/var/www/<project>/
|
|
189
|
+
releases/
|
|
190
|
+
<release-id>/
|
|
191
|
+
shared/
|
|
192
|
+
.env.production # mode 600, owner: runtime user
|
|
193
|
+
deploy-metadata.json # active color, last release, timestamp
|
|
194
|
+
current -> releases/<release-id>
|
|
195
|
+
deploy-logs/
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
SSH roles: `bootstrapUser` (usually root, for initial setup) and `runtimeUser` (default `deploy`, for app processes). App processes never run as root.
|
|
199
|
+
|
|
200
|
+
### SSH: First-Run Configuration Wizard
|
|
201
|
+
|
|
202
|
+
When `.prizmkit/deploy/deploy.config.json` does not exist, enter configuration wizard. The flow is: **collect → validate → confirm → persist**.
|
|
203
|
+
|
|
204
|
+
#### Step 1: SSH Server Discovery
|
|
205
|
+
|
|
206
|
+
Ask for and validate:
|
|
207
|
+
- **Server host and port** (e.g., `43.161.221.171:22`)
|
|
208
|
+
- **Bootstrap user** (usually `root`) — used for initial package install and user creation
|
|
209
|
+
- **Runtime user** (recommend `deploy`) — app runs as this user, never root
|
|
210
|
+
- **Auth method** — SSH key path or agent
|
|
211
|
+
|
|
212
|
+
Validate immediately: `ssh <bootstrapUser>@<host> 'echo OK'`. If that fails, nothing else matters — stop and fix connectivity first.
|
|
213
|
+
|
|
214
|
+
#### Step 2: Repository Access
|
|
215
|
+
|
|
216
|
+
Ask for and validate:
|
|
217
|
+
- **Git URL** (e.g., `git@github.com:owner/repo.git`)
|
|
218
|
+
- **Branch** (e.g., `master`)
|
|
219
|
+
- **Auth strategy** — prefer read-only Deploy Key
|
|
220
|
+
|
|
221
|
+
If using Deploy Key:
|
|
222
|
+
1. Generate ed25519 key on server: `sudo -u <runtimeUser> ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""`
|
|
223
|
+
2. Show the public key to the user with explicit instruction: "Add this to GitHub Deploy Keys (read-only)"
|
|
224
|
+
3. Wait for user confirmation, then verify: attempt a git clone as runtime user
|
|
225
|
+
|
|
226
|
+
#### Step 3: Application Configuration
|
|
227
|
+
|
|
228
|
+
For each app, collect:
|
|
229
|
+
- **id** — short name (e.g., `web`)
|
|
230
|
+
- **path** — relative path within repo
|
|
231
|
+
- **packageManager** — npm / yarn / pnpm
|
|
232
|
+
- **installCommand** — `npm ci` / `yarn install` etc.
|
|
233
|
+
- **buildCommand** — `npm run build` etc.
|
|
234
|
+
- **startCommand** — `npm run start` etc.
|
|
235
|
+
- **ports** — blue/green port pair (default 3101/3102)
|
|
236
|
+
- **healthChecks** — list of `{ name, url, expectedStatus[] }`
|
|
237
|
+
|
|
238
|
+
#### Step 4: Environment Variables
|
|
239
|
+
|
|
240
|
+
- Scan source code for `process.env.<VAR>` references.
|
|
241
|
+
- Ask user for each required value.
|
|
242
|
+
- Identify which are secrets (API keys, tokens) vs. non-secrets (URLs, anon keys).
|
|
243
|
+
- Ask about secret storage strategy (see Secrets Management below).
|
|
244
|
+
|
|
245
|
+
#### Step 5: Persist Configuration
|
|
246
|
+
|
|
247
|
+
Write `deploy.config.json` with all collected values and `validated: {}` stubs for each section. Write `deploy.md` as human-readable documentation.
|
|
248
|
+
|
|
249
|
+
### SSH: Bootstrap Flow
|
|
250
|
+
|
|
251
|
+
Before first deployment, bootstrap the server. Present a plan to the user showing every privileged action before executing anything.
|
|
252
|
+
|
|
253
|
+
**Always-run preflight:**
|
|
254
|
+
```
|
|
255
|
+
locale-gen en_US.UTF-8 # fix locale warnings on bare Ubuntu
|
|
256
|
+
apt-get update -qq # refresh package list
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Check-and-install (idempotent):**
|
|
260
|
+
- **Node.js**: check `node --version`. If missing or too old, install via NodeSource. Use v22 LTS if v25 not available — that's fine for most projects.
|
|
261
|
+
- **npm**: verify separately from node (`which npm`). On minimal installs, npm may be a separate package.
|
|
262
|
+
- **PM2**: `npm install -g pm2` if missing.
|
|
263
|
+
- **Nginx**: `apt-get install -y nginx` if missing.
|
|
264
|
+
- **Git**: `apt-get install -y git` if missing.
|
|
265
|
+
|
|
266
|
+
**Detect port conflicts before starting Nginx:**
|
|
267
|
+
```
|
|
268
|
+
ss -tlnp | grep :80 || true
|
|
269
|
+
```
|
|
270
|
+
If port 80/443 is occupied, report what's using it and ask how to resolve.
|
|
271
|
+
|
|
272
|
+
**User and directory setup:**
|
|
273
|
+
```
|
|
274
|
+
useradd -m -s /bin/bash <runtimeUser> # if not exists
|
|
275
|
+
mkdir -p /var/www/<project>/{releases,shared,deploy-logs}
|
|
276
|
+
chown -R <runtimeUser>:<runtimeUser> /var/www/<project>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**PM2 startup:**
|
|
280
|
+
```
|
|
281
|
+
env PATH=$PATH:/usr/bin pm2 startup systemd -u <runtimeUser> --hp /home/<runtimeUser>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Deploy key (if strategy is deploy-key):**
|
|
285
|
+
```
|
|
286
|
+
sudo -u <runtimeUser> ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
|
|
287
|
+
sudo -u <runtimeUser> ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
After each bootstrap step, record the result. Bootstrap operations must be idempotent. Back up any existing config files before modifying them.
|
|
291
|
+
|
|
292
|
+
### SSH: Deployment Execution Flow
|
|
293
|
+
|
|
294
|
+
Pipeline runs in strict order. Each group must complete before the next begins. If any step before traffic switch fails, STOP — do not touch the live version.
|
|
295
|
+
|
|
296
|
+
**Group 1 — Pre-flight & Prepare:**
|
|
297
|
+
- Verify SSH, runtime user, tools, deploy key, port availability.
|
|
298
|
+
- Generate `releaseId`: `YYYYMMDD-<short-commit-sha>`. Create `releases/<releaseId>`.
|
|
299
|
+
- Determine target color: read `activeColor` from `shared/deploy-metadata.json` and use the opposite. If first deploy (no metadata, no `current` symlink), default to blue (port 3101).
|
|
300
|
+
|
|
301
|
+
**Group 2 — Fetch & Build:**
|
|
302
|
+
- `git clone <repoUrl> --branch <branch> releases/<releaseId>` as runtime user.
|
|
303
|
+
- `cd releases/<releaseId> && <installCommand>` as runtime user.
|
|
304
|
+
- Copy `.env.production` from `shared/` into release dir BEFORE build — `NEXT_PUBLIC_*` vars are baked at build time.
|
|
305
|
+
- Run `<buildCommand>`. If build fails: STOP.
|
|
306
|
+
|
|
307
|
+
**Group 3 — Stage & Health Check:**
|
|
308
|
+
- Start new version on the inactive port via PM2: `pm2 start npm --name <project>-<app>-<color> -- run start -- -p <inactivePort>`.
|
|
309
|
+
- PM2 process naming: `<project>-<app>-<color>` (e.g., `prizm-ideas-web-green`).
|
|
310
|
+
- Wait 3-5 seconds, run health checks against new port. If any fails: STOP. Do NOT switch traffic. Record failure.
|
|
311
|
+
|
|
312
|
+
**Group 4 — Switch & Verify:**
|
|
313
|
+
- Update Nginx upstream to new port. Run `nginx -t` — abort on failure.
|
|
314
|
+
- `systemctl reload nginx`. Update `current` symlink to new release.
|
|
315
|
+
- Write `shared/deploy-metadata.json` with new `activeColor`, `activePort`, `lastReleaseId`.
|
|
316
|
+
- Run health checks against public endpoint. If any fails: rollback immediately (switch Nginx back, restart old PM2).
|
|
317
|
+
|
|
318
|
+
**Group 5 — Cleanup & Record:**
|
|
319
|
+
- Stop old PM2 process. Remove oldest releases beyond `releaseRetention` count. `pm2 save`.
|
|
320
|
+
- Write deploy-history JSON to `.prizmkit/deploy/deploy-history/<releaseId>.json` (schema: `references/deploy-history-schema.md`).
|
|
321
|
+
- Update `deploy.config.json` with new validation status.
|
|
322
|
+
|
|
323
|
+
### SSH: Blue/Green PM2 + Nginx Strategy
|
|
324
|
+
|
|
325
|
+
The active color (blue or green) maps to a port:
|
|
326
|
+
- Blue: port 3101 (default)
|
|
327
|
+
- Green: port 3102 (default)
|
|
328
|
+
|
|
329
|
+
Active color is persisted in `/var/www/<project>/shared/deploy-metadata.json`. If metadata is missing, rediscover from Nginx `proxy_pass` directive or from running PM2 processes.
|
|
330
|
+
|
|
331
|
+
PM2 process naming: `<project>-<app>-<color>` (deterministic, never reuse old release IDs in names).
|
|
332
|
+
|
|
333
|
+
Nginx config must include the PrizmKit managed marker:
|
|
334
|
+
```
|
|
335
|
+
# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Before modifying any Nginx config that lacks this marker, ask for user confirmation.
|
|
339
|
+
|
|
340
|
+
Always `nginx -t` before `systemctl reload nginx`. If syntax check fails, abort.
|
|
341
|
+
|
|
342
|
+
### SSH: Rollback
|
|
343
|
+
|
|
344
|
+
Two rollback triggers:
|
|
345
|
+
1. **Automatic**: health check failure after traffic switch → roll back immediately.
|
|
346
|
+
2. **Manual**: `/prizmkit-deploy rollback --app <id> [--to <releaseId>]`
|
|
347
|
+
|
|
348
|
+
Rollback steps:
|
|
349
|
+
1. Identify target release: `--to <releaseId>` or discover previous release from deploy history.
|
|
350
|
+
2. Verify target release directory exists and has a valid build.
|
|
351
|
+
3. Determine which port the target release used (from deploy history or release metadata).
|
|
352
|
+
4. Start the target PM2 process on its port (if not already running).
|
|
353
|
+
5. Update Nginx upstream to target port, run `nginx -t`, reload.
|
|
354
|
+
6. Run health checks against the restored version.
|
|
355
|
+
7. Write a rollback event to deploy history.
|
|
356
|
+
8. Do NOT delete the failed release or its logs — preserve for debugging.
|
|
357
|
+
|
|
358
|
+
If no previous release exists (first deployment), rollback is not possible — state this clearly.
|
|
359
|
+
|
|
360
|
+
### SSH: Operations Commands
|
|
361
|
+
|
|
362
|
+
#### status
|
|
363
|
+
SSH to server and run `pm2 list` as runtime user. Also show:
|
|
364
|
+
- Active release (from `current` symlink target)
|
|
365
|
+
- Active color/port (from `deploy-metadata.json`)
|
|
366
|
+
- Last deploy timestamp
|
|
367
|
+
|
|
368
|
+
#### logs --app <id>
|
|
369
|
+
SSH to server and run `pm2 logs <process-name> --lines 100` as runtime user.
|
|
370
|
+
|
|
371
|
+
#### restart --app <id>
|
|
372
|
+
1. Identify the active PM2 process for the app.
|
|
373
|
+
2. Run `pm2 restart <process-name>` as runtime user.
|
|
374
|
+
3. Wait for process to come online.
|
|
375
|
+
4. Run health checks to verify recovery.
|
|
376
|
+
|
|
377
|
+
#### health --app <id>
|
|
378
|
+
Run all configured health checks for the app against the public endpoint. Report pass/fail for each.
|
|
379
|
+
|
|
380
|
+
#### history
|
|
381
|
+
Read `.prizmkit/deploy/deploy-history/` directory, list events chronologically. Show event type, release ID, commit SHA, timestamp, status.
|
|
382
|
+
|
|
383
|
+
## Environment Policy
|
|
384
|
+
|
|
385
|
+
| Mode | dev | test | production |
|
|
386
|
+
|------|-----|------|------------|
|
|
387
|
+
| Interactive | Allowed | Allowed | Allowed (requires confirmation) |
|
|
388
|
+
| Headless | Allowed | Allowed | **REJECTED** — exits with ENVIRONMENT_DENIED |
|
|
389
|
+
|
|
390
|
+
This is non-negotiable. Even if config allows it, headless must reject production.
|
|
391
|
+
|
|
392
|
+
## Secrets Management
|
|
393
|
+
|
|
394
|
+
Four storage modes, configured during first-run wizard:
|
|
395
|
+
|
|
396
|
+
- **ask-every-time**: Prompt for secrets on each deploy. Safest, most manual.
|
|
397
|
+
- **encrypted-local**: Store in `.prizmkit/deploy/secrets.enc.json`. Encrypt with user passphrase using Argon2id/scrypt KDF. Decryption material never stored alongside ciphertext.
|
|
398
|
+
- **plaintext-local**: Store in `.prizmkit/deploy/secrets.local.json`. Must be gitignored. Before each deploy, verify the file is not tracked by git. If tracked, stop and ask to resolve.
|
|
399
|
+
- **user-managed-on-server-only**: User handles secrets manually. Skill verifies server-side `.env.production` has all required vars before deploying.
|
|
400
|
+
|
|
401
|
+
Server runtime secrets live in `/var/www/<project>/shared/.env.production` with mode `600`, owned by runtime user.
|
|
402
|
+
|
|
403
|
+
Deploy history records secret presence metadata only (e.g., `{"SUPABASE_SERVICE_ROLE_KEY": {"present": true}}`). Never record raw secret values or unsalted hashes.
|
|
404
|
+
|
|
405
|
+
### SSH: Existing Deployment Takeover
|
|
406
|
+
|
|
407
|
+
When deploying to a server that already has deployment assets:
|
|
408
|
+
|
|
409
|
+
1. Detect: existing `/var/www/<project>` directory, existing PM2 processes with similar names, Nginx config referencing the same domain/IP, port conflicts.
|
|
410
|
+
2. Report findings to the user and ask for takeover decision:
|
|
411
|
+
- **Take over and backup**: Back up existing config, then proceed.
|
|
412
|
+
- **Coexist**: Use different directory/ports/process names.
|
|
413
|
+
- **Manual resolve**: Stop and let the user handle it.
|
|
414
|
+
3. Record takeover decision and validation results in config and history.
|
|
415
|
+
|
|
416
|
+
### SSH: Nginx Management
|
|
417
|
+
|
|
418
|
+
- First Nginx config creation or update of a non-PrizmKit block requires user confirmation.
|
|
419
|
+
- Subsequent updates to PrizmKit-managed blocks (`# PrizmKit Managed:` marker) may proceed automatically.
|
|
420
|
+
- Managed marker format: `# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY`
|
|
421
|
+
- Always run `nginx -t` before reload.
|
|
422
|
+
- If a server block exists without the managed marker, ask before modifying.
|
|
423
|
+
|
|
424
|
+
See `references/nginx-blue-green.md` for the full Nginx config template, traffic switch procedure, and active port rediscovery technique.
|
|
425
|
+
|
|
426
|
+
### SSH: Bootstrap Safety Rules
|
|
427
|
+
|
|
428
|
+
Before executing privileged bootstrap work, generate an action plan listing:
|
|
429
|
+
- Packages to install/upgrade
|
|
430
|
+
- Users/groups to create/modify
|
|
431
|
+
- SSH keys to create
|
|
432
|
+
- Nginx config to create/modify
|
|
433
|
+
- Directories and permissions to change
|
|
434
|
+
- Services that may be restarted
|
|
435
|
+
|
|
436
|
+
Execution rules:
|
|
437
|
+
- User gives one explicit approval for the entire bootstrap plan.
|
|
438
|
+
- If the plan changes during execution, pause and ask again.
|
|
439
|
+
- Bootstrap operations must be idempotent.
|
|
440
|
+
- Existing config files must be backed up before modification.
|
|
441
|
+
- All privileged actions and results recorded in deploy history.
|
|
442
|
+
- Failed bootstrap stops before deployment, provides recovery instructions.
|
|
443
|
+
|
|
444
|
+
### SSH: Multi-App Coordination
|
|
445
|
+
|
|
446
|
+
An all-app deploy creates one release group. Rules:
|
|
447
|
+
- Pre-traffic phases (fetch, install, build, stage) must complete for ALL selected apps before ANY app switches traffic.
|
|
448
|
+
- If any app fails before traffic switch, NO app switches traffic. Staged processes are stopped, live system unchanged.
|
|
449
|
+
- If any app fails after traffic switch, default: group rollback (all apps in the release group roll back).
|
|
450
|
+
- Single-app deploys (`--app <id>`) do not affect unrelated apps.
|
|
451
|
+
|
|
452
|
+
## Validation
|
|
453
|
+
|
|
454
|
+
Validation is mandatory before production deploy. Check:
|
|
455
|
+
- SSH connectivity and user permissions
|
|
456
|
+
- Required tools present (node, npm, git, pm2, nginx)
|
|
457
|
+
- Repository reachability and branch existence
|
|
458
|
+
- Ports availability
|
|
459
|
+
- Required env vars present
|
|
460
|
+
- Nginx config syntax
|
|
461
|
+
- Health check routes accessible
|
|
462
|
+
|
|
463
|
+
Persist validation in `deploy.config.json` under each section's `validated` field.
|
|
464
|
+
|
|
465
|
+
## Adapter Paths
|
|
466
|
+
|
|
467
|
+
After Discovery routes to a deployment target, read the corresponding reference file for execution details:
|
|
468
|
+
|
|
469
|
+
| Target | Reference | Mode |
|
|
470
|
+
|--------|-----------|------|
|
|
471
|
+
| SSH Linux server | SSH sections below (Server Model through Multi-App) | Full automation |
|
|
472
|
+
| Vercel, Netlify, Fly.io | `references/cloud-platform-deploy.md` | Guided CLI |
|
|
473
|
+
| Docker / Docker Compose | `references/docker-deploy.md` | Guided build + run |
|
|
474
|
+
| Unrecognized target | Deployment Discovery Step 4 | Documented fallback |
|
|
475
|
+
|
|
476
|
+
The SSH path is documented inline below because it is the fully-automated adapter and the model needs its instructions in every SSH deployment session. Cloud and Docker paths are in references because they're loaded only when Discovery routes to them.
|
|
477
|
+
|
|
478
|
+
## Deploy History Record Schema
|
|
479
|
+
|
|
480
|
+
Each deployment, rollback, or significant event writes a record to `.prizmkit/deploy/deploy-history/<id>.json`. The full schema is in `references/deploy-history-schema.md` — read it when writing history records.
|
|
481
|
+
|
|
482
|
+
Never record raw secret values in history — presence metadata only.
|
|
483
|
+
|
|
484
|
+
## Implementation Notes from Live Validation
|
|
485
|
+
|
|
486
|
+
These findings from PrizmIdeas first deployment should guide your behavior:
|
|
487
|
+
|
|
488
|
+
1. **Detect port conflicts before installing Nginx.** Check what's on port 80/443 and ask before stopping anything.
|
|
489
|
+
2. **Verify npm separately from node.** Minimal Node installs may not bundle npm.
|
|
490
|
+
3. **Fix locale on bare Ubuntu.** Run `locale-gen en_US.UTF-8` early to avoid perl warnings in apt.
|
|
491
|
+
4. **Deploy key workflow is inherently interactive.** Generate key → wait for user to add to GitHub → verify. Headless mode cannot complete this.
|
|
492
|
+
5. **`pm2 startup` needs explicit PATH.** Always use `env PATH=$PATH:/usr/bin pm2 startup ...`.
|
|
493
|
+
6. **Persist deploy metadata on server.** Write `activeColor`, `activePort`, `lastReleaseId`, `lastDeployTimestamp` to `shared/deploy-metadata.json`.
|
|
494
|
+
7. **Detect first deployment.** If no `current` symlink and no PM2 process for the app, skip rollback safety checks and use blue (3101) as initial color.
|
|
495
|
+
8. **Build-time env vars.** Copy `.env.production` before `npm run build`, not after. `NEXT_PUBLIC_*` vars are baked at build time.
|
|
496
|
+
9. **Node.js version flexibility.** Default to v22 LTS if v25 is unavailable. Most frameworks tolerate a minor version diff.
|