@oaklandzoo/ostup 0.3.0 → 0.5.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/README.md +23 -0
- package/bin/cli.mjs +27 -1
- package/package.json +1 -1
- package/src/brief/classify.mjs +218 -0
- package/src/brief/index.mjs +126 -0
- package/src/brief/profile-router.mjs +89 -0
- package/src/brief/questions.mjs +333 -0
- package/src/brief/render-brief.mjs +232 -0
- package/src/brief/sample-briefs.mjs +304 -0
- package/src/brief/schema.mjs +176 -0
- package/src/mvp-flow.mjs +43 -1
- package/src/templates.mjs +4 -0
- package/templates/.claude/commands/break-into-stories.md +101 -0
- package/templates/.claude/commands/handoff-doctor.md +93 -0
- package/templates/.claude/commands/resume.md +102 -0
- package/templates/AGENTS.md +13 -2
- package/templates/CLAUDE.md +3 -0
- package/templates/START_HERE.md +11 -4
- package/templates/profiles/blog/.env.example.additions +7 -0
- package/templates/profiles/blog/README.md +70 -0
- package/templates/profiles/blog/section-prompts.md +63 -0
- package/templates/profiles/booking/.env.example.additions +16 -0
- package/templates/profiles/booking/README.md +61 -0
- package/templates/profiles/booking/section-prompts.md +47 -0
- package/templates/profiles/lead-gen/.env.example.additions +8 -0
- package/templates/profiles/lead-gen/README.md +58 -0
- package/templates/profiles/lead-gen/section-prompts.md +47 -0
- package/templates/profiles/marketing/README.md +39 -0
- package/templates/profiles/marketing/section-prompts.md +36 -0
- package/templates/profiles/saas-dashboard/.env.example.additions +21 -0
- package/templates/profiles/saas-dashboard/README.md +60 -0
- package/templates/profiles/saas-dashboard/section-prompts.md +52 -0
- package/templates/scripts/verify.sh +128 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Audit HANDOFF.md against actual repo state. Flags stale claims, missing follow-throughs, and orphan files not mentioned anywhere. Read-only; surfaces a punch list for /prompt-end to fix.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /handoff-doctor
|
|
6
|
+
|
|
7
|
+
HANDOFF.md should reflect repo reality. When it does not, agents (including you) make decisions based on lies. This command catches lies before they cause work loss.
|
|
8
|
+
|
|
9
|
+
## Step 1: probe
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
echo "=== HANDOFF claims ==="
|
|
13
|
+
grep -E "^(\*\*Status:\*\*|\*\*Branch:\*\*|\*\*Working tree:\*\*|\*\*Last session ended:\*\*)" HANDOFF.md | head -8
|
|
14
|
+
|
|
15
|
+
echo ""
|
|
16
|
+
echo "=== Repo reality ==="
|
|
17
|
+
echo "Branch: $(git branch --show-current)"
|
|
18
|
+
echo "Last commit: $(git log -1 --oneline)"
|
|
19
|
+
echo "Ahead of origin: $(git rev-list --count origin/$(git branch --show-current)..HEAD 2>/dev/null || echo 'no upstream')"
|
|
20
|
+
echo "Behind origin: $(git rev-list --count HEAD..origin/$(git branch --show-current) 2>/dev/null || echo 'no upstream')"
|
|
21
|
+
echo "Working tree:"
|
|
22
|
+
git status --short
|
|
23
|
+
|
|
24
|
+
echo ""
|
|
25
|
+
echo "=== Files HANDOFF claims were touched ==="
|
|
26
|
+
grep -E "^\s*-\s*\`[^\`]+\`" HANDOFF.md | head -20
|
|
27
|
+
|
|
28
|
+
echo ""
|
|
29
|
+
echo "=== Files actually changed in last 5 commits ==="
|
|
30
|
+
git log --name-only --oneline -5 | grep -v "^[0-9a-f]\{7\}" | sort -u | head -30
|
|
31
|
+
|
|
32
|
+
echo ""
|
|
33
|
+
echo "=== Tasks mentioned in HANDOFF ==="
|
|
34
|
+
grep -E "tasks/|prd-|\.md" HANDOFF.md | head -10
|
|
35
|
+
|
|
36
|
+
echo ""
|
|
37
|
+
echo "=== Tasks actually in tasks/ ==="
|
|
38
|
+
ls tasks/ 2>/dev/null
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
echo "=== Manual blockers claimed ==="
|
|
42
|
+
[ -f docs/MANUAL_TASKS.md ] && grep -c "^\s*-\s*\[ \]" docs/MANUAL_TASKS.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Step 2: diagnose
|
|
46
|
+
|
|
47
|
+
Audit each of these axes. For each finding, state CLAIM vs ACTUAL.
|
|
48
|
+
|
|
49
|
+
1. **Branch mismatch.** HANDOFF says branch X, git is on branch Y.
|
|
50
|
+
2. **Push lag.** HANDOFF says "push commit X" but `git log origin/$(git branch --show-current)` already includes X.
|
|
51
|
+
3. **Working tree drift.** HANDOFF says "clean" but `git status` shows N dirty files.
|
|
52
|
+
4. **Last-session timestamp.** HANDOFF "Last session ended" is more than 7 days old. Mark as STALE.
|
|
53
|
+
5. **Orphan tasks.** Files in `tasks/` not referenced by HANDOFF.
|
|
54
|
+
6. **Phantom files.** HANDOFF references files that do not exist (`ls` them to verify).
|
|
55
|
+
7. **Phantom commits.** HANDOFF references SHAs not in `git log`.
|
|
56
|
+
8. **Manual-task drift.** HANDOFF says no blockers but MANUAL_TASKS.md has Active items (or vice versa).
|
|
57
|
+
9. **Brief drift.** docs/brief.md exists but HANDOFF makes no reference to it; or HANDOFF references a brief that does not exist.
|
|
58
|
+
10. **Test-pass lie.** HANDOFF says "N/N tests green" — run `npm test` (or similar) and compare.
|
|
59
|
+
|
|
60
|
+
## Step 3: print findings
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
HANDOFF DOCTOR REPORT
|
|
64
|
+
|
|
65
|
+
Overall: <CLEAN | NEEDS REWRITE | CRITICAL>
|
|
66
|
+
|
|
67
|
+
Findings:
|
|
68
|
+
|
|
69
|
+
[CRITICAL] <description> Fix: <what to do>
|
|
70
|
+
[STALE] <description> Fix: <what to do>
|
|
71
|
+
[ORPHAN] <description> Fix: <what to do>
|
|
72
|
+
[PHANTOM] <description> Fix: <what to do>
|
|
73
|
+
[CLEAN] No issues on this axis: <axis name>
|
|
74
|
+
|
|
75
|
+
Recommended actions:
|
|
76
|
+
1. <action>
|
|
77
|
+
2. <action>
|
|
78
|
+
|
|
79
|
+
Run /prompt-end to rewrite HANDOFF.md with current reality.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Hard rules
|
|
83
|
+
|
|
84
|
+
- Read-only. Never modify HANDOFF.md from this command. `/prompt-end` is the writer.
|
|
85
|
+
- Be specific in findings. "HANDOFF says push 9a4708f but it is already at origin/main" is useful. "HANDOFF is wrong" is not.
|
|
86
|
+
- If a finding is borderline (e.g. timestamp 6 days old, threshold is 7), mark it CLEAN with a note rather than STALE.
|
|
87
|
+
- If everything passes, say so. Do not invent issues.
|
|
88
|
+
|
|
89
|
+
## When to run
|
|
90
|
+
|
|
91
|
+
- Before `/prompt-start` if you suspect HANDOFF is wrong.
|
|
92
|
+
- After a long AFK session before a new agent picks up.
|
|
93
|
+
- Any time HANDOFF claims something that does not match what you just saw in git.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Resume an in-progress session by reading git diff, HANDOFF, tasks, and the brief if present. Briefs the agent on actual current state vs claimed state. Use instead of /prompt-start when you suspect HANDOFF.md is stale.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /resume
|
|
6
|
+
|
|
7
|
+
`/prompt-start` reads HANDOFF and trusts it. `/resume` reads HANDOFF and **verifies it against git reality**. Use when:
|
|
8
|
+
|
|
9
|
+
- You stopped mid-feature and HANDOFF was not rewritten.
|
|
10
|
+
- You came back after several days and are not sure HANDOFF is current.
|
|
11
|
+
- A teammate worked in this repo while you were away.
|
|
12
|
+
- Something feels off about the briefing.
|
|
13
|
+
|
|
14
|
+
## Step 1: collect ground truth
|
|
15
|
+
|
|
16
|
+
Run all of these in one bash block:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
echo "=== Git reality ==="
|
|
20
|
+
git status --short
|
|
21
|
+
git log --oneline -10
|
|
22
|
+
git diff --stat HEAD~5..HEAD 2>/dev/null || git diff --stat
|
|
23
|
+
|
|
24
|
+
echo ""
|
|
25
|
+
echo "=== HANDOFF.md (claimed state) ==="
|
|
26
|
+
[ -f HANDOFF.md ] && head -60 HANDOFF.md || echo "no HANDOFF.md"
|
|
27
|
+
|
|
28
|
+
echo ""
|
|
29
|
+
echo "=== Active tasks / PRDs ==="
|
|
30
|
+
ls tasks/ 2>/dev/null
|
|
31
|
+
[ -f tasks/prd-initial-build.md ] && head -30 tasks/prd-initial-build.md
|
|
32
|
+
|
|
33
|
+
echo ""
|
|
34
|
+
echo "=== Brief (if present) ==="
|
|
35
|
+
[ -f docs/brief.md ] && head -40 docs/brief.md || echo "no brief"
|
|
36
|
+
|
|
37
|
+
echo ""
|
|
38
|
+
echo "=== Manual blockers ==="
|
|
39
|
+
[ -f docs/MANUAL_TASKS.md ] && grep -A 2 "## Active" docs/MANUAL_TASKS.md | head -20
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Step 2: compare claimed vs actual
|
|
43
|
+
|
|
44
|
+
Build a diff in your head between:
|
|
45
|
+
|
|
46
|
+
| Source | Status they show |
|
|
47
|
+
|---|---|
|
|
48
|
+
| HANDOFF.md "What to do next" | What the last session said is queued |
|
|
49
|
+
| `git log` | What actually got committed |
|
|
50
|
+
| `git status` | What is in-flight and uncommitted |
|
|
51
|
+
| `tasks/` PRDs and PRD-seeds | What features are scoped |
|
|
52
|
+
| `docs/brief.md` (if any) | What the project is supposed to be |
|
|
53
|
+
|
|
54
|
+
Flag every mismatch. Examples of mismatches:
|
|
55
|
+
|
|
56
|
+
- HANDOFF says "push commit X" but `git log` shows X is already pushed (HANDOFF is stale; rewrite at session close).
|
|
57
|
+
- HANDOFF lists a "next action" but uncommitted work in `git status` shows that action was started and abandoned.
|
|
58
|
+
- `tasks/prd-foo.md` exists but is not mentioned in HANDOFF (forgotten artifact).
|
|
59
|
+
- Brief says profile is `booking` but the codebase has no booking-related files.
|
|
60
|
+
|
|
61
|
+
## Step 3: print the resume brief
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
RESUMED
|
|
65
|
+
|
|
66
|
+
Last commit: <SHA + subject>
|
|
67
|
+
Working tree: <clean | N dirty files: list>
|
|
68
|
+
HANDOFF claim: <one-line status>
|
|
69
|
+
Git reality: <does it match? if not, what's the gap?>
|
|
70
|
+
|
|
71
|
+
In-flight (uncommitted) work:
|
|
72
|
+
<git status summary>
|
|
73
|
+
|
|
74
|
+
What the brief expects (if brief exists):
|
|
75
|
+
<profile + add-ons + must-have sections>
|
|
76
|
+
|
|
77
|
+
Queued from HANDOFF:
|
|
78
|
+
1. <action>
|
|
79
|
+
2. <action>
|
|
80
|
+
|
|
81
|
+
Mismatches surfaced:
|
|
82
|
+
- <mismatch 1, or "none">
|
|
83
|
+
- <mismatch 2>
|
|
84
|
+
|
|
85
|
+
Recommended next move:
|
|
86
|
+
<pick one: continue queued action / resolve mismatch / pivot>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Step 4: ask before doing
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Continue with the recommended next move? Or pivot?
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Wait for confirmation. Do NOT modify any files until the operator picks.
|
|
96
|
+
|
|
97
|
+
## Hard rules
|
|
98
|
+
|
|
99
|
+
- Never silently rewrite HANDOFF to match git. Surface the mismatch; let the operator decide.
|
|
100
|
+
- Never silently amend or rebase to "fix" git history.
|
|
101
|
+
- If `git status` shows uncommitted changes that the operator might not remember making, ask before doing anything that could lose them.
|
|
102
|
+
- This command is read-only by default. The only writes are after the operator confirms the next move.
|
package/templates/AGENTS.md
CHANGED
|
@@ -27,12 +27,23 @@ Operator materials live in `{{INPUTS_PATH}}`. Read `{{INPUTS_PATH}}README.md` fo
|
|
|
27
27
|
|
|
28
28
|
## Slash commands available
|
|
29
29
|
|
|
30
|
-
Session lifecycle: `/bootstrap`, `/prompt-start`, `/prompt-mid`, `/prompt-end`, `/preflight`
|
|
30
|
+
Session lifecycle: `/bootstrap`, `/prompt-start`, `/prompt-mid`, `/prompt-end`, `/preflight`, `/resume`, `/handoff-doctor`
|
|
31
31
|
|
|
32
|
-
Building: `/create-prd`, `/generate-tasks`, `/update-image`, `/update-gui`, `/update-backend`, `/add-storage`, `/generate-image-prompt`, `/generate-image`
|
|
32
|
+
Building: `/create-prd`, `/break-into-stories`, `/generate-tasks`, `/update-image`, `/update-gui`, `/update-backend`, `/add-storage`, `/generate-image-prompt`, `/generate-image`
|
|
33
33
|
|
|
34
34
|
See each file under `.claude/commands/` for the full routine.
|
|
35
35
|
|
|
36
|
+
## ostup CLI subcommands (run outside Claude Code)
|
|
37
|
+
|
|
38
|
+
- `ostup brief` — 10-question operator intake; writes `docs/brief.md`, `docs/brief.json`, `tasks/prd-initial-build.md`.
|
|
39
|
+
- `ostup init --brief <path>` — scaffold using an existing brief.json; applies the matching profile overlay.
|
|
40
|
+
- `ostup init` — interactive scaffold without brief.
|
|
41
|
+
|
|
36
42
|
## Helpers
|
|
37
43
|
|
|
38
44
|
- `scripts/screenshot.sh <url> [out] [WxH]` — headless Chrome screenshot. Required for visual verification per `CLAUDE.md` Part 19.
|
|
45
|
+
- `scripts/verify.sh [profile] [deploy_url]` — profile-aware verification gate. Auto-detects profile from `docs/brief.json` and deploy URL from `.vercel/project.json`. Runs common checks (build, env, live URL) plus profile-specific checks (e.g. `/api/contact` for lead-gen, `/rss.xml` for blog).
|
|
46
|
+
|
|
47
|
+
## If `docs/brief.md` is present in this project
|
|
48
|
+
|
|
49
|
+
Treat it as authoritative for scope, profile, brand, business model, and constraints. Downstream commands (`/create-prd`, `/generate-tasks`, etc.) should read `docs/brief.json` first to avoid re-asking the operator the same questions. Profile-specific guidance lives at `templates/profiles/<profile>/` (copied into your project root as `README.md` and `section-prompts.md` when the overlay is applied).
|
package/templates/CLAUDE.md
CHANGED
|
@@ -227,6 +227,9 @@ Detailed file map: `docs/ARCHITECTURE.md`.
|
|
|
227
227
|
> Things unique to THIS repo. Filled by `/bootstrap` or as discovered.
|
|
228
228
|
|
|
229
229
|
- Operator materials live in `{{INPUTS_PATH}}`. Read `{{INPUTS_PATH}}README.md` for the layout. If `{{INPUTS_PATH}}INGEST_MANIFEST.md` exists, read it before starting work.
|
|
230
|
+
- If `docs/brief.md` exists, it is the **authoritative source** for scope, profile, brand, business model, and constraints. Read `docs/brief.json` for the machine-readable version. Do not re-ask the operator the questions already answered there.
|
|
231
|
+
- If `tasks/prd-initial-build.md` exists, it is the **first PRD seed** generated from the brief. Start there before writing code.
|
|
232
|
+
- If a `README.md` and `section-prompts.md` exist at the project root from a profile overlay (e.g. `lead-gen`, `booking`, `saas-dashboard`, `blog`), follow that profile's hard rules and section guidance.
|
|
230
233
|
- {{CONVENTION_1}}
|
|
231
234
|
- {{CONVENTION_2}}
|
|
232
235
|
- {{CONVENTION_3}}
|
package/templates/START_HERE.md
CHANGED
|
@@ -17,9 +17,9 @@ Or use `codex`, `gemini`, or whichever CLI agent you prefer.
|
|
|
17
17
|
### 2. Paste this as your first message
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
Read CLAUDE.md, AGENTS.md, and everything in {{INPUTS_PATH}}. If {{INPUTS_PATH}} has source materials (research, reference repos, brand assets, notes), use them as context. If it is empty or only has a README, that is fine. Either way, ask me up to 3 clarifying questions about what I want to build. Then propose a 30 to 60 minute MVP scope as a numbered list. Do not write code until I approve the scope.
|
|
20
|
+
Read CLAUDE.md, AGENTS.md, docs/brief.md (if it exists), tasks/prd-initial-build.md (if it exists), and everything in {{INPUTS_PATH}}. If {{INPUTS_PATH}} has source materials (research, reference repos, brand assets, notes), use them as context. If it is empty or only has a README, that is fine. Either way, ask me up to 3 clarifying questions about what I want to build. Then propose a 30 to 60 minute MVP scope as a numbered list. Do not write code until I approve the scope.
|
|
21
21
|
|
|
22
|
-
After I approve, run /bootstrap to fill in this project's metadata, then start building.
|
|
22
|
+
After I approve, run /bootstrap to fill in this project's metadata, then start building. If docs/brief.md exists, treat it as authoritative for scope, brand, and constraints.
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
That is the whole jump-in. The agent reads, asks, proposes, you approve, it builds.
|
|
@@ -38,6 +38,10 @@ That is the whole jump-in. The agent reads, asks, proposes, you approve, it buil
|
|
|
38
38
|
| `docs/ARCHITECTURE.md` | Stack, file map, env vars, deploy details. | Agent |
|
|
39
39
|
| `{{INPUTS_PATH}}` | Your source materials. May be empty. You can add files anytime. | Both |
|
|
40
40
|
| `tasks/` | PRDs and task lists for features. | Both |
|
|
41
|
+
| `docs/brief.md` | Operator brief (only if you scaffolded with `ostup brief`). Source of truth for scope, brand, constraints. | Both |
|
|
42
|
+
| `docs/brief.json` | Machine-readable brief (same trigger). Used by downstream commands. | Agent |
|
|
43
|
+
| `tasks/prd-initial-build.md` | Auto-seeded first PRD from the brief (same trigger). | Both |
|
|
44
|
+
| `templates/profiles/<profile>/` | (if applicable) Profile-specific guidance the agent reads on day one. | Agent |
|
|
41
45
|
| `.claude/commands/` | Slash command definitions. | Agent |
|
|
42
46
|
|
|
43
47
|
## Slash commands
|
|
@@ -59,6 +63,9 @@ Type these in your CLI agent. Each runs a structured routine.
|
|
|
59
63
|
| `/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. |
|
|
60
64
|
| `/generate-image-prompt` | Compose an image-generation prompt from the project brief + 2-3 questions. No API call. Paste the prompt into your preferred image tool. | When you need a visual asset and want to use Midjourney, DALL-E, Imagen, etc. directly. |
|
|
61
65
|
| `/generate-image` | Compose the prompt AND call Vercel AI Gateway, saving the image to `inputs/images/`. Requires `VERCEL_AI_GATEWAY_KEY`. | When you want the image generated in-line without leaving your agent. |
|
|
66
|
+
| `/resume` | Read git diff + HANDOFF + tasks + brief, surface mismatches between claimed and actual state. | When HANDOFF.md feels stale, you came back after several days, or something feels off about the briefing. |
|
|
67
|
+
| `/handoff-doctor` | Audit HANDOFF.md against actual repo reality (commits, working tree, files, tasks, manual blockers). Read-only punch list. | Before `/prompt-start` if you suspect HANDOFF is wrong; after a long AFK session. |
|
|
68
|
+
| `/break-into-stories` | Break a PRD into 3-7 vertical, shippable stories before generating granular tasks. | Between `/create-prd` and `/generate-tasks` for any non-trivial feature. |
|
|
62
69
|
|
|
63
70
|
## Three workflows
|
|
64
71
|
|
|
@@ -66,13 +73,13 @@ Type these in your CLI agent. Each runs a structured routine.
|
|
|
66
73
|
|
|
67
74
|
1. `claude` in this folder.
|
|
68
75
|
2. Paste the prompt from step 2 above.
|
|
69
|
-
3. The agent reads everything, asks 2 or 3 questions, proposes an MVP.
|
|
76
|
+
3. The agent reads everything (including `docs/brief.md` if present), asks 2 or 3 questions, proposes an MVP.
|
|
70
77
|
4. You approve (or refine).
|
|
71
78
|
5. The agent runs `/bootstrap` to fill in project metadata.
|
|
72
79
|
6. The agent builds the first cut and pushes commits.
|
|
73
80
|
7. `/prompt-end` when you stop.
|
|
74
81
|
|
|
75
|
-
Works the same whether `{{INPUTS_PATH}}` is empty or full. With materials, the agent uses them. Without, it asks you what to build outright.
|
|
82
|
+
Works the same whether `{{INPUTS_PATH}}` is empty or full. With materials, the agent uses them. Without, it asks you what to build outright. If you scaffolded with `ostup brief` or `ostup init --brief`, the agent has a richer starting point: scope, profile, business model, and add-ons already chosen.
|
|
76
83
|
|
|
77
84
|
### B. Return session (pick up where you left off)
|
|
78
85
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Profile: blog
|
|
2
|
+
|
|
3
|
+
> Content engine. MDX posts, RSS, sitemap, tag/author pages. SEO-first. No CMS v1.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Homepage | Latest 6-10 posts, intro paragraph | yes |
|
|
10
|
+
| Post page | Single post by slug, MDX-rendered | yes |
|
|
11
|
+
| Tag index | List of all tags with post counts | yes |
|
|
12
|
+
| Tag page | All posts under a tag | yes |
|
|
13
|
+
| Author page (if multi-author) | Author bio + their posts | conditional |
|
|
14
|
+
| RSS feed | `/rss.xml` valid RSS 2.0 | yes |
|
|
15
|
+
| Sitemap | `/sitemap.xml` valid sitemap | yes |
|
|
16
|
+
| About | Static about page | yes |
|
|
17
|
+
| Footer | Links, RSS, year | yes |
|
|
18
|
+
|
|
19
|
+
## Wired infrastructure
|
|
20
|
+
|
|
21
|
+
- **MDX** for post bodies. Posts live as `.mdx` files in `content/posts/`.
|
|
22
|
+
- Frontmatter schema: `title`, `slug`, `date`, `tags[]`, `author?`, `description?`, `draft?`.
|
|
23
|
+
- `next-mdx-remote` or `@next/mdx` (agent picks; both work).
|
|
24
|
+
- Open Graph + Twitter card metadata per post.
|
|
25
|
+
- Article + Organization JSON-LD schema.
|
|
26
|
+
|
|
27
|
+
## Env additions
|
|
28
|
+
|
|
29
|
+
See `.env.example.additions` (mostly empty for blog v1).
|
|
30
|
+
|
|
31
|
+
## File contracts
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
content/posts/<slug>.mdx
|
|
35
|
+
---
|
|
36
|
+
title: "Post title"
|
|
37
|
+
slug: "post-slug"
|
|
38
|
+
date: "2026-05-21"
|
|
39
|
+
tags: ["agents", "tooling"]
|
|
40
|
+
author: "GG"
|
|
41
|
+
description: "One-sentence summary for SEO."
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
Body in MDX.
|
|
45
|
+
|
|
46
|
+
content/authors/<author>.mdx (optional)
|
|
47
|
+
---
|
|
48
|
+
name: "GG"
|
|
49
|
+
bio: "One-paragraph bio."
|
|
50
|
+
social: { x: "@goodshin", github: "DubsFan" }
|
|
51
|
+
---
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Hard rules
|
|
55
|
+
|
|
56
|
+
- Posts ship as committed MDX files. No DB v1.
|
|
57
|
+
- `draft: true` excludes from production builds AND from RSS/sitemap.
|
|
58
|
+
- RSS / sitemap regenerate on build.
|
|
59
|
+
- Code blocks use one syntax highlighter (Shiki recommended). Pick at build time, not client-side.
|
|
60
|
+
- Reading width capped at 720px or so for body comfort.
|
|
61
|
+
- Light + dark mode via `prefers-color-scheme`.
|
|
62
|
+
|
|
63
|
+
## Acceptance
|
|
64
|
+
|
|
65
|
+
- Homepage shows latest 6 posts sorted by date desc.
|
|
66
|
+
- Individual post page renders MDX with syntax-highlighted code.
|
|
67
|
+
- RSS feed validates at https://validator.w3.org/feed/.
|
|
68
|
+
- Sitemap includes every published post (no drafts).
|
|
69
|
+
- Tag pages reachable from each post's tag list.
|
|
70
|
+
- Lighthouse Performance >= 95 (static content, should be fast).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Blog profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief. Default MDX library: `next-mdx-remote`. Use `gray-matter` for frontmatter parsing.
|
|
4
|
+
|
|
5
|
+
## Homepage
|
|
6
|
+
|
|
7
|
+
- Title + tagline from the brief.
|
|
8
|
+
- Latest 6 posts: title (clickable), date, 1-2-sentence excerpt from `description` or first 160 chars of body.
|
|
9
|
+
- "All posts" link to a chronological archive (optional v1).
|
|
10
|
+
- Tag cloud or top 5 tags if there are 3+ tagged posts.
|
|
11
|
+
|
|
12
|
+
## Post page (`/posts/[slug]`)
|
|
13
|
+
|
|
14
|
+
- Title (h1), date, tags (clickable to tag pages), author (if multi-author).
|
|
15
|
+
- MDX-rendered body.
|
|
16
|
+
- Code blocks: syntax-highlighted with Shiki. Light + dark theme.
|
|
17
|
+
- Body width capped (~65ch).
|
|
18
|
+
- Reading time estimate (optional).
|
|
19
|
+
- Open Graph: title, description, type=article, published_time, author.
|
|
20
|
+
|
|
21
|
+
## Tag index (`/tags`)
|
|
22
|
+
|
|
23
|
+
- All tags from all published posts, sorted by post count desc.
|
|
24
|
+
- Each tag: name + post count + link.
|
|
25
|
+
|
|
26
|
+
## Tag page (`/tags/[tag]`)
|
|
27
|
+
|
|
28
|
+
- All posts under that tag, chronological desc.
|
|
29
|
+
- Same card format as homepage list.
|
|
30
|
+
|
|
31
|
+
## Author page (`/authors/[author]`) — only if multi-author
|
|
32
|
+
|
|
33
|
+
- Author bio from `content/authors/<author>.mdx`.
|
|
34
|
+
- All posts by that author.
|
|
35
|
+
|
|
36
|
+
## RSS feed (`/rss.xml`)
|
|
37
|
+
|
|
38
|
+
- RSS 2.0.
|
|
39
|
+
- Include title, link, description, pubDate, category for each post.
|
|
40
|
+
- Published posts only (`draft: false`).
|
|
41
|
+
- Validate the output structure manually before claiming done.
|
|
42
|
+
|
|
43
|
+
## Sitemap (`/sitemap.xml`)
|
|
44
|
+
|
|
45
|
+
- All published posts + tag pages + author pages + homepage + about.
|
|
46
|
+
- `<lastmod>` on each entry.
|
|
47
|
+
- No drafts.
|
|
48
|
+
|
|
49
|
+
## About
|
|
50
|
+
|
|
51
|
+
- Pulled from the brief: who runs the site, what it covers, contact.
|
|
52
|
+
- Single page. Plain text + maybe a portrait from `inputs/images/`.
|
|
53
|
+
|
|
54
|
+
## Footer
|
|
55
|
+
|
|
56
|
+
- RSS link with feed icon.
|
|
57
|
+
- GitHub link (if applicable).
|
|
58
|
+
- Year + copyright.
|
|
59
|
+
|
|
60
|
+
## First post
|
|
61
|
+
|
|
62
|
+
- If the brief mentions a launch announcement, write `content/posts/hello-world.mdx` as a placeholder with the project summary.
|
|
63
|
+
- Otherwise leave `content/posts/` with a `.gitkeep` only and let the operator write the first post.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# --- booking profile additions ---
|
|
2
|
+
# Database for Booking entity (Neon recommended; any Postgres works)
|
|
3
|
+
DATABASE_URL=
|
|
4
|
+
|
|
5
|
+
# Email confirmation
|
|
6
|
+
RESEND_API_KEY=
|
|
7
|
+
BOOKING_TO_EMAIL=
|
|
8
|
+
BOOKING_FROM_EMAIL=noreply@example.com
|
|
9
|
+
|
|
10
|
+
# Optional: Stripe deposit checkout (enable only if `payments` addon is on)
|
|
11
|
+
STRIPE_SECRET_KEY=
|
|
12
|
+
STRIPE_PUBLISHABLE_KEY=
|
|
13
|
+
STRIPE_WEBHOOK_SECRET=
|
|
14
|
+
|
|
15
|
+
# Public app URL (Vercel sets this for production)
|
|
16
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Profile: booking
|
|
2
|
+
|
|
3
|
+
> Appointment / reservation site. Availability request, booking form, optional Stripe deposit, email confirmations.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Hero | Single value statement + "Check availability" or "Book now" CTA | yes |
|
|
10
|
+
| Availability / Booking form | Date range or appointment slot picker + guest info | yes |
|
|
11
|
+
| Rooms / Services | List of bookable units with descriptions and rates | yes |
|
|
12
|
+
| Deposit checkout | Stripe Checkout for the deposit if `payments` addon is on | conditional |
|
|
13
|
+
| Confirmation email | Auto-send on submission to both guest and admin | yes |
|
|
14
|
+
| About / Amenities | Trust-building content from the brief | yes |
|
|
15
|
+
| Footer | Contact, cancellation policy summary | yes |
|
|
16
|
+
|
|
17
|
+
## Wired infrastructure
|
|
18
|
+
|
|
19
|
+
- **Postgres** for the `Booking` entity (date_start, date_end, guest info, status, deposit_status).
|
|
20
|
+
- **Resend** for guest + admin confirmation emails.
|
|
21
|
+
- **Stripe Checkout** for deposit (only if `payments` addon is on per the brief).
|
|
22
|
+
- Mobile-first calendar / date picker.
|
|
23
|
+
|
|
24
|
+
## Env additions
|
|
25
|
+
|
|
26
|
+
See `.env.example.additions`.
|
|
27
|
+
|
|
28
|
+
## API contracts
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
POST /api/booking/request
|
|
32
|
+
Body: { name, email, phone?, date_start, date_end, room_or_service?, notes? }
|
|
33
|
+
Response: { ok, booking_id }
|
|
34
|
+
Behavior: insert Booking with status='pending', email both parties.
|
|
35
|
+
|
|
36
|
+
POST /api/booking/deposit
|
|
37
|
+
Body: { booking_id }
|
|
38
|
+
Response: { ok, checkout_url }
|
|
39
|
+
Behavior: create Stripe Checkout session, return URL.
|
|
40
|
+
|
|
41
|
+
POST /api/webhooks/stripe
|
|
42
|
+
Behavior: on payment_intent.succeeded, mark booking deposit_status='paid'.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Hard rules
|
|
46
|
+
|
|
47
|
+
- Date pickers MUST be mobile-friendly (no tiny native date inputs without testing).
|
|
48
|
+
- Server-side validate the date range (no past dates, no end-before-start).
|
|
49
|
+
- Confirmation emails go out immediately on form submit, even before deposit.
|
|
50
|
+
- Deposit is OPTIONAL: if `payments` addon is off, skip Stripe entirely. Booking still goes through.
|
|
51
|
+
- Calendar availability check should be server-side; do not trust client.
|
|
52
|
+
- If `Booking.status` is 'pending' for >48h with no deposit, mark as 'expired'.
|
|
53
|
+
|
|
54
|
+
## Acceptance
|
|
55
|
+
|
|
56
|
+
- Visitor can request dates and submit.
|
|
57
|
+
- Both visitor and admin receive emails within 30 seconds.
|
|
58
|
+
- Deposit Checkout opens if enabled, completes round-trip to the booking record.
|
|
59
|
+
- Past dates rejected with clear error.
|
|
60
|
+
- Hero CTA above the fold at 420x900.
|
|
61
|
+
- Lighthouse mobile Performance >= 85 (acceptable lower than marketing because of date picker JS).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Booking profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief in `docs/brief.md`. Honor `must_avoid` strictly.
|
|
4
|
+
|
|
5
|
+
## Hero
|
|
6
|
+
|
|
7
|
+
- Headline (5-9 words) about the experience being booked.
|
|
8
|
+
- Subhead: one sentence on what the visitor gets when they book.
|
|
9
|
+
- Primary CTA: "Check availability" or "Book now" — opens the booking form modal or scrolls to it.
|
|
10
|
+
|
|
11
|
+
## Availability / Booking form
|
|
12
|
+
|
|
13
|
+
- Date range picker (or single-date for appointments). Mobile-friendly is mandatory.
|
|
14
|
+
- Guest info: name, email, phone, party size (if relevant), notes.
|
|
15
|
+
- Validate server-side: no past dates, end after start, party size within room limits.
|
|
16
|
+
- Loading state on submit. Success state with booking ID. Error state with clear message.
|
|
17
|
+
|
|
18
|
+
## Rooms / Services
|
|
19
|
+
|
|
20
|
+
- Pull entity list from the brief's `data_model.entities`. If a Room entity exists, list its fields visually.
|
|
21
|
+
- Each unit: name, description (short), rate per night/hour, photo placeholder if `inputs/images/` has anything matching.
|
|
22
|
+
- "Book this" CTA scrolls back to the booking form with the room pre-selected.
|
|
23
|
+
|
|
24
|
+
## Deposit checkout (conditional)
|
|
25
|
+
|
|
26
|
+
- Only render if `payments` addon is in the brief.
|
|
27
|
+
- After successful booking submission, present a "Pay deposit to confirm" CTA.
|
|
28
|
+
- Clicking opens Stripe Checkout via `/api/booking/deposit`.
|
|
29
|
+
- On Checkout success, return to a `/booking/[id]/confirmed` page.
|
|
30
|
+
- Webhook `/api/webhooks/stripe` updates `deposit_status='paid'`.
|
|
31
|
+
|
|
32
|
+
## Confirmation emails
|
|
33
|
+
|
|
34
|
+
- Guest receives: "Your booking request is in. We'll confirm within X hours. Booking ID: ABC123."
|
|
35
|
+
- Admin receives: full booking details + a link to the admin route (TBD v2).
|
|
36
|
+
- Use Resend. Plain text + HTML versions.
|
|
37
|
+
|
|
38
|
+
## About / Amenities
|
|
39
|
+
|
|
40
|
+
- Pull from the brief's `must_have_sections`. Echo the brief's vibe.
|
|
41
|
+
- Photos from `inputs/images/` if any. Otherwise text-only placeholders.
|
|
42
|
+
|
|
43
|
+
## Footer
|
|
44
|
+
|
|
45
|
+
- Cancellation policy summary (1-2 sentences from the brief or a placeholder asking the operator).
|
|
46
|
+
- Contact email + phone.
|
|
47
|
+
- Year + copyright.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Profile: lead-gen
|
|
2
|
+
|
|
3
|
+
> Service-company site that captures contact requests. Resend for email, optional CRM webhook, local SEO basics.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Hero | Single value statement + primary CTA "Request a quote" or "Contact us" | yes |
|
|
10
|
+
| Services | 3-8 service cards or list. Tap-to-call on mobile. | yes |
|
|
11
|
+
| Service area | Map placeholder OR text list of cities / zip codes covered | yes |
|
|
12
|
+
| Testimonials | 2-4 quotes (placeholders OK if brief has none) | yes |
|
|
13
|
+
| FAQ | 4-8 questions, accordion or stacked | yes |
|
|
14
|
+
| Contact form | Name, phone, email, message. Posts to /api/contact. | yes |
|
|
15
|
+
| Footer | Phone, email, license number if applicable, year | yes |
|
|
16
|
+
|
|
17
|
+
## Wired infrastructure
|
|
18
|
+
|
|
19
|
+
- **Resend** for email notifications when a lead submits the form.
|
|
20
|
+
- Optional **CRM webhook** (env: `CRM_WEBHOOK_URL`). If set, also POST the lead payload as JSON.
|
|
21
|
+
- **JSON-LD LocalBusiness schema** in the head of every page.
|
|
22
|
+
- Open Graph + Twitter metadata using `{{DISPLAY_NAME}}` and the brand summary.
|
|
23
|
+
|
|
24
|
+
## Env additions
|
|
25
|
+
|
|
26
|
+
See `.env.example.additions` for the variables this profile expects.
|
|
27
|
+
|
|
28
|
+
## API contract for /api/contact
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
POST /api/contact
|
|
32
|
+
Content-Type: application/json
|
|
33
|
+
Body: { name: string, email: string, phone?: string, message: string }
|
|
34
|
+
Response: { ok: boolean, id?: string }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The route:
|
|
38
|
+
1. Validates required fields (name, email, message).
|
|
39
|
+
2. Sends an email via Resend to `CONTACT_TO_EMAIL` from `CONTACT_FROM_EMAIL`.
|
|
40
|
+
3. If `CRM_WEBHOOK_URL` is set, POSTs the lead payload there.
|
|
41
|
+
4. Returns 200 with `{ ok: true }` on success; 400 on validation; 500 on send failure.
|
|
42
|
+
|
|
43
|
+
No persistent storage v1. Leads live in the operator's email inbox.
|
|
44
|
+
|
|
45
|
+
## Hard rules
|
|
46
|
+
|
|
47
|
+
- Phone number on every page (mobile sticky CTA acceptable).
|
|
48
|
+
- Service area is explicit. Do not claim to cover areas the brief does not mention.
|
|
49
|
+
- No JS-heavy carousels. Stacked content reads better on phones.
|
|
50
|
+
- Honor `constraints.must_avoid` strictly.
|
|
51
|
+
|
|
52
|
+
## Acceptance
|
|
53
|
+
|
|
54
|
+
- Visitor can submit the contact form, sees an inline success state.
|
|
55
|
+
- Owner receives the lead by email at the address in `CONTACT_TO_EMAIL`.
|
|
56
|
+
- JSON-LD LocalBusiness schema validates at https://search.google.com/test/rich-results.
|
|
57
|
+
- Hero CTA above the fold at 420x900.
|
|
58
|
+
- Lighthouse mobile Performance >= 90, Accessibility >= 95.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Lead-gen profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief in `docs/brief.md`. Do not invent service offerings, prices, or testimonials.
|
|
4
|
+
|
|
5
|
+
## Hero
|
|
6
|
+
|
|
7
|
+
- Headline: 5-9 words. Echo the project summary in the operator's voice.
|
|
8
|
+
- Subhead: one sentence on who it serves and what they get.
|
|
9
|
+
- Primary CTA: "Request a quote" or "Contact us today" (use the brief's wording if it specifies).
|
|
10
|
+
- Secondary trust signal: years in business, license number, or service area at a glance (only if in brief).
|
|
11
|
+
|
|
12
|
+
## Services
|
|
13
|
+
|
|
14
|
+
- List 3-8 services from the brief's `scope.must_have_sections` (filter out non-service sections like hero/footer/contact).
|
|
15
|
+
- Each service card: short title + one or two sentences + (if available from brief) a starting-price hint.
|
|
16
|
+
- Tap-to-call phone link visible on mobile.
|
|
17
|
+
|
|
18
|
+
## Service area
|
|
19
|
+
|
|
20
|
+
- If the brief mentions specific cities, towns, or zip codes, list them.
|
|
21
|
+
- If only a general area, use that phrasing exactly.
|
|
22
|
+
- If no specific area info: ask the operator to fill in `docs/brief.md` before building this section. Do NOT default to "nationwide."
|
|
23
|
+
|
|
24
|
+
## Testimonials
|
|
25
|
+
|
|
26
|
+
- 2-4 short quotes. If the brief has actual quotes, use them.
|
|
27
|
+
- If none: use clear placeholders like `[Testimonial pending — operator to add]` and DO NOT fabricate.
|
|
28
|
+
|
|
29
|
+
## FAQ
|
|
30
|
+
|
|
31
|
+
- 4-8 questions tied to the services from the brief.
|
|
32
|
+
- Suggested defaults: "How fast can you get here?", "Do you provide free estimates?", "Are you licensed and insured?", "Do you offer financing?". Match to the brief's business model.
|
|
33
|
+
- Use an accordion or stacked Q/A. No JS framework needed.
|
|
34
|
+
|
|
35
|
+
## Contact form
|
|
36
|
+
|
|
37
|
+
- Fields: name (required), email (required), phone (optional), message (required).
|
|
38
|
+
- POSTs to `/api/contact`.
|
|
39
|
+
- Inline success message on submit: "Got it. We will be in touch within one business day."
|
|
40
|
+
- On error: inline message with retry, never alert dialogs.
|
|
41
|
+
- Form labels visible, not just placeholders (accessibility).
|
|
42
|
+
|
|
43
|
+
## Footer
|
|
44
|
+
|
|
45
|
+
- Phone, email, address (if relevant), license number (if relevant).
|
|
46
|
+
- Current year, copyright.
|
|
47
|
+
- Privacy / Terms links if the operator has them (otherwise omit; do not invent legalese).
|