qualia-framework 6.8.0 → 6.9.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/CHANGELOG.md +32 -0
- package/bin/install.js +212 -17
- package/bin/state.js +70 -5
- package/docs/EMPLOYEE-QUICKSTART.md +162 -0
- package/package.json +2 -1
- package/skills/qualia-doctor/SKILL.md +62 -0
- package/skills/qualia-new/REFERENCE.md +7 -0
- package/skills/qualia-new/SKILL.md +42 -0
- package/skills/qualia-report/SKILL.md +13 -0
- package/templates/stacks/README.md +110 -0
- package/templates/stacks/ai-agent/env.required.json +44 -0
- package/templates/stacks/ai-agent/phases.md +53 -0
- package/templates/stacks/ai-agent/scaffold/.env.example +12 -0
- package/templates/stacks/ai-agent/scaffold/README.md +31 -0
- package/templates/stacks/ai-agent/scaffold/app/api/chat/route.ts +33 -0
- package/templates/stacks/ai-agent/scaffold/app/globals.css +13 -0
- package/templates/stacks/ai-agent/scaffold/app/layout.tsx +19 -0
- package/templates/stacks/ai-agent/scaffold/app/page.tsx +12 -0
- package/templates/stacks/ai-agent/scaffold/evals/cases.json +23 -0
- package/templates/stacks/ai-agent/scaffold/lib/openrouter/client.ts +51 -0
- package/templates/stacks/ai-agent/scaffold/lib/prompts/system.ts +6 -0
- package/templates/stacks/ai-agent/scaffold/lib/supabase/client.ts +10 -0
- package/templates/stacks/ai-agent/scaffold/lib/supabase/server.ts +28 -0
- package/templates/stacks/ai-agent/scaffold/next.config.mjs +7 -0
- package/templates/stacks/ai-agent/scaffold/package.json +29 -0
- package/templates/stacks/ai-agent/scaffold/postcss.config.mjs +7 -0
- package/templates/stacks/ai-agent/scaffold/supabase/migrations/0001_init.sql +41 -0
- package/templates/stacks/ai-agent/scaffold/tsconfig.json +21 -0
- package/templates/stacks/ai-agent/stack.json +9 -0
- package/templates/stacks/ai-agent/verify-checklist.md +31 -0
- package/templates/stacks/full-app/env.required.json +20 -0
- package/templates/stacks/full-app/phases.md +45 -0
- package/templates/stacks/full-app/scaffold/.env.example +7 -0
- package/templates/stacks/full-app/scaffold/README.md +28 -0
- package/templates/stacks/full-app/scaffold/app/globals.css +14 -0
- package/templates/stacks/full-app/scaffold/app/layout.tsx +19 -0
- package/templates/stacks/full-app/scaffold/app/page.tsx +20 -0
- package/templates/stacks/full-app/scaffold/lib/supabase/client.ts +10 -0
- package/templates/stacks/full-app/scaffold/lib/supabase/server.ts +31 -0
- package/templates/stacks/full-app/scaffold/next.config.mjs +7 -0
- package/templates/stacks/full-app/scaffold/package.json +29 -0
- package/templates/stacks/full-app/scaffold/postcss.config.mjs +7 -0
- package/templates/stacks/full-app/scaffold/supabase/migrations/0001_init.sql +27 -0
- package/templates/stacks/full-app/scaffold/tsconfig.json +21 -0
- package/templates/stacks/full-app/stack.json +9 -0
- package/templates/stacks/full-app/verify-checklist.md +32 -0
- package/templates/stacks/internal-tool/env.required.json +20 -0
- package/templates/stacks/internal-tool/phases.md +45 -0
- package/templates/stacks/internal-tool/scaffold/.env.example +7 -0
- package/templates/stacks/internal-tool/scaffold/README.md +29 -0
- package/templates/stacks/internal-tool/scaffold/app/globals.css +13 -0
- package/templates/stacks/internal-tool/scaffold/app/layout.tsx +20 -0
- package/templates/stacks/internal-tool/scaffold/app/page.tsx +22 -0
- package/templates/stacks/internal-tool/scaffold/lib/supabase/client.ts +9 -0
- package/templates/stacks/internal-tool/scaffold/lib/supabase/server.ts +28 -0
- package/templates/stacks/internal-tool/scaffold/next.config.mjs +6 -0
- package/templates/stacks/internal-tool/scaffold/package.json +29 -0
- package/templates/stacks/internal-tool/scaffold/postcss.config.mjs +7 -0
- package/templates/stacks/internal-tool/scaffold/supabase/migrations/0001_init.sql +28 -0
- package/templates/stacks/internal-tool/scaffold/tsconfig.json +21 -0
- package/templates/stacks/internal-tool/stack.json +9 -0
- package/templates/stacks/internal-tool/verify-checklist.md +31 -0
- package/templates/stacks/landing-page/env.required.json +8 -0
- package/templates/stacks/landing-page/phases.md +42 -0
- package/templates/stacks/landing-page/scaffold/.env.example +3 -0
- package/templates/stacks/landing-page/scaffold/README.md +25 -0
- package/templates/stacks/landing-page/scaffold/app/globals.css +14 -0
- package/templates/stacks/landing-page/scaffold/app/layout.tsx +19 -0
- package/templates/stacks/landing-page/scaffold/app/page.tsx +21 -0
- package/templates/stacks/landing-page/scaffold/next.config.mjs +7 -0
- package/templates/stacks/landing-page/scaffold/package.json +26 -0
- package/templates/stacks/landing-page/scaffold/postcss.config.mjs +7 -0
- package/templates/stacks/landing-page/scaffold/tsconfig.json +21 -0
- package/templates/stacks/landing-page/stack.json +9 -0
- package/templates/stacks/landing-page/verify-checklist.md +28 -0
- package/tests/bin.test.sh +3 -3
- package/tests/state.test.sh +83 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Qualia Framework — Employee Quickstart
|
|
2
|
+
|
|
3
|
+
A five-minute path from a fresh machine to a shipped, reported day of work. This is the route for a **new employee who does not have a team install code yet**. You can install and do real work in employee mode today; the OWNER (Fawzi) issues the keys that unlock ERP reporting and any direct provider integrations.
|
|
4
|
+
|
|
5
|
+
Who issues credentials: **the OWNER (Fawzi) issues every key** — team install codes, the ERP API key, OpenRouter / Supabase / Vercel / Retell / ElevenLabs / Telnyx credentials. If a step says "ask Fawzi", that is who to ask. Never share or reuse another person's key.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The path
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
install (employee mode) → /qualia-doctor → /qualia-new (pick preset) → build/verify loop → /qualia-ship → report
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Install — employee mode (no team code needed)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx qualia-framework@latest install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
At the prompt:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Install code or "EMPLOYEE":
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Have a team code (`QS-NAME-##`)? Enter it — you install as that team member.
|
|
30
|
+
- **No code yet?** Type **`EMPLOYEE`**. You install at the least-privilege role: feature branches only, no pushes to `main` (enforced by the `branch-guard` hook). The full framework — skills, agents, hooks, knowledge — is installed exactly the same.
|
|
31
|
+
|
|
32
|
+
What employee mode changes vs. a coded install:
|
|
33
|
+
|
|
34
|
+
| | Coded install (team member) | Employee mode (no code) |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| Role | OWNER or EMPLOYEE per code | EMPLOYEE |
|
|
37
|
+
| Skills / agents / hooks | full | full |
|
|
38
|
+
| Push to `main` | OWNER only | blocked |
|
|
39
|
+
| ERP reporting | on (with API key) | **off** until a code/key is set |
|
|
40
|
+
| `/qualia-report` | uploads to ERP | saves a **local** report file |
|
|
41
|
+
|
|
42
|
+
**Credentials this step needs:** none. That's the point — you can start immediately.
|
|
43
|
+
|
|
44
|
+
To upgrade to a real team identity later: ask Fawzi for your `QS-NAME-##` code, then re-run `npx qualia-framework install` and enter it. That flips ERP reporting back on (you'll also need the ERP API key — see step 6).
|
|
45
|
+
|
|
46
|
+
### Optional: shared team knowledge mirror
|
|
47
|
+
|
|
48
|
+
The installer can pull a **read-only** copy of the team's shared knowledge wiki (`qualia-memory`) into `~/.claude/knowledge/shared/` so you start with the team's accumulated patterns and fixes. It is **opt-in and copy-on-install only** — not a live sync.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Local checkout of the knowledge repo:
|
|
52
|
+
QUALIA_KNOWLEDGE_SOURCE=/path/to/qualia-memory npx qualia-framework@latest install
|
|
53
|
+
|
|
54
|
+
# Or a git URL (ask Fawzi for access if the repo is private):
|
|
55
|
+
QUALIA_KNOWLEDGE_SOURCE=https://github.com/Qualiasolutions/qualia-memory.git \
|
|
56
|
+
npx qualia-framework@latest install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `QUALIA_KNOWLEDGE_SOURCE` — a local path **or** a git URL. Unset → the pull is skipped silently.
|
|
60
|
+
- `QUALIA_KNOWLEDGE_SUBPATH` — subdirectory inside the source to copy (default `wiki/_export`).
|
|
61
|
+
- The mirror lands at `~/.claude/knowledge/shared/` with every file marked read-only. Your own learnings still go through `/qualia-learn` into your personal knowledge files — the shared mirror is reference material, refreshed on each install/update.
|
|
62
|
+
- If the source is unreachable (no git, offline, missing path, private-repo auth fail) the installer **warns and continues** — it never blocks the install.
|
|
63
|
+
|
|
64
|
+
**Credentials this step needs:** read access to the `qualia-memory` repo if you use a private git URL — ask Fawzi.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 2. `/qualia-doctor` — confirm the install is healthy
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
/qualia-doctor
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Checks install integrity, hooks, project state, contracts, memory, and the ERP queue. In employee mode it will report ERP as disabled — that is expected and not an error. Fix anything it flags before starting real work.
|
|
75
|
+
|
|
76
|
+
**Credentials this step needs:** none.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 3. `/qualia-new` — start a project (pick a preset)
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
/qualia-new
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Runs the kickoff interview, researches the domain, and writes the planning substrate (`JOURNEY.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `CONTEXT.md`). When prompted, pick the project **preset / type** that matches what you're building (e.g. landing page, full app, AI agent, internal tool). The preset seeds the milestone arc so you're not planning from a blank page.
|
|
87
|
+
|
|
88
|
+
**Credentials this step may need:**
|
|
89
|
+
- `OPENROUTER_API_KEY` — for any AI-assisted research/generation. Ask Fawzi for one.
|
|
90
|
+
- Provider keys (Supabase, Vercel, etc.) are not needed yet — they come in when you wire those services.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 4. Build / verify loop
|
|
95
|
+
|
|
96
|
+
Plan, build, and verify each phase:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
/qualia-plan # break the current phase into wave-grouped tasks
|
|
100
|
+
/qualia-build # execute the plan — builders + atomic commits
|
|
101
|
+
/qualia-verify # goal-backward check against acceptance criteria
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Iterate until the phase passes verification. Use `/qualia` at any point to ask "what's my next step?".
|
|
105
|
+
|
|
106
|
+
**Credentials this step needs:** whatever the feature touches —
|
|
107
|
+
- `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`, `SUPABASE_SERVICE_ROLE_KEY` for database work (service role key is **server-only**, never in client code).
|
|
108
|
+
- `OPENROUTER_API_KEY` for AI calls.
|
|
109
|
+
- Voice keys (`RETELL_API_KEY`, `ELEVENLABS_API_KEY`, `TELNYX_API_KEY`) for voice work.
|
|
110
|
+
|
|
111
|
+
Pull these into a project with `vercel env pull` once the project is linked. **Ask Fawzi for any key you don't have** — do not invent or hardcode keys, and never commit a `.env` file.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 5. `/qualia-ship` — deploy
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
/qualia-ship
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Runs the quality gates, commits, deploys (Vercel via CLI), and verifies. As an employee you ship through a **feature branch and review** — `branch-guard` blocks direct pushes to `main`. Deploys happen only through the CLI; GitHub auto-deploy is intentionally disabled.
|
|
122
|
+
|
|
123
|
+
**Credentials this step needs:**
|
|
124
|
+
- A Vercel login on the correct team (`vercel whoami`; `vercel link` if the project isn't linked). Ask Fawzi which Vercel team the project belongs to.
|
|
125
|
+
- Push access to the GitHub repo (org `QualiasolutionsCY` or `SakaniQualia`). Ask Fawzi to be added.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 6. Report — clock out
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
/qualia-report
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Generates your shift report, commits it to `.planning/reports/report-{date}.md`, and (when configured) uploads it to the ERP.
|
|
136
|
+
|
|
137
|
+
**In employee mode (no team code), the report degrades gracefully:** it is generated and committed **locally**, and you'll see a clear message that it was saved locally because no team code is set. Nothing fails. To start uploading reports to the ERP:
|
|
138
|
+
|
|
139
|
+
1. Get your team code (`QS-NAME-##`) from Fawzi and re-run `npx qualia-framework install` with it, **and**
|
|
140
|
+
2. Set the ERP API key (ask Fawzi for it):
|
|
141
|
+
```bash
|
|
142
|
+
printf '%s' "$QUALIA_ERP_KEY" | qualia-framework set-erp-key
|
|
143
|
+
```
|
|
144
|
+
Verify with `qualia-framework erp-ping`.
|
|
145
|
+
|
|
146
|
+
After that, `/qualia-report` uploads automatically and retries on transient ERP outages.
|
|
147
|
+
|
|
148
|
+
**Credentials this step needs:** a team code + the ERP API key — both issued by Fawzi. Until then, local reports are the expected behavior.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Quick reference
|
|
153
|
+
|
|
154
|
+
| Need | Command | Issued by |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| Install with no code | type `EMPLOYEE` at the prompt | — |
|
|
157
|
+
| Team code | re-run install, enter `QS-NAME-##` | Fawzi |
|
|
158
|
+
| ERP API key | `qualia-framework set-erp-key` (piped) | Fawzi |
|
|
159
|
+
| AI model access | `OPENROUTER_API_KEY` | Fawzi |
|
|
160
|
+
| Supabase / Vercel / Voice keys | `vercel env pull` once linked | Fawzi |
|
|
161
|
+
| Shared knowledge mirror | `QUALIA_KNOWLEDGE_SOURCE=... install` | repo access from Fawzi |
|
|
162
|
+
| "What's my next step?" | `/qualia` | — |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qualia-framework",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "Claude Code and Codex workflow framework by Qualia Solutions. Plan, build, verify, ship.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"qualia-framework": "./bin/cli.js"
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"docs/release.md",
|
|
53
53
|
"docs/changelog-v6.html",
|
|
54
54
|
"docs/onboarding.html",
|
|
55
|
+
"docs/EMPLOYEE-QUICKSTART.md",
|
|
55
56
|
"CLAUDE.md",
|
|
56
57
|
"AGENTS.md",
|
|
57
58
|
"guide.md",
|
|
@@ -112,6 +112,61 @@ If the queue fails with `401`, the ERP API key is invalid. Use:
|
|
|
112
112
|
printf '%s' "$QUALIA_ERP_KEY" | qualia-framework set-erp-key
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
## 7. Project Env & Auth Health
|
|
116
|
+
|
|
117
|
+
Verify the project has the env vars its stack preset requires, and that the CLIs the deploy pipeline needs are logged in. This is the gap that catches "it built fine locally but the deploy has no Supabase keys."
|
|
118
|
+
|
|
119
|
+
**Read the env contract.** `/qualia-new` writes it per stack preset to `.planning/env.required.json` (fallback `./env.required.json`). It is a JSON array of `{ name, purpose, howToObtain, ownerIssued }`. If neither file exists, print `Env: N/A (no env contract — run /qualia-new to lay down a stack preset)` and skip to CLI auth.
|
|
120
|
+
|
|
121
|
+
**Check each required var.** A var is PASS if it is present in the process env OR defined (non-empty value) in `.env.local`. Run this from the project root:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
ENVFILE=".planning/env.required.json"; [ -f "$ENVFILE" ] || ENVFILE="env.required.json"
|
|
125
|
+
if [ -f "$ENVFILE" ]; then
|
|
126
|
+
node -e '
|
|
127
|
+
const fs=require("fs");
|
|
128
|
+
const vars=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));
|
|
129
|
+
let local="";
|
|
130
|
+
try { local=fs.readFileSync(".env.local","utf8"); } catch {}
|
|
131
|
+
const inLocal=(n)=>new RegExp("^\\s*"+n+"\\s*=\\s*\\S","m").test(local);
|
|
132
|
+
for (const v of vars) {
|
|
133
|
+
const present = (process.env[v.name] && process.env[v.name].length>0) || inLocal(v.name);
|
|
134
|
+
if (present) { console.log("PASS "+v.name); continue; }
|
|
135
|
+
if (v.ownerIssued) {
|
|
136
|
+
console.log("FAIL "+v.name+" — MISSING. Owner-issued: ask the OWNER (Fawzi) for this key, then add it to .env.local");
|
|
137
|
+
} else {
|
|
138
|
+
console.log("FAIL "+v.name+" — MISSING. "+(v.howToObtain||"")+" Then add "+v.name+"=... to .env.local");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
' "$ENVFILE"
|
|
142
|
+
fi
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Print one PASS/FAIL line per var with the **exact** next action:
|
|
146
|
+
- Missing + `ownerIssued: true` → `ask the OWNER (Fawzi) for this key` (no self-serve command — only the OWNER issues it).
|
|
147
|
+
- Missing + `ownerIssued: false` → the var's `howToObtain` string, then `add {NAME}=... to .env.local`.
|
|
148
|
+
- Present → `PASS {NAME}`.
|
|
149
|
+
|
|
150
|
+
**Check CLI logins.** The deploy pipeline needs these authenticated. Each prints PASS or FAIL with the exact fix:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Vercel — needed for `vercel --prod`
|
|
154
|
+
vercel whoami >/dev/null 2>&1 && echo "PASS vercel (logged in)" \
|
|
155
|
+
|| echo "FAIL vercel — not logged in. Fix: vercel login"
|
|
156
|
+
|
|
157
|
+
# Supabase — CLI present + authenticated (projects list needs auth; version proves install)
|
|
158
|
+
supabase projects list >/dev/null 2>&1 && echo "PASS supabase (authenticated)" \
|
|
159
|
+
|| { supabase --version >/dev/null 2>&1 \
|
|
160
|
+
&& echo "FAIL supabase — installed but not authenticated. Fix: supabase login" \
|
|
161
|
+
|| echo "FAIL supabase — CLI missing. Fix: npm i -g supabase (or use npx supabase)"; }
|
|
162
|
+
|
|
163
|
+
# GitHub — needed for push / PRs
|
|
164
|
+
gh auth status >/dev/null 2>&1 && echo "PASS gh (authenticated)" \
|
|
165
|
+
|| echo "FAIL gh — not logged in. Fix: gh auth login"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Roll the worst result into the `Env` line of the Output block: all PASS → `PASS`; any owner-issued var missing → `BLOCKED (owner key needed)`; any other FAIL → `DEGRADED`.
|
|
169
|
+
|
|
115
170
|
## Output
|
|
116
171
|
|
|
117
172
|
End with:
|
|
@@ -127,10 +182,14 @@ Planning hygiene: ...
|
|
|
127
182
|
Memory: ...
|
|
128
183
|
Design/UI: ...
|
|
129
184
|
Employee experience: ...
|
|
185
|
+
Env: ...
|
|
186
|
+
CLI auth: ...
|
|
130
187
|
ERP: ...
|
|
131
188
|
Next: ...
|
|
132
189
|
```
|
|
133
190
|
|
|
191
|
+
`Env` summarizes section 7's env-var check (PASS / DEGRADED / BLOCKED (owner key needed) / N/A). `CLI auth` summarizes the vercel/supabase/gh login checks (PASS if all three are authenticated, else DEGRADED with the first failing CLI named).
|
|
192
|
+
|
|
134
193
|
## Rules
|
|
135
194
|
|
|
136
195
|
1. Read diagnostics before repair.
|
|
@@ -138,3 +197,6 @@ Next: ...
|
|
|
138
197
|
3. Treat missing contracts as degraded trust, not a project failure.
|
|
139
198
|
4. Prefer reinstall for missing framework files.
|
|
140
199
|
5. Prefer `state.js fix` only for malformed generated state.
|
|
200
|
+
6. **Never print secret values.** The env check reports presence (PASS/FAIL) only — never echo a key's contents.
|
|
201
|
+
7. **Owner-issued vars get the OWNER, not a command.** For a missing `ownerIssued: true` var, the only correct fix is "ask the OWNER (Fawzi) for this key" — never suggest a self-serve way to obtain it (per the no-proxy-approval rule).
|
|
202
|
+
8. Missing env contract is `N/A`, not a failure — it means no stack preset was laid down yet (`/qualia-new`).
|
|
@@ -84,6 +84,13 @@ User-scoped v1 features:
|
|
|
84
84
|
Template type: {template_type from config.json}
|
|
85
85
|
If set, use ${QUALIA_TEMPLATES}/projects/{type}.md as the milestone arc starting point.
|
|
86
86
|
|
|
87
|
+
Stack preset: {stack_id from config.json}
|
|
88
|
+
If .planning/phases.md exists (laid down by the Step 5a stack preset), read it as the
|
|
89
|
+
seed phase plan for Milestone 1 — it is tuned to this stack's archetype. The runnable
|
|
90
|
+
scaffold for this stack is already in the project root, so Milestone 1's foundation
|
|
91
|
+
phase should build ON the scaffold (auth wiring, first migration, first feature),
|
|
92
|
+
not re-scaffold from scratch.
|
|
93
|
+
|
|
87
94
|
<full_detail>{true if --full-detail, else false}</full_detail>
|
|
88
95
|
- false (default): Milestone 1 gets full phase detail; M2..M{N-1} stay as sketches. Detail fills in when each milestone opens via /qualia-milestone.
|
|
89
96
|
- true: every milestone (M1..Handoff) gets full phase-level detail in ROADMAP.md upfront. Useful when the client wants a fully-committed plan at kickoff.
|
|
@@ -124,6 +124,44 @@ If "More questions": re-invoke `/qualia-scope` for additional rounds. Otherwise
|
|
|
124
124
|
|
|
125
125
|
From questioning answers, infer type → `website` | `ai-agent` | `voice-agent` | `mobile-app` | `null`. If matched, `cat ${QUALIA_TEMPLATES}/projects/{type}.md` gives suggested milestone arc. Store `template_type` for Step 13.
|
|
126
126
|
|
|
127
|
+
### Step 5a. Stack Preset Gate + Instantiate (ONE question, then lay down the scaffold)
|
|
128
|
+
|
|
129
|
+
This is the **only** stack question. It selects one of four preset directories at `${QUALIA_TEMPLATES}/stacks/<id>/` and instantiates it. The preset carries the default tech, the env contract, the seed phase plan, and a runnable starter — so the project begins from a real skeleton, not an empty folder. Skip this step entirely on `--quick` (the quick wizard owns its own minimal layout).
|
|
130
|
+
|
|
131
|
+
Use **AskUserQuestion** (never a plain-text prompt):
|
|
132
|
+
|
|
133
|
+
- header: "Stack"
|
|
134
|
+
- question: "What kind of build is this? Pick one — it lays down the starter scaffold and the env it needs."
|
|
135
|
+
- options:
|
|
136
|
+
- "Landing page" — static marketing site, no database, no auth. (`landing-page`)
|
|
137
|
+
- "Full app" — authenticated product, Supabase + RLS + database. (`full-app`)
|
|
138
|
+
- "AI agent" — LLM/chat/voice agent, Supabase + OpenRouter. (`ai-agent`)
|
|
139
|
+
- "Internal tool" — staff portal, invite-only auth, role-gated. (`internal-tool`)
|
|
140
|
+
|
|
141
|
+
Map the answer to `STACK_ID` ∈ `{landing-page, full-app, ai-agent, internal-tool}`. Pre-select the option that matches `template_type` from Step 5 if one was detected (`website`→`landing-page`/`full-app`, `ai-agent`/`voice-agent`→`ai-agent`), but the user's pick always wins.
|
|
142
|
+
|
|
143
|
+
Then instantiate the preset (replace `<id>` with `STACK_ID`):
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
PRESET="${QUALIA_TEMPLATES}/stacks/${STACK_ID}"
|
|
147
|
+
|
|
148
|
+
# 1. Lay down the starter scaffold into the project root (skeleton, not an app).
|
|
149
|
+
# -n: never clobber a file the user already created.
|
|
150
|
+
mkdir -p .planning
|
|
151
|
+
cp -Rn "${PRESET}/scaffold/." . 2>/dev/null || true
|
|
152
|
+
|
|
153
|
+
# 2. Copy the env contract so /qualia-doctor can check it.
|
|
154
|
+
cp "${PRESET}/env.required.json" .planning/env.required.json
|
|
155
|
+
|
|
156
|
+
# 3. Seed the phase plan from the preset (roadmapper refines it in Step 13).
|
|
157
|
+
cp "${PRESET}/phases.md" .planning/phases.md
|
|
158
|
+
|
|
159
|
+
# 4. Keep the per-stack Definition-of-Done where verify can find it.
|
|
160
|
+
cp "${PRESET}/verify-checklist.md" .planning/verify-checklist.md
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Record the chosen stack in `config.json` (Step 9) as `"stack_id": "${STACK_ID}"`. The seed `phases.md` is the roadmapper's starting point at Step 13 — it reads `.planning/phases.md` (preset plan) alongside `${QUALIA_TEMPLATES}/projects/{template_type}.md` (milestone-arc hint) and the research synthesis, then writes the final ROADMAP.md. The scaffold gives Milestone 1 a real foundation to build on instead of an empty directory.
|
|
164
|
+
|
|
127
165
|
### Step 6. Design Direction (frontend only)
|
|
128
166
|
|
|
129
167
|
- header: "Design"
|
|
@@ -212,6 +250,7 @@ git commit -m "docs: PRODUCT.md — register, users, voice, anti-references"
|
|
|
212
250
|
"mode": "interactive",
|
|
213
251
|
"depth": "standard",
|
|
214
252
|
"template_type": "{detected or null}",
|
|
253
|
+
"stack_id": "{landing-page | full-app | ai-agent | internal-tool}",
|
|
215
254
|
"workflow": {
|
|
216
255
|
"research": true,
|
|
217
256
|
"plan_check": true,
|
|
@@ -220,6 +259,8 @@ git commit -m "docs: PRODUCT.md — register, users, voice, anti-references"
|
|
|
220
259
|
}
|
|
221
260
|
```
|
|
222
261
|
|
|
262
|
+
`stack_id` is the preset chosen at Step 5a. It tells `/qualia-doctor` which env contract to expect and `/qualia-verify` which per-stack Definition-of-Done to load.
|
|
263
|
+
|
|
223
264
|
**Note:** `workflow.research` is always `true`. It exists for telemetry but is no longer read as a gate.
|
|
224
265
|
|
|
225
266
|
### Step 10. Create DESIGN.md (frontend projects — OKLCH-first)
|
|
@@ -421,6 +462,7 @@ Do NOT use `--quick` for: client projects, anything with compliance stakes, anyt
|
|
|
421
462
|
## Rules
|
|
422
463
|
|
|
423
464
|
1. **Project type is the first question, period.** Step 1 (Demo / Full / Quick) is the literal first interaction with the user — even before "what are you building". Every downstream step branches on the answer. Don't skip it, don't infer it, don't ask anything before it.
|
|
465
|
+
1a. **One stack question, then a real scaffold.** Step 5a asks exactly ONE stack-preset question (`landing-page` / `full-app` / `ai-agent` / `internal-tool`) and then instantiates it: copies `scaffold/` into the project (never clobbering existing files), copies `env.required.json` → `.planning/env.required.json`, and copies `phases.md` → `.planning/phases.md`. The project starts from a runnable skeleton, not an empty folder. Skip this step on `--quick`. Record the choice as `config.json.stack_id`.
|
|
424
466
|
2. **AskUserQuestion for every discrete-choice question.** Project type, brownfield gate, design vibe, client type, approval gate, auto-chain — all use the interactive UI. The ONLY free-text question in the kickoff flow is the Step 3 one-line pitch. No plain-text prompts for anything that has a closed set of answers.
|
|
425
467
|
3. **No ad-hoc clarification questioning.** After Step 3 (one-line pitch), the next tool call is `/qualia-scope`. No "let me ask a few quick things first", no "that's too broad, can you clarify". Depth is the scope skill's job — not yours.
|
|
426
468
|
4. **Discovery interview is mandatory.** Step 4 always invokes `/qualia-scope` in PROJECT MODE. No free-form questioning loop, no "I'll just sketch PROJECT.md from the user's first message." The interview is 8 questions for demo, 14 for full project.
|
|
@@ -126,12 +126,15 @@ fi
|
|
|
126
126
|
### Step 6 — Upload to ERP
|
|
127
127
|
|
|
128
128
|
The full payload-builder + 3-attempt-retry logic lives unchanged from v4 — see the **ERP Upload** section below for the canonical implementation. Behavior summary:
|
|
129
|
+
- **No team code in config (employee mode)** → skip upload, report stays LOCAL only; tell the employee explicitly it was saved locally because no team code is set
|
|
129
130
|
- ERP disabled in config → skip upload with an info line, note local commit
|
|
130
131
|
- API key missing → warn with self-service fix instructions, skip upload
|
|
131
132
|
- 401/422 → permanent failure, no retry, tell employee to ask Fawzi
|
|
132
133
|
- Transient (timeout/5xx) → 3 attempts with 1s/3s/9s backoff
|
|
133
134
|
- Success → "Uploaded as $CLIENT_REPORT_ID (ERP: {uuid})"
|
|
134
135
|
|
|
136
|
+
**No-team-code degrade (employee mode):** When the framework was installed in employee mode, `.qualia-config.json` has `code: ""` and `erp.enabled: false`. The report is still generated, written to `.planning/reports/report-{date}.md`, and committed locally (Steps 3 + 5). The ERP upload is skipped and the employee is told the report lives locally and how to enable ERP later (get a team code from Fawzi, or `qualia-framework set-erp-key`). This is a clean degrade, not an error.
|
|
137
|
+
|
|
135
138
|
### Step 7 — State + closing
|
|
136
139
|
|
|
137
140
|
```bash
|
|
@@ -148,6 +151,7 @@ node ${QUALIA_BIN}/qualia-ui.js info "Shift report submitted. You can clock out
|
|
|
148
151
|
|
|
149
152
|
| Symptom | Likely cause | Self-service fix |
|
|
150
153
|
|---|---|---|
|
|
154
|
+
| "Report saved locally, not uploaded" | No team code (employee-mode install) | Expected — report is committed locally. To upload to ERP, get a team code from Fawzi and re-run `npx qualia-framework install`, or set a key with `qualia-framework set-erp-key` |
|
|
151
155
|
| "Could not allocate report ID" | tracking.json missing/corrupt | `cat .planning/tracking.json` to inspect, or restore from `git checkout HEAD -- .planning/tracking.json` |
|
|
152
156
|
| "ERP API key missing" | `${QUALIA_HOME}/.erp-api-key` empty | `printf '%s' "$QUALIA_ERP_KEY" \| qualia-framework set-erp-key` (ask Fawzi for the key) |
|
|
153
157
|
| "ERP auth failed (401)" | Key revoked or wrong | Ask Fawzi for a fresh key |
|
|
@@ -168,6 +172,15 @@ REPORT_FILE=".planning/reports/report-{date}.md"
|
|
|
168
172
|
SUBMITTED_BY=$(git config user.name || echo "unknown")
|
|
169
173
|
SUBMITTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
170
174
|
|
|
175
|
+
# Team code presence — empty in employee-mode installs. No code → the report
|
|
176
|
+
# can't be attributed to a team member, so it degrades to a local-only report.
|
|
177
|
+
TEAM_CODE=$(node -e "try{const c=JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.claude/.qualia-config.json','utf8'));process.stdout.write((c.code||'').trim())}catch{}")
|
|
178
|
+
if [ -z "$TEAM_CODE" ] && [ "$DRY_RUN" != "true" ]; then
|
|
179
|
+
node ${QUALIA_BIN}/qualia-ui.js info "No team code configured (employee mode) — report saved LOCALLY at $REPORT_FILE, not uploaded to the ERP."
|
|
180
|
+
node ${QUALIA_BIN}/qualia-ui.js info "To enable ERP uploads: get a team code from Fawzi and re-run 'npx qualia-framework install', or 'printf '%s' \"\$QUALIA_ERP_KEY\" | qualia-framework set-erp-key'."
|
|
181
|
+
ERP_ENABLED="false"
|
|
182
|
+
fi
|
|
183
|
+
|
|
171
184
|
# Idempotency key — deterministic per (client_report_id, submitted_at). A retry
|
|
172
185
|
# of the same shift report carries the same key, so the ERP can dedupe at the
|
|
173
186
|
# header level in addition to the UPSERT on (project_id, client_report_id).
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Project-Type Stack Presets
|
|
2
|
+
|
|
3
|
+
These presets turn the question *"what kind of project is this?"* into a runnable
|
|
4
|
+
starting point. When `qualia-new` asks the user to pick a project type, the chosen
|
|
5
|
+
preset supplies the env contract, the phase plan, the Definition-of-Done checklist,
|
|
6
|
+
and a minimal-but-real code scaffold.
|
|
7
|
+
|
|
8
|
+
This directory installs to `~/.claude/qualia-templates/stacks/` automatically — it
|
|
9
|
+
ships inside the `templates/` tree, which the installer copies wholesale. No
|
|
10
|
+
installer change is required to add or edit a preset.
|
|
11
|
+
|
|
12
|
+
## The four stacks
|
|
13
|
+
|
|
14
|
+
| `id` | What it is | Database / auth | AI | Voice |
|
|
15
|
+
|-----------------|-------------------------------------------------------------------|--------------------------|----------|----------|
|
|
16
|
+
| `landing-page` | Static / SSG marketing site. No login, no DB. | none | none | none |
|
|
17
|
+
| `full-app` | Authenticated product: accounts, roles, dashboard, RLS-everywhere. | Supabase (auth + RLS) | optional | none |
|
|
18
|
+
| `ai-agent` | LLM / chat / tool-calling agent on top of the full-app base. | Supabase (+ pgvector) | OpenRouter | optional |
|
|
19
|
+
| `internal-tool` | Staff-only portal / admin tool. Same Supabase base as full-app. | Supabase (auth + RLS) | optional | none |
|
|
20
|
+
|
|
21
|
+
All stacks default to the Qualia standard: **Next.js 16 (App Router) + React 19 +
|
|
22
|
+
TypeScript + Tailwind + Vercel**, AI via **OpenRouter**, data via **Supabase**.
|
|
23
|
+
|
|
24
|
+
## Preset contract (every `<id>/` directory has exactly this shape)
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
templates/stacks/<id>/
|
|
28
|
+
stack.json metadata: id, title, description, archetype, defaultStack,
|
|
29
|
+
scaffoldEntry, whenToUse
|
|
30
|
+
env.required.json array of { name, purpose, howToObtain, ownerIssued }
|
|
31
|
+
phases.md the increment / phase plan tuned for this stack
|
|
32
|
+
verify-checklist.md the per-stack Definition-of-Done checklist
|
|
33
|
+
scaffold/ a minimal but REAL runnable starter (MVP, not a full app)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### `stack.json` fields
|
|
37
|
+
|
|
38
|
+
| Field | Meaning |
|
|
39
|
+
|-----------------|-------------------------------------------------------------------------------------|
|
|
40
|
+
| `id` | Stack id; must equal the directory name. |
|
|
41
|
+
| `title` | Human label shown in the `qualia-new` project-type picker. |
|
|
42
|
+
| `description` | One line describing what this stack builds. |
|
|
43
|
+
| `archetype` | The `references/archetypes/*.md` file whose DoD + Road this stack borrows. |
|
|
44
|
+
| `defaultStack` | The default tech string (Next.js / Supabase / OpenRouter / …). |
|
|
45
|
+
| `scaffoldEntry` | The file a developer opens first after the scaffold is laid down. |
|
|
46
|
+
| `whenToUse` | A short "pick this when…" sentence to disambiguate from neighbouring stacks. |
|
|
47
|
+
|
|
48
|
+
### Stack → archetype mapping (DoD source of truth)
|
|
49
|
+
|
|
50
|
+
The stack ids are a delivery-facing rename of the archetype ids. The mapping keeps
|
|
51
|
+
`qualia-scope`'s archetype DoD grill and `qualia-doctor`'s env check consistent:
|
|
52
|
+
|
|
53
|
+
| Stack `id` | `archetype` (DoD source) |
|
|
54
|
+
|-----------------|---------------------------------|
|
|
55
|
+
| `landing-page` | `website` |
|
|
56
|
+
| `full-app` | `web-app` |
|
|
57
|
+
| `ai-agent` | `ai-agent` |
|
|
58
|
+
| `internal-tool` | `web-app` |
|
|
59
|
+
|
|
60
|
+
`internal-tool` and `landing-page` reuse `web-app` / `website` DoD respectively;
|
|
61
|
+
their `phases.md` and `verify-checklist.md` narrow that DoD to the stack's shape
|
|
62
|
+
(no public SEO for an internal tool, no auth for a landing page).
|
|
63
|
+
|
|
64
|
+
### `env.required.json` fields
|
|
65
|
+
|
|
66
|
+
Each entry is an environment variable the stack needs to run:
|
|
67
|
+
|
|
68
|
+
| Field | Meaning |
|
|
69
|
+
|---------------|--------------------------------------------------------------------------------------|
|
|
70
|
+
| `name` | The env var name (e.g. `NEXT_PUBLIC_SUPABASE_URL`). |
|
|
71
|
+
| `purpose` | Why the stack needs it. |
|
|
72
|
+
| `howToObtain` | The exact step (or CLI command) to get the value. |
|
|
73
|
+
| `ownerIssued` | `true` if only the OWNER (Fawzi) can issue the key; `false` if self-serve. |
|
|
74
|
+
|
|
75
|
+
`ownerIssued: true` vars are ones a developer cannot mint themselves (paid third-party
|
|
76
|
+
API keys: OpenRouter, Retell, ElevenLabs, Telnyx). When such a var is missing,
|
|
77
|
+
`qualia-doctor` prints **"ask the OWNER (Fawzi) for this key"** instead of a self-serve
|
|
78
|
+
fix command.
|
|
79
|
+
|
|
80
|
+
## How `qualia-new` consumes a preset
|
|
81
|
+
|
|
82
|
+
After the user picks a project type, `qualia-new`:
|
|
83
|
+
|
|
84
|
+
1. Resolves the chosen `id` to `templates/stacks/<id>/`.
|
|
85
|
+
2. Copies `env.required.json` → the new project's `.planning/env.required.json`
|
|
86
|
+
(creating `.planning/` if absent).
|
|
87
|
+
3. Folds `phases.md` into the generated plan as the milestone-arc starting point.
|
|
88
|
+
4. Lays down `scaffold/` into the project root (a runnable skeleton, then the
|
|
89
|
+
roadmapped phases build on it).
|
|
90
|
+
|
|
91
|
+
## How `qualia-doctor` consumes a preset
|
|
92
|
+
|
|
93
|
+
`qualia-doctor` reads `.planning/env.required.json` (falling back to `./env.required.json`)
|
|
94
|
+
and, for each entry:
|
|
95
|
+
|
|
96
|
+
1. Checks the var is present (in the shell env or in `.env.local`).
|
|
97
|
+
2. Checks the relevant CLI logins: `vercel whoami`, `supabase projects list`
|
|
98
|
+
(or `supabase --version` for auth), `gh auth status`.
|
|
99
|
+
3. Prints **PASS / FAIL** per item with the EXACT fix command.
|
|
100
|
+
4. For `ownerIssued: true` vars whose value is missing, prints
|
|
101
|
+
**"ask the OWNER (Fawzi) for this key"** rather than a self-serve command.
|
|
102
|
+
|
|
103
|
+
## Editing a preset
|
|
104
|
+
|
|
105
|
+
- Keep the scaffold MVP. A runnable skeleton, not a finished app — the roadmapped
|
|
106
|
+
phases earn the rest.
|
|
107
|
+
- Keep `env.required.json` accurate. A var that the scaffold does not actually read
|
|
108
|
+
should not be listed; a var the scaffold needs to boot must be.
|
|
109
|
+
- After editing any JSON, validate it parses:
|
|
110
|
+
`node -e "require('./templates/stacks/<id>/stack.json')"`.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "NEXT_PUBLIC_SUPABASE_URL",
|
|
4
|
+
"purpose": "Supabase project URL — used by both client and server SDKs.",
|
|
5
|
+
"howToObtain": "Supabase Dashboard → Project Settings → API → Project URL, or `npx supabase projects list`.",
|
|
6
|
+
"ownerIssued": false
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"name": "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY",
|
|
10
|
+
"purpose": "Public (anon/publishable) key for client-side Supabase calls. RLS protects data.",
|
|
11
|
+
"howToObtain": "Supabase Dashboard → Project Settings → API → Publishable/anon key.",
|
|
12
|
+
"ownerIssued": false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "SUPABASE_SERVICE_ROLE_KEY",
|
|
16
|
+
"purpose": "Server-only service-role key. NEVER NEXT_PUBLIC_, never in a client component.",
|
|
17
|
+
"howToObtain": "Supabase Dashboard → Project Settings → API → service_role key.",
|
|
18
|
+
"ownerIssued": false
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "OPENROUTER_API_KEY",
|
|
22
|
+
"purpose": "Routes every LLM call through OpenRouter — never hardcode a single provider.",
|
|
23
|
+
"howToObtain": "Issued by Qualia. Ask the OWNER (Fawzi) for a key.",
|
|
24
|
+
"ownerIssued": true
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "RETELL_API_KEY",
|
|
28
|
+
"purpose": "Voice agent platform (only if the agent takes/makes phone calls).",
|
|
29
|
+
"howToObtain": "Issued by Qualia. Ask the OWNER (Fawzi) for a key.",
|
|
30
|
+
"ownerIssued": true
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "ELEVENLABS_API_KEY",
|
|
34
|
+
"purpose": "Voice synthesis / cloning / streaming (voice agents only).",
|
|
35
|
+
"howToObtain": "Issued by Qualia. Ask the OWNER (Fawzi) for a key.",
|
|
36
|
+
"ownerIssued": true
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "TELNYX_API_KEY",
|
|
40
|
+
"purpose": "Telephony / SIP for voice-agent phone numbers (voice agents only).",
|
|
41
|
+
"howToObtain": "Issued by Qualia. Ask the OWNER (Fawzi) for a key.",
|
|
42
|
+
"ownerIssued": true
|
|
43
|
+
}
|
|
44
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# AI Agent — Phase Plan
|
|
2
|
+
|
|
3
|
+
Stack: Next.js 16 (Vercel) · Supabase (Postgres + pgvector) · OpenRouter · Tailwind · Railway (workers, optional).
|
|
4
|
+
Archetype: `ai-agent`. Seed plan copied into ROADMAP.md by `/qualia-new`.
|
|
5
|
+
The differentiator is **Phase 3 — the eval gate**: no ship before evals are green.
|
|
6
|
+
|
|
7
|
+
## Phase 1: Foundation & Data
|
|
8
|
+
|
|
9
|
+
**Goal:** Stack deployed to a Vercel preview; Supabase wired with RLS on every table; OpenRouter wired with a model + fallback.
|
|
10
|
+
|
|
11
|
+
**Success criteria:**
|
|
12
|
+
1. Authenticated user can hit a stubbed endpoint; RLS verified as two users.
|
|
13
|
+
2. Schema: conversations, messages, users (+ pgvector tables if RAG).
|
|
14
|
+
3. OpenRouter wired with a model + fallback chain; secrets in env.
|
|
15
|
+
4. Deploys to a Vercel preview URL.
|
|
16
|
+
|
|
17
|
+
## Phase 2: Core Agent Loop
|
|
18
|
+
|
|
19
|
+
**Goal:** A real end-to-end conversation works (input → model → response → persist), with cost/latency logged from the first call.
|
|
20
|
+
|
|
21
|
+
**Success criteria:**
|
|
22
|
+
1. Streaming chat works end-to-end and persists to Supabase.
|
|
23
|
+
2. System prompt lives in source control — never hardcoded inline.
|
|
24
|
+
3. Tool-calling scaffold present; RAG retrieval if applicable.
|
|
25
|
+
4. Per-request token + latency + cost logged.
|
|
26
|
+
|
|
27
|
+
## Phase 3: Evals & Guardrails (THE GATE)
|
|
28
|
+
|
|
29
|
+
**Goal:** The agent passes a measurable eval suite mapped to the success metric. Guardrails handle refusal, fallback, and tool failure.
|
|
30
|
+
|
|
31
|
+
**Success criteria:**
|
|
32
|
+
1. Eval harness with pass/fail cases mapped to the success metric — green.
|
|
33
|
+
2. Input validation; refusal/safety behavior; fallback on model failure; human-escalation path.
|
|
34
|
+
3. Each tool: server-side validation, timeout + failure handling, idempotency on writes.
|
|
35
|
+
4. Per-request + daily cost ceilings enforced. **No ship before this closes.**
|
|
36
|
+
|
|
37
|
+
## Phase 4: App Surface & Polish
|
|
38
|
+
|
|
39
|
+
**Goal:** Auth flows, rate limiting, and a non-AI-looking design pass.
|
|
40
|
+
|
|
41
|
+
**Success criteria:**
|
|
42
|
+
1. Auth flows + user management + rate limiting.
|
|
43
|
+
2. DESIGN.md anti-slop pass; responsive; all async states incl. streaming.
|
|
44
|
+
3. Product looks built, not generated.
|
|
45
|
+
|
|
46
|
+
## Phase 5: Handoff
|
|
47
|
+
|
|
48
|
+
**Goal:** Security review, prod deploy (Vercel + Railway if a worker), real-call smoke, handover.
|
|
49
|
+
|
|
50
|
+
**Success criteria:**
|
|
51
|
+
1. Secrets/env audit; GDPR posture (consent, retention, export/delete).
|
|
52
|
+
2. Prod deploy; post-deploy smoke includes **real agent calls**, not just HTTP 200.
|
|
53
|
+
3. Credentials, walkthrough, archive, `/qualia-report` to ERP.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Supabase
|
|
2
|
+
NEXT_PUBLIC_SUPABASE_URL=
|
|
3
|
+
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
|
|
4
|
+
SUPABASE_SERVICE_ROLE_KEY=
|
|
5
|
+
|
|
6
|
+
# AI — route ALL LLM calls through OpenRouter. Ask the OWNER (Fawzi) for a key.
|
|
7
|
+
OPENROUTER_API_KEY=
|
|
8
|
+
|
|
9
|
+
# Voice (only for voice agents). Owner-issued — ask Fawzi.
|
|
10
|
+
# RETELL_API_KEY=
|
|
11
|
+
# ELEVENLABS_API_KEY=
|
|
12
|
+
# TELNYX_API_KEY=
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# AI Agent
|
|
2
|
+
|
|
3
|
+
LLM / chat / agent — Next.js 16 + Supabase + OpenRouter (+ optional Retell/ElevenLabs/Telnyx voice).
|
|
4
|
+
|
|
5
|
+
## Run
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
cp .env.example .env.local # fill Supabase keys + OPENROUTER_API_KEY (ask Fawzi)
|
|
10
|
+
npx supabase db push
|
|
11
|
+
npm run dev # http://localhost:3000
|
|
12
|
+
curl -X POST localhost:3000/api/chat -H 'content-type: application/json' \
|
|
13
|
+
-d '{"message":"hello"}'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Where things live
|
|
17
|
+
|
|
18
|
+
- `app/api/chat/route.ts` — the agent endpoint (input validation + routing).
|
|
19
|
+
- `lib/openrouter/client.ts` — the ONLY seam that talks to the LLM. Model + fallback chain here.
|
|
20
|
+
- `lib/prompts/system.ts` — system prompt in source control, never inline.
|
|
21
|
+
- `lib/supabase/server.ts` — server adapter (mutations, RLS).
|
|
22
|
+
- `supabase/migrations/` — conversations + messages, RLS from the first migration.
|
|
23
|
+
- `evals/cases.json` — **the ship gate**. No ship before the suite is green (Phase 3).
|
|
24
|
+
|
|
25
|
+
## Non-negotiables
|
|
26
|
+
|
|
27
|
+
- All LLM calls through OpenRouter — never hardcode a provider.
|
|
28
|
+
- Evals are the finish line, not "it replied".
|
|
29
|
+
- `service_role` + `OPENROUTER_API_KEY` server-only, never logged.
|
|
30
|
+
|
|
31
|
+
This is an MVP skeleton. Build the streaming loop, persistence, and evals per `.planning/ROADMAP.md`.
|