@oaklandzoo/ostup 0.1.2 → 0.2.0
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/package.json +1 -1
- package/src/mvp-flow.mjs +13 -1
- package/src/scaffold.mjs +12 -1
- package/src/templates.mjs +6 -0
- package/templates/.claude/commands/add-storage.md +112 -0
- package/templates/.claude/commands/bootstrap.md +3 -0
- package/templates/.claude/commands/preflight.md +57 -0
- package/templates/.claude/commands/update-backend.md +74 -0
- package/templates/.claude/commands/update-gui.md +55 -0
- package/templates/.claude/commands/update-image.md +57 -0
- package/templates/AGENTS.md +8 -3
- package/templates/CLAUDE.md +13 -0
- package/templates/START_HERE.md +5 -0
- package/templates/scripts/screenshot.sh +35 -0
package/package.json
CHANGED
package/src/mvp-flow.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// mvp-flow.mjs: orchestrate the full MVP scaffold: preflight, prompts, creds, scaffold, GitHub, Vercel, inject, summary.
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { readdir, mkdir, writeFile, readFile, rm } from 'node:fs/promises';
|
|
3
|
+
import { readdir, mkdir, writeFile, readFile, rm, chmod } from 'node:fs/promises';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
4
5
|
import { resolve, join, dirname } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { preflightOrExit } from './preflight.mjs';
|
|
@@ -56,6 +57,7 @@ export async function runMvp({ flags = {}, cwd = process.cwd() } = {}) {
|
|
|
56
57
|
const targetDir = resolve(cwd, answers.projectName);
|
|
57
58
|
await ensureFreshTarget(targetDir, flags.force);
|
|
58
59
|
await mkdir(targetDir, { recursive: true });
|
|
60
|
+
await ensureMemoryDir(targetDir);
|
|
59
61
|
|
|
60
62
|
await maybeScaffoldStack({ stack: answers.stack, projectName: answers.projectName, targetDir });
|
|
61
63
|
|
|
@@ -179,6 +181,16 @@ async function writeOne({ entry, targetDir, tokens, defer }) {
|
|
|
179
181
|
const out = substitute(raw, tokens, { defer });
|
|
180
182
|
await mkdir(dirname(dest), { recursive: true });
|
|
181
183
|
await writeFile(dest, out, 'utf8');
|
|
184
|
+
if (entry.executable) {
|
|
185
|
+
await chmod(dest, 0o755);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export async function ensureMemoryDir(targetDir) {
|
|
190
|
+
const sanitized = targetDir.replace(/[/ ]/g, '-');
|
|
191
|
+
const memoryDir = join(homedir(), '.claude', 'projects', sanitized, 'memory');
|
|
192
|
+
await mkdir(memoryDir, { recursive: true });
|
|
193
|
+
return memoryDir;
|
|
182
194
|
}
|
|
183
195
|
|
|
184
196
|
async function writeProjectEnvFiles({ targetDir, collected }) {
|
package/src/scaffold.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises';
|
|
2
|
+
import { readFile, writeFile, mkdir, readdir, chmod } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
3
4
|
import { dirname, resolve, join } from 'node:path';
|
|
4
5
|
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import { execSync } from 'node:child_process';
|
|
@@ -38,6 +39,7 @@ export async function scaffold({ targetDir, flags, stdinIsTTY = process.stdin.is
|
|
|
38
39
|
const tokens = buildTokenMap(values);
|
|
39
40
|
|
|
40
41
|
await mkdir(absTarget, { recursive: true });
|
|
42
|
+
await ensureMemoryDir(absTarget);
|
|
41
43
|
|
|
42
44
|
for (const entry of REGISTRY) {
|
|
43
45
|
await writeOne({ entry, absTarget, tokens });
|
|
@@ -60,6 +62,15 @@ async function writeOne({ entry, absTarget, tokens }) {
|
|
|
60
62
|
const out = substitute(raw, tokens);
|
|
61
63
|
await mkdir(dirname(dest), { recursive: true });
|
|
62
64
|
await writeFile(dest, out, 'utf8');
|
|
65
|
+
if (entry.executable) {
|
|
66
|
+
await chmod(dest, 0o755);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function ensureMemoryDir(absTarget) {
|
|
71
|
+
const sanitized = absTarget.replace(/[/ ]/g, '-');
|
|
72
|
+
const memoryDir = join(homedir(), '.claude', 'projects', sanitized, 'memory');
|
|
73
|
+
await mkdir(memoryDir, { recursive: true });
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
async function ensureTargetReady(absTarget, force) {
|
package/src/templates.mjs
CHANGED
|
@@ -21,6 +21,11 @@ export const REGISTRY = [
|
|
|
21
21
|
{ src: '.claude/commands/prompt-end.md', dest: '.claude/commands/prompt-end.md' },
|
|
22
22
|
{ src: '.claude/commands/create-prd.md', dest: '.claude/commands/create-prd.md' },
|
|
23
23
|
{ src: '.claude/commands/generate-tasks.md', dest: '.claude/commands/generate-tasks.md' },
|
|
24
|
+
{ src: '.claude/commands/preflight.md', dest: '.claude/commands/preflight.md' },
|
|
25
|
+
{ src: '.claude/commands/update-image.md', dest: '.claude/commands/update-image.md' },
|
|
26
|
+
{ src: '.claude/commands/update-gui.md', dest: '.claude/commands/update-gui.md' },
|
|
27
|
+
{ src: '.claude/commands/update-backend.md', dest: '.claude/commands/update-backend.md' },
|
|
28
|
+
{ src: '.claude/commands/add-storage.md', dest: '.claude/commands/add-storage.md' },
|
|
24
29
|
{ src: 'CLAUDE.md', dest: 'CLAUDE.md' },
|
|
25
30
|
{ src: 'AGENTS.md', dest: 'AGENTS.md' },
|
|
26
31
|
{ src: 'START_HERE.md', dest: 'START_HERE.md' },
|
|
@@ -31,6 +36,7 @@ export const REGISTRY = [
|
|
|
31
36
|
{ src: 'docs/ARCHITECTURE.md', dest: 'docs/ARCHITECTURE.md' },
|
|
32
37
|
{ src: 'tasks/.gitkeep', dest: 'tasks/.gitkeep' },
|
|
33
38
|
{ src: 'inputs/README.md', dest: 'inputs/README.md' },
|
|
39
|
+
{ src: 'scripts/screenshot.sh', dest: 'scripts/screenshot.sh', executable: true },
|
|
34
40
|
];
|
|
35
41
|
|
|
36
42
|
export const OPTIONAL_REGISTRY = [
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Provision a Vercel storage product (Blob, KV, Postgres, Edge Config), pull its env vars, and scaffold a typed lib helper.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Add storage
|
|
6
|
+
|
|
7
|
+
## Step 1: which type
|
|
8
|
+
|
|
9
|
+
If the operator named a type (e.g. `/add-storage blob`), use it. Otherwise ask:
|
|
10
|
+
|
|
11
|
+
| Type | What it is | When to pick |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `blob` | File storage with public URLs | Image uploads, downloads, generated PDFs |
|
|
14
|
+
| `kv` | Redis-style key/value | Sessions, caches, counters, rate limits |
|
|
15
|
+
| `postgres` | Relational SQL | Users, transactions, anything with joins |
|
|
16
|
+
| `edge-config` | Read-heavy small config (<8 KB) | Feature flags, A/B variants, allowlists |
|
|
17
|
+
|
|
18
|
+
## Step 2: check what already exists
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
vercel <type> list-stores --all 2>&1 | head -10
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If a suitable store already exists, ask the operator if they want to reuse it instead of creating a new one. Skip to Step 4 if reusing.
|
|
25
|
+
|
|
26
|
+
## Step 3: provision a new store
|
|
27
|
+
|
|
28
|
+
Ask for a store name. Default to `<project-name>-<type>`. Then run:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
vercel <type> create-store <name> \
|
|
32
|
+
--environment production --environment preview --environment development --yes
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For `blob`, also include `--access public` if the stored objects should be served via public URLs:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
vercel blob create-store <name> --access public --yes \
|
|
39
|
+
--environment production --environment preview --environment development
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Capture the output (store ID, etc.) and surface it.
|
|
43
|
+
|
|
44
|
+
## Step 4: pull env vars
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
vercel env pull .env.local
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Confirm `.env.local` got the new keys. Common ones:
|
|
51
|
+
|
|
52
|
+
| Type | Keys |
|
|
53
|
+
|---|---|
|
|
54
|
+
| blob | `BLOB_READ_WRITE_TOKEN` |
|
|
55
|
+
| kv | `KV_URL`, `KV_REST_API_URL`, `KV_REST_API_TOKEN`, `KV_REST_API_READ_ONLY_TOKEN` |
|
|
56
|
+
| postgres | `POSTGRES_URL`, `POSTGRES_PRISMA_URL`, `POSTGRES_URL_NON_POOLING`, `POSTGRES_USER`, etc. |
|
|
57
|
+
| edge-config | `EDGE_CONFIG` |
|
|
58
|
+
|
|
59
|
+
## Step 5: install the SDK and scaffold the lib helper
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @vercel/<type>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Create `src/lib/<type>.ts` with typed helpers. Example for blob:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// src/lib/blob.ts
|
|
69
|
+
import { put, list, del } from '@vercel/blob';
|
|
70
|
+
|
|
71
|
+
export async function uploadFile(path: string, body: Blob | ArrayBuffer | string) {
|
|
72
|
+
return put(path, body, { access: 'public' });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function listFiles(prefix?: string) {
|
|
76
|
+
return list({ prefix });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function deleteFile(url: string) {
|
|
80
|
+
return del(url);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Match the project's existing TypeScript conventions (named exports, no defaults, etc.).
|
|
85
|
+
|
|
86
|
+
## Step 6: update AGENTS.md
|
|
87
|
+
|
|
88
|
+
Append under a `## Storage` section:
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
## Storage
|
|
92
|
+
|
|
93
|
+
- `<type>`: `src/lib/<type>.ts`. Store: `<name>`. Env vars in `.env.local`.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Step 7: commit and push
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
git add src/lib/<type>.ts AGENTS.md package.json package-lock.json
|
|
100
|
+
git commit -m "feat(storage): add <type> via src/lib/<type>.ts"
|
|
101
|
+
git push
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Step 8: report
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
Added <type> storage:
|
|
108
|
+
- Store: <name>
|
|
109
|
+
- Lib: src/lib/<type>.ts
|
|
110
|
+
- Env: <list of keys>
|
|
111
|
+
- Deploy: <url>
|
|
112
|
+
```
|
|
@@ -22,6 +22,9 @@ find . -maxdepth 2 -type d ! -path '*/node_modules*' ! -path '*/.git*' ! -path '
|
|
|
22
22
|
[ -f inputs/INGEST_MANIFEST.md ] && cat inputs/INGEST_MANIFEST.md
|
|
23
23
|
[ -f inputs/README.md ] && cat inputs/README.md
|
|
24
24
|
[ -d inputs ] && ls -la inputs/
|
|
25
|
+
# Helpers available in this kit
|
|
26
|
+
[ -x scripts/screenshot.sh ] && echo "scripts/screenshot.sh ready (required for visual verification per CLAUDE.md Part 19)"
|
|
27
|
+
ls .claude/commands/ 2>/dev/null
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
## Step 2: Determine what you know
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Surface what is already provisioned for this project (Vercel auth, blob stores, gh auth, env vars, Chrome). Prevents the agent from assigning CLI work it could do itself.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Preflight
|
|
6
|
+
|
|
7
|
+
Run at the start of any session where you might touch Vercel, gh, the GUI, or storage. The output tells you what already exists so you do not duplicate setup or assign the operator CLI work that is already done.
|
|
8
|
+
|
|
9
|
+
## Step 1: probe everything in one block
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
echo "=== Vercel ==="
|
|
13
|
+
vercel whoami 2>&1 | head -3
|
|
14
|
+
if [ -f .vercel/project.json ]; then
|
|
15
|
+
echo "Linked:"
|
|
16
|
+
cat .vercel/project.json
|
|
17
|
+
else
|
|
18
|
+
echo "Not linked (no .vercel/project.json)"
|
|
19
|
+
fi
|
|
20
|
+
echo ""
|
|
21
|
+
echo "Blob stores:"
|
|
22
|
+
vercel blob list-stores --all 2>&1 | head -10
|
|
23
|
+
echo ""
|
|
24
|
+
echo "Env vars:"
|
|
25
|
+
vercel env list 2>&1 | head -15
|
|
26
|
+
|
|
27
|
+
echo ""
|
|
28
|
+
echo "=== GitHub ==="
|
|
29
|
+
gh auth status 2>&1 | head -5
|
|
30
|
+
git remote -v 2>&1 | head -2
|
|
31
|
+
|
|
32
|
+
echo ""
|
|
33
|
+
echo "=== Local tools ==="
|
|
34
|
+
node --version
|
|
35
|
+
[ -d "/Applications/Google Chrome.app" ] && echo "Chrome: present" || echo "Chrome: MISSING (operator must install for visual verification per CLAUDE.md Part 19)"
|
|
36
|
+
[ -x "scripts/screenshot.sh" ] && echo "scripts/screenshot.sh: ready" || echo "scripts/screenshot.sh: MISSING or not executable"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Step 2: print the SESSION READY summary
|
|
40
|
+
|
|
41
|
+
After reading the output, print exactly:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
SESSION READY
|
|
45
|
+
|
|
46
|
+
Vercel: <authed as X | linked to project Y | N blob stores | M env vars>
|
|
47
|
+
GitHub: <authed | remote URL>
|
|
48
|
+
Chrome: <present | MISSING>
|
|
49
|
+
Screenshot: <ready | missing>
|
|
50
|
+
Node: <version>
|
|
51
|
+
|
|
52
|
+
Anything missing above must be flagged before claiming any work that depends on it.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Step 3: hard rule
|
|
56
|
+
|
|
57
|
+
Do NOT propose CLI steps the operator should run for anything Vercel or gh already covers per the SESSION READY line above. CLAUDE.md Part 3 Rule 9 is the constraint: agent does what the agent can do.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Make a backend logic change (API route, lib function, server action), deploy, and verify the new behavior via API call before claiming done.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Update backend
|
|
6
|
+
|
|
7
|
+
Non-visual analog to `/update-gui`. Verify behavior, not just compile.
|
|
8
|
+
|
|
9
|
+
## Step 1: confirm intent
|
|
10
|
+
|
|
11
|
+
Restate the change in one sentence. Get a thumbs-up before editing if scope is non-trivial.
|
|
12
|
+
|
|
13
|
+
## Step 2: edit
|
|
14
|
+
|
|
15
|
+
Make the change. Minimal diff.
|
|
16
|
+
|
|
17
|
+
## Step 3: write or run a test
|
|
18
|
+
|
|
19
|
+
If a test framework is configured, run the test suite:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm test 2>&1 | tail -10
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If no tests exist for the touched code, write one that exercises the new behavior (preferred), or capture an expected response shape for Step 6.
|
|
26
|
+
|
|
27
|
+
If no test framework exists at all, skip to Step 4 and rely on the curl probe in Step 6.
|
|
28
|
+
|
|
29
|
+
## Step 4: build
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm run build 2>&1 | tail -10
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If the build fails, fix before deploying.
|
|
36
|
+
|
|
37
|
+
## Step 5: deploy
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git add <changed-files>
|
|
41
|
+
git commit -m "<short message>"
|
|
42
|
+
git push
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Wait ~60 seconds for Vercel auto-deploy.
|
|
46
|
+
|
|
47
|
+
## Step 6: probe the live endpoint
|
|
48
|
+
|
|
49
|
+
For an API route change:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
curl -s -i "<deploy-url>/api/<route>" | head -20
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For a route that takes a body:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl -s -X POST "<deploy-url>/api/<route>" \
|
|
59
|
+
-H "Content-Type: application/json" \
|
|
60
|
+
-d '{"key":"value"}' | head -20
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Compare the response to the expected shape from Step 3.
|
|
64
|
+
|
|
65
|
+
## Step 7: report
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Backend change shipped: <one-line description>
|
|
69
|
+
Deploy: <url>
|
|
70
|
+
Verified via: <test name or curl command>
|
|
71
|
+
Response: <status, key field, whatever proves it works>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If verification fails, do NOT claim done. Diagnose, fix, re-deploy, re-probe.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Make a UI change, deploy it, and verify visually before claiming done. Enforces CLAUDE.md Part 19.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Update GUI
|
|
6
|
+
|
|
7
|
+
This command exists so that CLAUDE.md Part 19 (visual verification) is the default for any UI change, not an afterthought.
|
|
8
|
+
|
|
9
|
+
## Step 1: confirm intent
|
|
10
|
+
|
|
11
|
+
The operator described the change. Restate it in one sentence and get a thumbs-up before editing if the scope is non-trivial. Skip the thumbs-up for tiny changes (typo, single color, single class).
|
|
12
|
+
|
|
13
|
+
## Step 2: edit
|
|
14
|
+
|
|
15
|
+
Make the change. Keep the diff minimal. No unrelated cleanup in the same commit.
|
|
16
|
+
|
|
17
|
+
## Step 3: build locally
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run build 2>&1 | tail -10
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If the build fails, fix before deploying.
|
|
24
|
+
|
|
25
|
+
## Step 4: deploy
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git add <changed-files>
|
|
29
|
+
git commit -m "<short message>"
|
|
30
|
+
git push
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Wait ~60 seconds for Vercel auto-deploy.
|
|
34
|
+
|
|
35
|
+
## Step 5: screenshot
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
scripts/screenshot.sh <deploy-url> /tmp/gui-check.png 420,900
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Step 6: read the PNG
|
|
42
|
+
|
|
43
|
+
Use the Read tool on `/tmp/gui-check.png`. Confirm the visual change matches what the operator asked for. If it does not, diagnose (CSS regression, z-index, cache, stale file path) and re-deploy. Do NOT claim done.
|
|
44
|
+
|
|
45
|
+
## Step 7: report
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
GUI change shipped: <one-line description>
|
|
49
|
+
Deploy: <url>
|
|
50
|
+
Screenshot: /tmp/gui-check.png (read, change confirmed)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Hard rule
|
|
54
|
+
|
|
55
|
+
HTTP 200, build success, lint pass, byte counts: none of these count as visual verification. Only a read PNG counts.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Swap an image referenced in the codebase (background, hero, logo) using a candidate from inputs/images/. Always ends with screenshot verification per CLAUDE.md Part 19.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Update an image
|
|
6
|
+
|
|
7
|
+
## Step 1: figure out the slot
|
|
8
|
+
|
|
9
|
+
If the operator named a slot (e.g. `/update-image bg-week`), use that.
|
|
10
|
+
|
|
11
|
+
If not, list every image reference in the codebase:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
grep -rln -E "/(bg|hero|logo|images?)/[a-zA-Z0-9_-]+\.(png|jpg|jpeg|svg|webp|avif)" src/ public/ 2>/dev/null
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Show the operator the slots and ask which to update.
|
|
18
|
+
|
|
19
|
+
## Step 2: pick the source
|
|
20
|
+
|
|
21
|
+
List candidates in `inputs/images/`:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ls -la inputs/images/ 2>/dev/null
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
If there is an `inputs/images/MANIFEST.md`, read it for filenames and captions.
|
|
28
|
+
|
|
29
|
+
If multiple candidates and the choice is not obvious, ask the operator. Do NOT Read more than 3 image files at a time — each Read returns a vision payload that is heavy in context.
|
|
30
|
+
|
|
31
|
+
## Step 3: swap it in
|
|
32
|
+
|
|
33
|
+
1. Copy the chosen file from `inputs/images/` to the right path under `public/`.
|
|
34
|
+
2. Update any code references if the filename changed.
|
|
35
|
+
3. `git add <changed files>` (the new image plus any code).
|
|
36
|
+
4. `git commit -m "feat(images): swap <slot>"`
|
|
37
|
+
5. `git push` (Vercel auto-deploys).
|
|
38
|
+
|
|
39
|
+
## Step 4: verify visually (REQUIRED per CLAUDE.md Part 19)
|
|
40
|
+
|
|
41
|
+
Wait ~60 seconds for Vercel to deploy. Then:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
scripts/screenshot.sh <deploy-url> /tmp/after-swap.png 420,900
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Read the resulting PNG with the Read tool. Confirm the new image is showing in the slot.
|
|
48
|
+
|
|
49
|
+
## Step 5: report
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Swapped <slot>: <old-filename> -> <new-filename>
|
|
53
|
+
Deploy: <url>
|
|
54
|
+
Screenshot: /tmp/after-swap.png (read and verified)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If the screenshot does not show the change, do NOT claim done. Diagnose (CSS z-index, wrong path, wrong file) and re-deploy before reporting.
|
package/templates/AGENTS.md
CHANGED
|
@@ -27,7 +27,12 @@ Operator materials live in `{{INPUTS_PATH}}`. Read `{{INPUTS_PATH}}README.md` fo
|
|
|
27
27
|
|
|
28
28
|
## Slash commands available
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
- `/create-prd`, `/generate-tasks`
|
|
30
|
+
Session lifecycle: `/bootstrap`, `/prompt-start`, `/prompt-mid`, `/prompt-end`, `/preflight`
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
Building: `/create-prd`, `/generate-tasks`, `/update-image`, `/update-gui`, `/update-backend`, `/add-storage`
|
|
33
|
+
|
|
34
|
+
See each file under `.claude/commands/` for the full routine.
|
|
35
|
+
|
|
36
|
+
## Helpers
|
|
37
|
+
|
|
38
|
+
- `scripts/screenshot.sh <url> [out] [WxH]` — headless Chrome screenshot. Required for visual verification per `CLAUDE.md` Part 19.
|
package/templates/CLAUDE.md
CHANGED
|
@@ -254,3 +254,16 @@ Detailed file map: `docs/ARCHITECTURE.md`.
|
|
|
254
254
|
| What happened recently | `docs/SESSION_NOTES.md` |
|
|
255
255
|
| Stack and file map | `docs/ARCHITECTURE.md` |
|
|
256
256
|
| How to behave | `CLAUDE.md` (this file) |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
# PART 19: VISUAL VERIFICATION
|
|
261
|
+
|
|
262
|
+
Any change that affects what the operator sees in a browser (HTML, CSS, Tailwind classes, image swaps, layout, copy in JSX, fonts, colors, hero sections, anything rendered) is NOT done until BOTH of the following are true:
|
|
263
|
+
|
|
264
|
+
1. `scripts/screenshot.sh <deployed-url>` has been run after the change is deployed.
|
|
265
|
+
2. The resulting PNG has been read with the Read tool and the visual change is confirmed to match the intent.
|
|
266
|
+
|
|
267
|
+
HTTP 200, build success, lint passing, byte counts of the deployed HTML: none of these count as visual verification.
|
|
268
|
+
|
|
269
|
+
If `scripts/screenshot.sh` is missing or Chrome is not installed, surface the gap before claiming the change is done. Do not assume.
|
package/templates/START_HERE.md
CHANGED
|
@@ -47,11 +47,16 @@ Type these in your CLI agent. Each runs a structured routine.
|
|
|
47
47
|
| Command | What it does | When to run it |
|
|
48
48
|
|---|---|---|
|
|
49
49
|
| `/bootstrap` | Scans the repo and asks up to 5 clarifiers, then fills in `CLAUDE.md` Parts 13 to 17 and `docs/ARCHITECTURE.md` with your project's real facts. | Once, on the first session. |
|
|
50
|
+
| `/preflight` | Surfaces what is already provisioned (Vercel auth, blob stores, gh auth, env vars, Chrome). Stops the agent from assigning CLI work it could do itself. | Start of any session where you might touch Vercel, gh, the GUI, or storage. |
|
|
50
51
|
| `/prompt-start` | Reads HANDOFF, MANUAL_TASKS, git status. Briefs the agent on the current state. Asks "Proceed or pivot?" | Start of every session after the first. |
|
|
51
52
|
| `/prompt-mid` | Checks context budget, restates progress, verifies any files the agent claimed to write actually exist. | Mid-session, if you feel lost or the agent seems off-track. |
|
|
52
53
|
| `/prompt-end` | Rewrites HANDOFF, appends to SESSION_NOTES, surfaces any new blockers to MANUAL_TASKS. | End of every session. Always. Without this the next session has no memory of what just happened. |
|
|
53
54
|
| `/create-prd` | Asks 3 to 5 clarifying questions, then writes a PRD to `tasks/prd-<feature>.md`. | Before building a significant new feature. Optional for small changes. |
|
|
54
55
|
| `/generate-tasks` | Reads a PRD, breaks it into a phased task list at `tasks/tasks-<feature>.md` (parent tasks first, then sub-tasks after you say "Go"). | After a PRD is approved, before the agent starts coding. |
|
|
56
|
+
| `/update-image` | Swap an image (background, hero, logo) using a candidate from `inputs/images/`. Ends with screenshot verification. | Any time you want to change a visual asset. |
|
|
57
|
+
| `/update-gui` | Make a UI change, deploy, screenshot, confirm the visual change matches intent. Enforces visual verification. | Any UI tweak. |
|
|
58
|
+
| `/update-backend` | Make a backend/API change, deploy, probe the live endpoint, confirm behavior. | Any server/API change. |
|
|
59
|
+
| `/add-storage` | Provision a Vercel Blob, KV, Postgres, or Edge Config store + scaffold a typed `src/lib/<type>.ts` helper + pull env vars. | When you need persistent storage. |
|
|
55
60
|
|
|
56
61
|
## Three workflows
|
|
57
62
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Headless Chrome screenshot helper. Use to visually verify a UI change.
|
|
3
|
+
# Required by CLAUDE.md Part 19 (Visual Verification).
|
|
4
|
+
#
|
|
5
|
+
# Usage: scripts/screenshot.sh <url> [output-path] [width,height]
|
|
6
|
+
# Example: scripts/screenshot.sh https://your-app.vercel.app /tmp/check.png 420,900
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
if [ -z "$1" ]; then
|
|
11
|
+
echo "Usage: $0 <url> [output-path] [width,height]" >&2
|
|
12
|
+
echo "Example: $0 https://your-app.vercel.app /tmp/check.png 420,900" >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
URL="$1"
|
|
17
|
+
OUT="${2:-/tmp/screenshot-$(date +%s).png}"
|
|
18
|
+
SIZE="${3:-420,900}"
|
|
19
|
+
|
|
20
|
+
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
21
|
+
if [ ! -x "$CHROME" ]; then
|
|
22
|
+
CHROME="$(command -v chromium 2>/dev/null || command -v google-chrome 2>/dev/null || echo '')"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
if [ -z "$CHROME" ] || [ ! -x "$CHROME" ]; then
|
|
26
|
+
echo "ERROR: Chrome not found. Install Google Chrome from https://www.google.com/chrome/" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
"$CHROME" \
|
|
31
|
+
--headless=new --disable-gpu --hide-scrollbars \
|
|
32
|
+
--window-size="$SIZE" --virtual-time-budget=4000 \
|
|
33
|
+
--screenshot="$OUT" "$URL" 2>/dev/null
|
|
34
|
+
|
|
35
|
+
echo "$OUT"
|