@oneie/claude 0.1.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.
Files changed (59) hide show
  1. package/.claude-plugin/plugin.json +16 -0
  2. package/.mcp.json +12 -0
  3. package/README.md +204 -0
  4. package/agents/w1-recon.md +102 -0
  5. package/agents/w2-decide.md +164 -0
  6. package/agents/w3-edit.md +91 -0
  7. package/agents/w4-verify.md +416 -0
  8. package/commands/browser.md +55 -0
  9. package/commands/cc-connect.md +67 -0
  10. package/commands/claw.md +135 -0
  11. package/commands/close.md +143 -0
  12. package/commands/create.md +78 -0
  13. package/commands/deploy.md +415 -0
  14. package/commands/do-autonomous.md +80 -0
  15. package/commands/do-improve.md +51 -0
  16. package/commands/do-show.md +89 -0
  17. package/commands/do.md +226 -0
  18. package/commands/improve.md +99 -0
  19. package/commands/kill.md +45 -0
  20. package/commands/release.md +144 -0
  21. package/commands/see.md +161 -0
  22. package/commands/setup.md +75 -0
  23. package/commands/sync.md +185 -0
  24. package/hooks/hooks.json +90 -0
  25. package/hooks/lib/signal.sh +28 -0
  26. package/hooks/scripts/design-check.sh +83 -0
  27. package/hooks/scripts/post-edit-check.sh +32 -0
  28. package/hooks/scripts/session-end-verify.sh +51 -0
  29. package/hooks/scripts/session-start.sh +88 -0
  30. package/hooks/scripts/stop-reflect.sh +95 -0
  31. package/hooks/scripts/sync-todo-docs.sh +46 -0
  32. package/hooks/scripts/task-complete-verify.sh +52 -0
  33. package/hooks/scripts/tool-signal.sh +48 -0
  34. package/package.json +33 -0
  35. package/rules/api.md +50 -0
  36. package/rules/astro.md +206 -0
  37. package/rules/design.md +221 -0
  38. package/rules/documentation.md +218 -0
  39. package/rules/engine.md +297 -0
  40. package/rules/react.md +137 -0
  41. package/rules/ui.md +82 -0
  42. package/scripts/cc-connect.sh +345 -0
  43. package/scripts/do-analyze.sh +42 -0
  44. package/scripts/do-folder.sh +63 -0
  45. package/scripts/do-prove.sh +51 -0
  46. package/scripts/do-reconcile.sh +28 -0
  47. package/scripts/do-smoke.sh +60 -0
  48. package/scripts/do-survey.sh +30 -0
  49. package/scripts/do-tier.sh +43 -0
  50. package/skills/build/SKILL.md +52 -0
  51. package/skills/cloudflare/SKILL.md +503 -0
  52. package/skills/dev/SKILL.md +58 -0
  53. package/skills/do/SKILL.md +24 -0
  54. package/skills/oneie/SKILL.md +51 -0
  55. package/skills/perf/SKILL.md +45 -0
  56. package/skills/signal/SKILL.md +108 -0
  57. package/skills/sui/SKILL.md +441 -0
  58. package/skills/tutorial/SKILL.md +96 -0
  59. package/skills/typecheck/SKILL.md +66 -0
@@ -0,0 +1,143 @@
1
+ # /close
2
+
3
+ **Skills:** `/signal` (4-outcome grammar: result / timeout / dissolved / failure) · `/typedb` (mark-dims, rubric scoring, write completion)
4
+
5
+ Mark a result — close the signal loop.
6
+
7
+ ## Flags
8
+
9
+ | Flag | Signal | Outcome | Loop |
10
+ |------|--------|---------|------|
11
+ | `<task-id>` | mark() | result — chain strengthens | L2 |
12
+ | `<task-id> --fail` | warn(1) | failure — full warn, chain breaks | L2 |
13
+ | `<task-id> --dissolved` | warn(0.5) | dissolved — mild warn | L2 |
14
+ | `<task-id> --timeout` | neutral | timeout — slow, not bad | L2 |
15
+ | *(no arg)* | mark() + tick | session report — record all outcomes | L2, L6 |
16
+ | `--todo <slug> --wave N` | emit `do:close` | wave close (soft gate) — append learnings.md; next wave proceeds if skipped | L1, L6 |
17
+ | `--todo <slug> --cycle N` | emit `do:close` | cycle close (**hard gate**) — verify learnings grew; block next cycle if missing | L1, L2, L6 |
18
+ | `--todo <slug> --cycle N --wave N` | emit `do:close` | specific wave of a cycle — used for re-running a failed close | L1 |
19
+
20
+ ## Routing
21
+
22
+ `/close` maps to `mark()` or `warn()` — the human emitting the Four Outcomes
23
+ signal back into the substrate. Rule 1 (Closed Loop): every signal must close.
24
+ Without `/close`, paths cannot learn.
25
+
26
+ ## Four Outcomes Reference (smoke)
27
+
28
+ The four flags map 1:1 to the Four Outcomes from routing.md:
29
+
30
+ ```
31
+ result → /close <id> mark() strength++ chain strengthens
32
+ timeout → /close <id> --timeout neutral no change chain continues
33
+ dissolved → /close <id> --dissolved warn(0.5) resist+=0.5 mild — path missing
34
+ failure → /close <id> --fail warn(1) resist+=1 full — agent failed
35
+ ```
36
+
37
+ Every possible outcome has a corresponding `/close` flag. No outcome goes unmarked.
38
+ This is Rule 1 enforced at the human boundary.
39
+
40
+ ## Steps
41
+
42
+ ### `<task-id>` — success
43
+
44
+ 1. Run W4 gate — score code rubric (each dimension 0–1, composite ≥ 0.65 to close):
45
+ - **security**: no injections, no secrets, all API routes validated
46
+ - **stability**: tests pass, zero type errors, every handler closes its loop
47
+ - **simplicity**: files focused, functions ≤ 20 lines, no ceremony beyond scope
48
+ - **speed**: Lighthouse held, bundle ≤ W0, tokens lean, cache hit ≥ 80%
49
+ - composite: `0.35·security + 0.30·stability + 0.25·simplicity + 0.10·speed`
50
+ 2. POST `http://localhost:4321/api/tasks/{id}/complete`
51
+ 3. POST `http://localhost:4321/api/loop/mark-dims` with `{ security, stability, simplicity, speed }`:
52
+ - Dim ≥ 0.5 → mark() on that dimension path (strength++)
53
+ - Dim < 0.5 → warn() on that dimension path (resistance++)
54
+ 4. Self-checkoff: update task checkbox in the TODO file `[ ]` → `[x]`
55
+ 5. **Emit feedback signal** — POST `http://localhost:4321/api/signal`:
56
+ ```json
57
+ {
58
+ "receiver": "loop:feedback",
59
+ "data": {
60
+ "tags": ["<task-tags>"],
61
+ "strength": "<composite 0–1>",
62
+ "content": {
63
+ "task_id": "<id>",
64
+ "rubric": { "security": X, "stability": Y, "simplicity": Z, "speed": W },
65
+ "composite": N,
66
+ "velocity": "±N",
67
+ "outcome": "result"
68
+ }
69
+ }
70
+ }
71
+ ```
72
+ This is the return-path pheromone. Future agents with matching tags follow this trail.
73
+ `composite >= 0.65` → mark each tag path. `composite < 0.65` → warn(0.5) each tag path.
74
+ 6. Report unlocked tasks (tasks where this was in their `blocks` list)
75
+ 7. **Propagate to docs** — auto-edit when triggers from the cycle's `.w2-doc-plan.json` match. Zero agent spawns; all bash + Edit tool.
76
+
77
+ | Trigger from W3 diff | Target | Edit |
78
+ |---|---|---|
79
+ | new MCP / CLI / SDK / API export | root `README.md` § public surface | append row |
80
+ | new component family or directory | nearest `one.ie/web/src/components/*/CLAUDE.md` | append section |
81
+ | 6-dim, L1-L8, or locked-rule change | root `CLAUDE.md` | edit relevant section |
82
+ | feature doc named in plan `source_of_truth` | feature doc | sync verb/component/endpoint counts |
83
+ | rename across W3 | every `.md` containing old name (W4 stale-name list) | already done by W3 grep |
84
+
85
+ For each trigger, the bash dispatcher reads the W3 diff, locates the anchor in the target doc, and applies the Edit tool inline. Anchor mismatch → log to `docs/improvements.md` for manual W2 next cycle (no halt).
86
+
87
+ 8. Report:
88
+ ```
89
+ mark(+5) on <from>→<to>
90
+ Rubric: security=X stability=Y simplicity=Z speed=W composite=N velocity=±N
91
+ Feedback: signal emitted → loop:feedback tags=[<tags>] strength=N
92
+ Propagate: docs=N edited triggers=[<codes>] manual=N
93
+ Unlocked: N tasks
94
+ ```
95
+
96
+ ### `--fail`
97
+
98
+ 1. POST `http://localhost:4321/api/tasks/{id}/complete` with `{ failed: true }`
99
+ 2. warn(1) — resistance += 1 on the path. Full failure, chain breaks.
100
+ 3. Report:
101
+ ```
102
+ warn(1) on <from>→<to>
103
+ Full failure — resistance++. Chain breaks.
104
+ ```
105
+
106
+ ### `--dissolved`
107
+
108
+ 1. POST `http://localhost:4321/api/tasks/{id}/complete` with `{ dissolved: true }`
109
+ 2. warn(0.5) — resistance += 0.5. Mild warn — path doesn't exist yet.
110
+ 3. Report:
111
+ ```
112
+ warn(0.5) on <from>→<to>
113
+ Dissolved — missing unit/capability. Mild warn. Chain breaks.
114
+ ```
115
+
116
+ ### `--timeout`
117
+
118
+ 1. POST `http://localhost:4321/api/tasks/{id}/complete` with `{ timeout: true }`
119
+ 2. No mark, no warn — neutral. Slow, not bad.
120
+ 3. Report:
121
+ ```
122
+ neutral on <from>→<to>
123
+ Timeout — slow, not bad. Chain continues.
124
+ ```
125
+
126
+ ### *(no arg)* — session report
127
+
128
+ 1. Read git diff: `git diff --stat HEAD` — what changed this session
129
+ 2. For each completed task this session: POST `/api/tasks/{id}/complete`
130
+ 3. POST `http://localhost:4321/api/tick` — process accumulated pheromone
131
+ 4. Report session outcomes (numbers first):
132
+ ```
133
+ Session: N tasks completed M tests K commits
134
+ Pheromone: N marks M warns this session
135
+ Rubric: security=X stability=Y simplicity=Z speed=W composite=N velocity=±N (session averages)
136
+ Hardened: N highways promoted to permanent (L6)
137
+ Frontiers: N new unexplored clusters (L7)
138
+ Next: 1. <task> priority=N 2. <task> priority=M 3. <task> priority=K
139
+ ```
140
+
141
+ ---
142
+
143
+ *`/close` is `mark()` made human-readable. Every outcome must close its loop.*
@@ -0,0 +1,78 @@
1
+ # /create
2
+
3
+ **Skills:** `/typedb` (write new entity) · `/signal` (emit creation, `ui:*` or `cli:create:*`)
4
+
5
+ Emit a new entity into the substrate.
6
+
7
+ ## Nouns
8
+
9
+ | Noun | What | Loop |
10
+ |------|------|------|
11
+ | `task <name> [--tags T] [--weight W]` | Atomic task into TypeDB via API | L1 |
12
+ | `todo <source-doc?>` | TODO from template (Haiku extract + wave structure) | L1 |
13
+ | `agent <markdown-file>` | Parse agent.md frontmatter → TypeDB unit + skills | L1 |
14
+ | `signal <receiver> <data>` | Ad-hoc signal emission for testing | L1 |
15
+
16
+ ## Routing
17
+
18
+ `/create` maps to `send()` — emit new entity or signal into the substrate.
19
+ Every noun writes to TypeDB and/or the in-memory queue.
20
+
21
+ | Noun | Primitive | Destination |
22
+ |------|-----------|-------------|
23
+ | task | `send()` | POST `/api/tasks` |
24
+ | todo | `send()` | Write `docs/{name}-todo.md` + POST `/api/tasks/sync` |
25
+ | agent | `send()` | `agent-md.ts` → TypeDB unit + skills + capabilities |
26
+ | signal | `send()` | POST `/api/signal` |
27
+
28
+ ## Steps
29
+
30
+ ### task
31
+
32
+ 1. Parse `$ARGUMENTS` into task fields:
33
+ - id (kebab-case from name), name
34
+ - value: critical / high / medium
35
+ - phase: C1-C7
36
+ - persona: ceo / dev / investor / gamer / kid / freelancer / agent
37
+ - tags (space-separated), blocks (other task IDs), exit condition
38
+ 2. Compute priority: value + phase + persona + blocking weight (max 115, min 35)
39
+ 3. POST to `http://localhost:4321/api/tasks` with JSON body
40
+ 4. Confirm created task: id, name, priority score + formula, tags
41
+ 5. Suggest `/see tasks` to view ranked list
42
+
43
+ ### todo
44
+
45
+ 1. Resolve source doc from `$ARGUMENTS`: try full path → `docs/$ARGUMENTS` → `docs/$ARGUMENTS.md`
46
+ 2. Run Haiku one-shot to extract raw tasks (~$0.004):
47
+ - Read doc, extract actionable items as checkbox tasks with metadata
48
+ 3. Load base context: `one/dictionary.md`, `one/rubrics.md`, `one/template-todo.md`
49
+ 4. Promote raw tasks into full wave template:
50
+ - Group by cycles (Wire → Prove → Grow) and waves (W1=Haiku, W2=Opus, W3=Sonnet, W4=Sonnet)
51
+ - Assign full metadata per task: id, value, effort, phase, persona, blocks, exit, tags
52
+ - Include: routing diagram, schema reference, wave structure, rubric scoring in W4, self-checkoff
53
+ 5. Write `docs/{docname}-todo.md`
54
+ 6. Verify: all tasks have 7 metadata fields, blocks references are valid, exit conditions are verifiable
55
+ 7. Report: cycle count, tasks per cycle, critical path, cost estimate
56
+
57
+ ### agent
58
+
59
+ 1. Read `<markdown-file>` (frontmatter: name, model, channels, group, skills, sensitivity)
60
+ 2. Parse via `src/engine/agent-md.ts` → `AgentSpec`
61
+ 3. Sync to TypeDB:
62
+ - Unit: uid, name, model, system-prompt, tags
63
+ - Skills: skill-id, name, price, tags per skill
64
+ - Capabilities: (provider: unit, offered: skill) relation
65
+ - Group membership: (group: $g, member: unit) relation
66
+ 4. Report: uid, model, skills count, group, TypeDB insert count
67
+
68
+ ### signal
69
+
70
+ 1. Parse `<receiver>` and `<data>` from `$ARGUMENTS`
71
+ - receiver: string (e.g. `bob:schema`, `analyst`)
72
+ - data: JSON or plain string
73
+ 2. POST to `http://localhost:4321/api/signal` with `{ receiver, data }`
74
+ 3. Report: signal sent, response outcome (result / timeout / dissolved / failure), any path marks triggered
75
+
76
+ ---
77
+
78
+ *Every `/create` is a `send()` call — a new signal enters the world.*
@@ -0,0 +1,415 @@
1
+ # /deploy
2
+
3
+ **Skills:** `/cloudflare` (Workers auth) · `/signal` (deploy:success / deploy:degraded)
4
+
5
+ Ship all four services to Cloudflare. Deterministic sandwich — W0 baseline, build, smoke, approval, parallel deploy, health.
6
+
7
+ > **Production cutover (2026-05-23):** Astro site runs on **CF Workers with Static Assets** (not Pages). Production target is **`https://one.ie`** via the `one-prod` worker. Deploy command is `wrangler deploy --env production`.
8
+ >
9
+ > **Environment model:**
10
+ > - **Production (live):** `https://one.ie` — `one-prod` worker, deployed from `one.ie/web/` via `wrangler deploy --env production`
11
+ > - **Dev (live):** `https://dev.one.ie` — `one-substrate` worker, deployed on every `main` push
12
+ > - **Gateway (live, stable):** `https://api.one.ie` — `one-gateway` worker
13
+ > - **Legacy idle (rollback only — do not deploy):**
14
+ > - `https://oneie.pages.dev` — old Pages project for `one.ie` ("Ecommerce Playbook" content). Re-attach `one.ie` to this project to roll back.
15
+ > - `app.one.ie`, `demo.one.ie`, `onestudio.dev` — still bound to the prior `one-demo` worker. `one-demo` stays in the account untouched for rollback; redeploying `one-demo` would push stale code, so don't.
16
+ > - `https://one-substrate.pages.dev` — paused Pages project, rollback only.
17
+ >
18
+ > See `docs/cf-workers-migration-todo.md` for migration history. The custom-domain detach step (Pages → Worker) is done manually via the CF API (no in-repo script today).
19
+
20
+ ## Modes
21
+
22
+ | Invocation | What |
23
+ |-----------|------|
24
+ | `/deploy` | Full pipeline — W0 + build + 4 services + health |
25
+ | `/deploy --skip-tests` | Skip W0 baseline (risky — use only when already verified) |
26
+ | `/deploy --dry-run` | Build + smoke only, no deploy |
27
+ | `/deploy --preview-only` | Build + preview Worker deploy (no CI-gated services) |
28
+ | `/deploy astro` | Astro Worker only (re-bundle after UI changes) |
29
+ | `/deploy workers` | Gateway + Sync + Agents only (no Astro rebuild) |
30
+ | `/deploy gateway` | Gateway worker only |
31
+ | `/deploy sync` | Sync worker only |
32
+ | `/deploy agents` | Agents edge agents only |
33
+
34
+ ## The 8-Step Pipeline
35
+
36
+ ```bash
37
+ bun run deploy # full pipeline
38
+ bun run deploy -- --dry-run
39
+ bun run deploy -- --skip-tests
40
+ DEPLOY_CONFIRM=yes bun run deploy # CI / non-interactive
41
+ ```
42
+
43
+ **Step 1 — W0 Baseline**
44
+ ```bash
45
+ bun run verify # biome + tsc --noEmit + vitest run + audit:design
46
+ ```
47
+ Record tests passed/total. Fix before proceeding — never deploy on red.
48
+
49
+ **Step 2 — Changes**
50
+ `git diff` summary. Flag large changesets.
51
+
52
+ **Step 3 — Build**
53
+ ```bash
54
+ NODE_ENV=production astro build
55
+ ```
56
+ Target: ~23s. Emits `dist/_worker.js/index.js` + static assets via `@astrojs/cloudflare@13`. Watch for bundle size warnings.
57
+
58
+ **Step 4 — Credentials**
59
+ `CLOUDFLARE_API_TOKEN` must be unset. Deploy uses `CLOUDFLARE_GLOBAL_API_KEY` only.
60
+ Scoped tokens lack permissions for workers + custom domains.
61
+
62
+ **Step 5 — Smoke**
63
+ Verify `dist/server/` exists, all 4 wrangler configs present: `api/wrangler.toml`, `sync/wrangler.toml`, `agents/wrangler.toml`, root `wrangler.toml`.
64
+
65
+ **Step 6 — Approval**
66
+ `main` branch: prompts "yes". Other branches: auto-approved.
67
+ CI: `DEPLOY_CONFIRM=yes bun run deploy` (already set in `.github/workflows/deploy.yml`).
68
+
69
+ **Step 6.5 — D1 Migrations**
70
+ Run before any worker deploy so schema is current when new code lands:
71
+ ```bash
72
+ cd one.ie/web && bunx wrangler d1 migrations apply DB --remote --env production
73
+ ```
74
+ "✅ No migrations to apply!" is a pass. Any applied migration is logged and counted.
75
+ Migration failures block deploy — never ship worker code ahead of its schema.
76
+
77
+ **Step 7 — Deploy (parallel workers + astro)**
78
+ Gateway + Sync + Agents deploy in parallel (~16s). Astro Worker deploys after (~16s).
79
+
80
+ **Step 8 — Health**
81
+ ```bash
82
+ curl https://api.one.ie/health # Gateway
83
+ curl https://one.ie/api/health # Astro Worker (production)
84
+ curl https://one-sync.oneie.workers.dev/ # Sync
85
+ curl https://agents.oneie.workers.dev/health # Agents
86
+ ```
87
+ 3 retries with backoff. All 4 must return 200. Astro `/api/health` must report `units: 140` (or current count) — empty `units: 0` means the build didn't bake `PUBLIC_GATEWAY_URL` correctly.
88
+
89
+ ---
90
+
91
+ ## Bundle Size Rules (CF Workers Free Tier — 3 MiB gzipped upload)
92
+
93
+ The Astro Worker upload must stay under **3 MiB gzipped** on the free tier (10 MiB
94
+ on paid). Wrangler reports both `Total Upload` (uncompressed) and `gzip` — only
95
+ gzip counts toward the ceiling. All chunks in `dist/server/chunks/` are uploaded
96
+ together; dynamic `await import()` does NOT exclude code from the upload.
97
+
98
+ These rules are **LOCKED** — do not revert them. Apply identically to any
99
+ developer template we ship (`oneie init` Workers scaffold mirrors this shape).
100
+
101
+ ### Rule 1 — `syntaxHighlight: false` in `astro.config.mjs`
102
+
103
+ ```js
104
+ markdown: { syntaxHighlight: false }
105
+ ```
106
+
107
+ Disables Shiki from Astro's markdown pipeline. Without this, Shiki pulls ~5.8 MiB of
108
+ language grammar files into the SSR worker on every build. **Do not re-enable.**
109
+
110
+ ### Rule 2 — `ssr.external` for heavy packages
111
+
112
+ ```js
113
+ ssr: {
114
+ external: ["node:async_hooks", "@mysten/sui", "@mysten/bcs", "shiki", "@shikijs/core", "@shikijs/types"]
115
+ }
116
+ ```
117
+
118
+ The CF adapter bundles everything by default. `ssr.external` creates a bare
119
+ `import { x } from 'pkg'` reference without inlining the package.
120
+
121
+ **Critical nuance:** `ssr.external` only works safely when the externalized package is
122
+ never executed on the server path. For `shiki`: `codeToHtml` is imported by `code-block.tsx`,
123
+ but all components that use `code-block.tsx` are `client:only` — so `codeToHtml` is never
124
+ called in the worker. The import statement exists in the bundle but is dead code.
125
+
126
+ If you add a new heavy dependency used only client-side, add it here.
127
+
128
+ ### Rule 3 — Pure-shell pages use `client:only` + `prerender = true`
129
+
130
+ ```astro
131
+ ---
132
+ export const prerender = true
133
+ import { MyComponent } from "@/components/MyComponent"
134
+ ---
135
+ <Layout title="...">
136
+ <MyComponent client:only="react" />
137
+ </Layout>
138
+ ```
139
+
140
+ `client:only="react"` — Astro renders an empty div on the server; the component never
141
+ runs in the worker. The React component tree (+ all its imports) stays out of the SSR bundle.
142
+
143
+ `export const prerender = true` — the page becomes a static asset generated once
144
+ at build time. The page's SSR handler collapses to a small stub. Zero worker cost
145
+ at runtime.
146
+
147
+ **Use this pattern for:** any page that has no server-side data dependencies
148
+ (no `Astro.locals`, no `Astro.request`, no DB queries in frontmatter).
149
+
150
+ Currently prerendered (verify with `grep -l "export const prerender = true" src/pages/*.astro`):
151
+ `404.astro`, `board.astro`, `build.astro`, `ceo.astro`, `chat.astro`, `chat-agents.astro`,
152
+ `chat-fast.astro`, `chat-routing.astro`, `in.astro`, `speed.astro`.
153
+
154
+ Pages that CANNOT be prerendered (need runtime session/auth):
155
+ `world.astro` (reads `Astro.locals.session`), `market.astro` (fetches capabilities).
156
+
157
+ ### Rule 4 — `inlineStylesheets: 'auto'` in `astro.config.mjs`
158
+
159
+ ```js
160
+ build: { inlineStylesheets: 'auto' }, // ← NEVER 'always'
161
+ ```
162
+
163
+ With `'always'`, Astro inlines the full Tailwind stylesheet into **every route's
164
+ serialized manifest entry**. With ~100 routes the entry chunk balloons by 8+ MiB
165
+ of duplicated CSS as a single string literal — diagnosable in worker-entry at
166
+ the line `const _manifest = deserializeManifest({...})`.
167
+
168
+ `'auto'` ships the bundle as one external `<link rel="stylesheet">` referenced
169
+ once across all routes. Browsers cache it across navigations — a page-speed
170
+ win, not just a worker-size win.
171
+
172
+ **Verified 2026-05-22:** flipping `always` → `auto` dropped worker-entry from
173
+ 9.5 MiB → 672 KiB and total gzip from 3302 KiB → 2079 KiB.
174
+
175
+ ### Rule 5 — `react-dom/server.edge` alias (production only)
176
+
177
+ ```js
178
+ resolve: {
179
+ alias: {
180
+ ...(isDev ? {} : { "react-dom/server": "react-dom/server.edge" })
181
+ }
182
+ }
183
+ ```
184
+
185
+ Already in `astro.config.mjs`. Required for CF Edge runtime compatibility.
186
+ Do not remove for production builds.
187
+
188
+ ---
189
+
190
+ ## Verified Bundle Numbers
191
+
192
+ | Snapshot | Total upload | gzip | Worker-entry | What changed |
193
+ |---|---|---|---|---|
194
+ | 2026-04-18 (post Pages→Workers migration) | — | — | 9.5 MiB | Rules 1-3 + 5 |
195
+ | 2026-05-22 before `inlineStylesheets` fix | 18.5 MiB | 3.3 MiB | 9.5 MiB | Over 3 MiB ceiling — deploy FAILED |
196
+ | 2026-05-22 after Rule 4 (`'always'` → `'auto'`) | 10.1 MiB | **2.1 MiB** | **672 KiB** | Under ceiling — deploy ✓ |
197
+
198
+ The 2026-05-22 regression was caused by `build: { inlineStylesheets: 'always' }`
199
+ inlining the full Tailwind stylesheet into every route's manifest entry. One
200
+ char change (`always` → `auto`) saved 8.8 MiB.
201
+
202
+ ---
203
+
204
+ ## Service Map (post-migration)
205
+
206
+ | Service | URL | Config | Deploy command |
207
+ |---------|-----|--------|---------------|
208
+ | Astro Worker (prod) | `one.ie` → `one-prod` | `one.ie/web/wrangler.toml` | `cd one.ie/web && wrangler deploy --env production` |
209
+ | Astro Worker (dev) | `dev.one.ie` → `one-substrate` | `wrangler.toml` (root) | `wrangler deploy` |
210
+ | Gateway | `api.one.ie` → `one-gateway` | `api/wrangler.toml` | `cd api && wrangler deploy` |
211
+ | Sync | `one-sync.oneie.workers.dev` | `sync/wrangler.toml` | `cd sync && wrangler deploy` |
212
+ | Agents | `agents.oneie.workers.dev` | `agents/wrangler.toml` | `cd agents && wrangler deploy` |
213
+ | Pages (legacy idle, rollback) | `oneie.pages.dev` | — | **do not deploy** — rollback target for `one.ie` |
214
+ | Worker (legacy idle, rollback) | `one-demo` (still serves `app.one.ie`, `demo.one.ie`, `onestudio.dev`) | — | **do not deploy** — rollback window for the prod cutover |
215
+
216
+ ---
217
+
218
+ ## Auth (CRITICAL — never change)
219
+
220
+ Always: `CLOUDFLARE_GLOBAL_API_KEY` + `CLOUDFLARE_EMAIL`.
221
+ Never: `CLOUDFLARE_API_TOKEN` (scoped token lacks workers + custom domain permissions).
222
+
223
+ The deploy script auto-unsets `CLOUDFLARE_API_TOKEN` from the spawned env to prevent
224
+ accidental use of a scoped token that was exported in the shell.
225
+
226
+ CI secrets required in `.github/workflows/deploy.yml` env block:
227
+ - `CLOUDFLARE_API_KEY` (mapped from `secrets.CLOUDFLARE_GLOBAL_API_KEY`)
228
+ - `CLOUDFLARE_EMAIL`
229
+ - `CLOUDFLARE_ACCOUNT_ID`
230
+ - `CLOUDFLARE_API_TOKEN: ''` (explicit blank)
231
+ - `DEPLOY_CONFIRM: 'yes'`
232
+ - `PUBLIC_GATEWAY_URL: https://api.one.ie` (build-time-inlined by Astro — **required**; without this the Worker bundle falls back to `one-gateway.oneie.workers.dev` and `/api/health` returns `units: 0`)
233
+
234
+ ---
235
+
236
+ ## Steps
237
+
238
+ ### `/deploy` (full pipeline)
239
+
240
+ 1. `bun run verify` — W0 gate. Fail here means don't deploy.
241
+ 2. `git diff` summary — surface scope to user.
242
+ 3. `NODE_ENV=production bun run build` — Astro production build.
243
+ 4. Verify credentials: assert `CLOUDFLARE_GLOBAL_API_KEY` present, unset `CLOUDFLARE_API_TOKEN`.
244
+ 5. Smoke check: assert `dist/_worker.js/` exists, all 4 wrangler configs present.
245
+ 6. Approval gate: prompt on `main`, auto on other branches.
246
+ 7. Parallel deploy: Gateway + Sync + Agents concurrently, then Astro Worker.
247
+ 8. Health checks: all 4 endpoints × 3 retries with backoff.
248
+ 9. Report:
249
+ ```
250
+ Branch: main
251
+ Tests: 320/320 pass
252
+ Build: 23.2s
253
+ Migrations: 2 applied (0 already up-to-date)
254
+ Workers: parallel 16.7s (vs ~42s sequential)
255
+ Astro: 16.1s
256
+ Health: 4/4 (Gateway 308ms, Astro 666ms, Sync 287ms, Agents 287ms)
257
+ Preview: https://<hash>.one-substrate.<account>.workers.dev
258
+ Total: ~65s
259
+ ```
260
+
261
+ ### `/deploy astro`
262
+
263
+ Deploys the production worker (`one-prod`) to `one.ie` from the `one.ie/web/` directory.
264
+
265
+ 1. `cd one.ie/web && NODE_ENV=production bun run build`
266
+ 2. Check bundle size: `du -sh one.ie/web/dist/server/`
267
+ 3. If > 12 MiB: check which chunk grew (`ls -lhS one.ie/web/dist/server/chunks/ | head -15`)
268
+ 4. Run D1 migrations: `cd one.ie/web && bunx wrangler d1 migrations apply DB --remote --env production`
269
+ 5. `cd one.ie/web && bunx wrangler deploy --env production`
270
+ 6. Health: `curl -sL https://one.ie/api/health` (expect 200, `units > 0`)
271
+
272
+ **Pre-flight (one-time, on cutover only):** ensure no other CF entity owns the `one.ie` custom domain. If wrangler errors with a hostname conflict, detach the prior owner first:
273
+
274
+ ```bash
275
+ # If a Pages project owns it (was `oneie` project pre-cutover):
276
+ curl -s -X DELETE \
277
+ "https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/pages/projects/oneie/domains/one.ie" \
278
+ -H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
279
+ -H "X-Auth-Key: $CLOUDFLARE_GLOBAL_API_KEY"
280
+ ```
281
+
282
+ ### `/deploy workers`
283
+
284
+ ```bash
285
+ cd api && bun wrangler deploy && cd ../workers/sync && bun wrangler deploy && cd ../../agents && bun wrangler deploy && cd ..
286
+ ```
287
+
288
+ Report: version hash per worker, health latency per service.
289
+
290
+ ### Cutover tool (`scripts/cf-cutover.ts`)
291
+
292
+ For Pages→Workers custom-domain flips on other services (script is parameterized):
293
+
294
+ ```bash
295
+ bun run cf-cutover # dry-run, safe
296
+ bun run cf-cutover --execute # real cutover: Workers route + Pages detach + health verify + substrate signal
297
+ ```
298
+
299
+ Defaults: domain=`dev.one.ie`, worker=`one-substrate`, pages=`one-substrate`. Override via `CF_CUTOVER_DOMAIN`, `CF_CUTOVER_WORKER`, `CF_CUTOVER_PAGES_PROJECT` env vars.
300
+
301
+ ---
302
+
303
+ ## Bundle Size Diagnosis
304
+
305
+ If build fails with "exceeds size limit":
306
+
307
+ ```bash
308
+ # Check total worker size
309
+ du -sh dist/server/
310
+
311
+ # Find top offenders
312
+ ls -lhS dist/server/chunks/ | head -20
313
+
314
+ # Check if a new import pulled in Shiki
315
+ grep -r "from 'shiki'" dist/server/chunks/ | wc -l
316
+ # If > 0: a component that imports shiki was SSR'd
317
+ # Fix: make its page client:only="react" + prerender=true
318
+
319
+ # Check if React crept back into worker via client:load
320
+ grep -l "react-vendor" dist/server/chunks/
321
+ # If multiple chunks: some page SSR-renders React via client:load
322
+ # Fix: audit src/pages/*.astro for client:load on pure-shell pages
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Rollback
328
+
329
+ ```bash
330
+ # Workers — rollback to previous version
331
+ bun wrangler rollback --name one-prod # production
332
+ bun wrangler rollback --name one-substrate # dev
333
+
334
+ # Legacy Pages fallback (still live at one-substrate.pages.dev for rollback window):
335
+ bun wrangler pages deployment list --project-name=one-substrate
336
+ bun wrangler pages deployments rollback --project-name=one-substrate
337
+
338
+ # Revert a Worker via git
339
+ cd api && git stash && bun wrangler deploy
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Known-Flaky Test Allowlist
345
+
346
+ Located in `scripts/deploy.ts`:
347
+
348
+ ```typescript
349
+ const KNOWN_FLAKY = [
350
+ 'Act 15: Speed Benchmarks', // hardware-dependent
351
+ 'STAN distribution', // stochastic
352
+ 'explorer mode', // stochastic
353
+ ]
354
+ ```
355
+
356
+ These failures don't block deploy. Real failures (type errors, broken logic)
357
+ always block. Use `--strict` to require full green.
358
+
359
+ ---
360
+
361
+ ## First-Time Setup
362
+
363
+ Only needed once — see `docs/deploy.md` for full walkthrough:
364
+
365
+ ```bash
366
+ # Create CF resources
367
+ bun wrangler d1 create one
368
+ bun wrangler kv namespace create KV
369
+ # → Paste IDs into wrangler.toml + sync/wrangler.toml
370
+
371
+ # Run D1 migration
372
+ bun wrangler d1 execute one --remote --file=migrations/0001_init.sql
373
+
374
+ # Gateway secrets (TypeDB credentials)
375
+ cd api
376
+ printf 'admin' | bun wrangler secret put TYPEDB_USERNAME
377
+ printf 'YOUR-PASSWORD' | bun wrangler secret put TYPEDB_PASSWORD
378
+ cd ..
379
+
380
+ # First deploy — Worker auto-provisions on first `wrangler deploy`
381
+ bun run deploy
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Logs
387
+
388
+ - `.deploy.log` — all deployment output, each worker appends here
389
+ - `.deploy-build.log` — W0 baseline diagnostics (biome + tsc + vitest separate)
390
+
391
+ Live logs:
392
+
393
+ ```bash
394
+ bun wrangler tail --name one-prod # Astro Worker (production)
395
+ bun wrangler tail --name one-substrate # Astro Worker (dev)
396
+ cd api && bun wrangler tail && cd .. # Gateway
397
+ bun wrangler deployments list --name one-prod | head -10
398
+ ```
399
+
400
+ ---
401
+
402
+ ## Gotchas
403
+
404
+ - TypeDB Cloud port is **1729** (not 80 or 443)
405
+ - TypeDB HTTP API prefix is `/v1/` (signin, query, databases)
406
+ - Always `CLOUDFLARE_GLOBAL_API_KEY` — scoped tokens lack permissions for workers + custom domains
407
+ - `import.meta.env` is build-time — `PUBLIC_GATEWAY_URL` is baked into the worker bundle at build. Missing → `/api/health` returns `units: 0`
408
+ - Custom domains: `[[routes]]` double bracket, no wildcards, add `workers_dev = true`
409
+ - Worker upload limit: **3 MiB gzipped** on free tier (10 MiB on paid). Wrangler reports `gzip:` — only that number counts. Follow the 5 Bundle Size Rules above
410
+ - **D1 schema-drift fails at runtime, not compile-time.** Migrations that DROP+CREATE a table (e.g. `0059_domains.sql` renamed `slug`→`gid`, `verified`→`verified_at`) silently break any code that queries the old columns — typecheck passes, deploy succeeds, the route 500s in production. After any DROP+CREATE migration, grep the codebase for the old column names and fix call sites BEFORE deploying
411
+ - **Error responses get the same `cache-control` as success responses.** Astro's Layout sets `public, max-age=300, s-maxage=86400, stale-while-revalidate=604800` on every render including 5xx pages. A bad deploy will be cached at the CF edge for 24h. When diagnosing, always bust the cache: `curl "https://host/path?_t=$(date +%s)"`. Consider a middleware rule that strips `cache-control` on `>= 500` status
412
+
413
+ ---
414
+
415
+ *Deploy is the closed loop. W0 baseline in, health check out. If health fails, mark() is blocked. Determinism: every step reports numbers, every number gets marked.*