@lifeaitools/rdc-skills 0.24.42 → 0.25.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 (198) hide show
  1. package/.claude/settings.json +15 -15
  2. package/.claude-plugin/marketplace.json +21 -21
  3. package/.claude-plugin/plugin.json +1518 -1371
  4. package/.github/workflows/publish.yml +34 -34
  5. package/.github/workflows/self-test.yml +58 -58
  6. package/CHANGELOG.md +310 -310
  7. package/LICENSE +21 -21
  8. package/MANIFEST.md +221 -221
  9. package/README.md +375 -376
  10. package/README.sandbox.md +3 -3
  11. package/assets/watcher/viewer.html +164 -164
  12. package/bin/rdc-skills-mcp.mjs +316 -316
  13. package/commands/build.md +183 -183
  14. package/commands/collab.md +180 -180
  15. package/commands/deploy.md +152 -152
  16. package/commands/design.md +31 -31
  17. package/commands/edit.md +28 -28
  18. package/commands/fixit.md +150 -124
  19. package/commands/handoff.md +173 -173
  20. package/commands/help.md +95 -95
  21. package/commands/overnight.md +220 -220
  22. package/commands/plan.md +158 -158
  23. package/commands/preplan.md +131 -131
  24. package/commands/prototype.md +145 -145
  25. package/commands/release.md +49 -49
  26. package/commands/report.md +99 -99
  27. package/commands/review.md +120 -120
  28. package/commands/self-test.md +113 -113
  29. package/commands/status.md +86 -86
  30. package/commands/watch.md +98 -98
  31. package/commands/workitems.md +137 -137
  32. package/git-sha.json +1 -1
  33. package/guides/agent-bootstrap.md +295 -295
  34. package/guides/agents/backend.md +104 -104
  35. package/guides/agents/content.md +94 -94
  36. package/guides/agents/cs2.md +56 -56
  37. package/guides/agents/data.md +87 -87
  38. package/guides/agents/design.md +77 -77
  39. package/guides/agents/frontend.md +92 -92
  40. package/guides/agents/infrastructure.md +81 -81
  41. package/guides/agents/setup.md +281 -281
  42. package/guides/agents/verify.md +151 -151
  43. package/guides/agents/viz.md +106 -106
  44. package/guides/backend.md +146 -146
  45. package/guides/content.md +147 -147
  46. package/guides/cs2.md +190 -190
  47. package/guides/data.md +123 -123
  48. package/guides/design.md +116 -116
  49. package/guides/engineering-behavior.md +43 -43
  50. package/guides/escalation-protocol.md +125 -125
  51. package/guides/frontend.md +151 -151
  52. package/guides/history-md-spec.md +297 -297
  53. package/guides/infrastructure.md +179 -179
  54. package/guides/lessons-learned-spec.md +145 -151
  55. package/guides/output-contract.md +108 -108
  56. package/guides/publish-md-spec.md +289 -289
  57. package/guides/rdc-skills-startup.md +30 -30
  58. package/guides/verify.md +11 -11
  59. package/hooks/check-cwd.js +31 -31
  60. package/hooks/check-rdc-environment.js +164 -164
  61. package/hooks/check-services.js +6 -6
  62. package/hooks/check-stale-work-items.js +19 -19
  63. package/hooks/foreground-process-gate.js +128 -128
  64. package/hooks/gate-watchdog-selfcheck.js +257 -257
  65. package/hooks/hook-logger.js +25 -25
  66. package/hooks/lib/run-evidence-gate.mjs +241 -241
  67. package/hooks/no-stop-open-epics.js +127 -127
  68. package/hooks/post-tool-batch-gate.js +203 -203
  69. package/hooks/post-work-check.js +21 -21
  70. package/hooks/postcompact-log.js +13 -13
  71. package/hooks/precompact-log.js +13 -13
  72. package/hooks/rate-limit-retry.js +46 -46
  73. package/hooks/rdc-invocation-marker.js +157 -157
  74. package/hooks/rdc-output-contract-gate.js +94 -94
  75. package/hooks/require-work-item-on-commit.js +294 -294
  76. package/hooks/restart-brief.js +19 -19
  77. package/hooks/run-hidden-hook.ps1 +47 -47
  78. package/hooks/task-completed-gate.js +274 -274
  79. package/hooks/work-item-exit-gate.js +944 -944
  80. package/lib/catalog.mjs +236 -236
  81. package/lib/cloud-rewrite.mjs +155 -155
  82. package/package.json +57 -57
  83. package/rules/work-items-rpc.md +520 -520
  84. package/scaffold/templates/HISTORY.md.template +39 -39
  85. package/scaffold/templates/PUBLISH.md.template +21 -21
  86. package/scaffold/templates/brochure-studio-default.html +70 -70
  87. package/scripts/acceptance.mjs +502 -502
  88. package/scripts/fixtures/guides/bad-guide.md +15 -15
  89. package/scripts/fixtures/guides-clean/good-guide.md +16 -16
  90. package/scripts/install-rdc-skills.js +1289 -1289
  91. package/scripts/install.ps1 +202 -202
  92. package/scripts/install.sh +132 -132
  93. package/scripts/lib/assertions.mjs +287 -287
  94. package/scripts/lib/manifest-schema.mjs +754 -754
  95. package/scripts/lib/runner.mjs +465 -465
  96. package/scripts/lib/sandbox.mjs +435 -435
  97. package/scripts/prepack.mjs +32 -32
  98. package/scripts/rdc-brochure.mjs +482 -482
  99. package/scripts/rdc-design-cli.mjs +134 -134
  100. package/scripts/rebuild-mcp.mjs +107 -107
  101. package/scripts/self-test.mjs +1460 -1460
  102. package/scripts/stamp-git-sha.mjs +29 -29
  103. package/scripts/test-guide-validator.mjs +196 -196
  104. package/scripts/test-rdc-hooks.mjs +145 -145
  105. package/scripts/uninstall.ps1 +77 -77
  106. package/scripts/uninstall.sh +69 -69
  107. package/scripts/update.ps1 +43 -43
  108. package/scripts/update.sh +43 -43
  109. package/scripts/validate-place-histories.js +461 -461
  110. package/scripts/validate-publish-manifests.js +502 -424
  111. package/scripts/watch-init.mjs +100 -100
  112. package/skills/brochure/SKILL.md +107 -107
  113. package/skills/build/SKILL.md +563 -563
  114. package/skills/channel-formatter/SKILL.md +538 -533
  115. package/skills/co-develop/SKILL.md +196 -196
  116. package/skills/collab/SKILL.md +239 -239
  117. package/skills/convert/SKILL.md +167 -140
  118. package/skills/deploy/SKILL.md +541 -541
  119. package/skills/design/SKILL.md +211 -211
  120. package/skills/design/reference/ownership.md +16 -16
  121. package/skills/design/reference/rampa.md +92 -92
  122. package/skills/design/reference/studio-model.md +153 -153
  123. package/skills/edit/SKILL.md +98 -98
  124. package/skills/fixit/SKILL.md +203 -165
  125. package/skills/fs-mcp/SKILL.md +148 -148
  126. package/skills/handoff/SKILL.md +236 -236
  127. package/skills/help/SKILL.md +143 -143
  128. package/skills/housekeeping/SKILL.md +160 -219
  129. package/skills/lifeai-brochure-author/SKILL.md +340 -340
  130. package/skills/onramp/SKILL.md +248 -0
  131. package/skills/overnight/SKILL.md +251 -251
  132. package/skills/plan/SKILL.md +345 -345
  133. package/skills/preplan/SKILL.md +90 -90
  134. package/skills/prototype/SKILL.md +150 -150
  135. package/skills/rdc-brochurify/SKILL.md +245 -245
  136. package/skills/rdc-extract-verifier-rules/SKILL.md +191 -191
  137. package/skills/release/SKILL.md +140 -140
  138. package/skills/report/SKILL.md +100 -100
  139. package/skills/review/SKILL.md +152 -152
  140. package/skills/rpms-filemap/SKILL.cloud.md +111 -111
  141. package/skills/rpms-filemap/SKILL.md +111 -111
  142. package/skills/self-test/SKILL.md +132 -132
  143. package/skills/status/SKILL.md +99 -99
  144. package/skills/terminal-config/SKILL.md +62 -62
  145. package/skills/tests/MATRIX.md +54 -54
  146. package/skills/tests/README.md +47 -47
  147. package/skills/tests/onramp.test.json +87 -0
  148. package/skills/tests/rdc-brochure.test.json +34 -34
  149. package/skills/tests/rdc-build.test.json +36 -36
  150. package/skills/tests/rdc-channel-formatter.test.json +45 -45
  151. package/skills/tests/rdc-co-develop.test.json +29 -29
  152. package/skills/tests/rdc-collab.test.json +29 -29
  153. package/skills/tests/rdc-convert.test.json +35 -35
  154. package/skills/tests/rdc-deploy.test.json +30 -30
  155. package/skills/tests/rdc-design.test.json +27 -27
  156. package/skills/tests/rdc-edit.test.json +29 -29
  157. package/skills/tests/rdc-fixit.test.json +36 -36
  158. package/skills/tests/rdc-fs-mcp.test.json +36 -36
  159. package/skills/tests/rdc-handoff.test.json +28 -28
  160. package/skills/tests/rdc-help.test.json +29 -29
  161. package/skills/tests/rdc-housekeeping.test.json +28 -32
  162. package/skills/tests/rdc-lifeai-brochure-author.test.json +35 -35
  163. package/skills/tests/rdc-overnight.test.json +37 -37
  164. package/skills/tests/rdc-plan.test.json +27 -27
  165. package/skills/tests/rdc-preplan.test.json +31 -31
  166. package/skills/tests/rdc-prototype.test.json +28 -28
  167. package/skills/tests/rdc-rdc-brochurify.test.json +23 -23
  168. package/skills/tests/rdc-rdc-extract-verifier-rules.test.json +34 -34
  169. package/skills/tests/rdc-release.test.json +29 -29
  170. package/skills/tests/rdc-report.test.json +28 -28
  171. package/skills/tests/rdc-review.test.json +29 -29
  172. package/skills/tests/rdc-rpms-filemap.test.json +28 -28
  173. package/skills/tests/rdc-self-test.test.json +24 -24
  174. package/skills/tests/rdc-status.test.json +29 -29
  175. package/skills/tests/rdc-terminal-config.test.json +29 -29
  176. package/skills/tests/rdc-watch.test.json +24 -24
  177. package/skills/tests/rdc-workitems.test.json +27 -27
  178. package/skills/watch/SKILL.md +97 -97
  179. package/skills/workitems/SKILL.md +151 -151
  180. package/tests/acceptance.test.mjs +59 -59
  181. package/tests/channel-formatter.contract.test.mjs +251 -251
  182. package/tests/curl-surface.test.mjs +289 -289
  183. package/tests/harness-gates.test.mjs +325 -325
  184. package/tests/help-surface.test.mjs +61 -61
  185. package/tests/install-rdc-skills.test.mjs +49 -49
  186. package/tests/manifest-contract-fields.test.mjs +78 -78
  187. package/tests/mcp.test.mjs +271 -271
  188. package/tests/rdc-brochure.test.mjs +125 -125
  189. package/tests/require-work-item-on-commit.test.mjs +162 -162
  190. package/tests/run-evidence-gate.test.mjs +82 -82
  191. package/tests/skill-test-matrix.test.mjs +66 -66
  192. package/tests/validate-skills.js +27 -27
  193. package/tests/work-item-exit-gate-l2.test.mjs +368 -368
  194. package/tests/work-item-exit-gate-l3.test.mjs +197 -197
  195. package/RELEASE.md +0 -42
  196. package/tests/housekeeping-lessons-triage.test.mjs +0 -49
  197. package/tests/lessons-pipeline-contract.test.mjs +0 -27
  198. package/tests/release-contract.test.mjs +0 -16
@@ -1,520 +1,520 @@
1
- # Work Items RPC Reference
2
-
3
- > Complete reference for work_items table operations via Supabase RPC functions.
4
- > Use these functions for ALL CRUD operations. Never write raw INSERT/UPDATE/SELECT against work_items.
5
-
6
- ---
7
-
8
- ## Core Rule
9
-
10
- **Always use RPC functions.** They handle defaults, check constraints, timestamps, sorting, and return structured JSONB.
11
-
12
- Exception: Ad-hoc analytics queries (e.g., `SELECT count(*)`) are acceptable as raw SQL.
13
-
14
- ---
15
-
16
- ## Valid Enum Values
17
-
18
- | Column | Allowed Values |
19
- |--------|---|
20
- | `status` | `todo` · `in_progress` · `blocked` · `review` · `done` · `archived` |
21
- | `priority` | `urgent` · `high` · `normal` · `low` |
22
- | `item_type` | `epic` · `task` · `subtask` · `bug` · `spike` |
23
-
24
- ---
25
-
26
- ## RPC Functions
27
-
28
- ### 1. get_open_epics — List open epics
29
-
30
- Returns all non-done/archived epics sorted by priority, then created_at.
31
-
32
- **Supabase SQL:**
33
- ```sql
34
- SELECT get_open_epics();
35
- SELECT get_open_epics('urgent');
36
- SELECT get_open_epics(p_label_filter := 'feature-x');
37
- SELECT get_open_epics('high', 'backend');
38
- ```
39
-
40
- **Supabase JS Client:**
41
- ```ts
42
- const { data } = await supabase.rpc('get_open_epics');
43
- const { data } = await supabase.rpc('get_open_epics', {
44
- p_priority_filter: 'urgent'
45
- });
46
- const { data } = await supabase.rpc('get_open_epics', {
47
- p_label_filter: 'cs2'
48
- });
49
- ```
50
-
51
- **Parameters:**
52
-
53
- | Name | Type | Required | Notes |
54
- |------|------|----------|-------|
55
- | `p_priority_filter` | text | no | NULL = all priorities. One of: `urgent`, `high`, `normal`, `low` |
56
- | `p_label_filter` | text | no | NULL = all labels. Uses array containment (`@>`) for matching |
57
-
58
- **Returns:**
59
- - JSONB array of epic objects (sorted by priority then created_at)
60
- - Empty `[]` if none found
61
- - Each epic has: `id`, `title`, `status`, `priority`, `item_type`, `labels`, `created_at`, `updated_at`
62
-
63
- ---
64
-
65
- ### 2. insert_work_item — Create a work item
66
-
67
- Create a new task, epic, subtask, bug, or spike.
68
-
69
- **Supabase SQL:**
70
- ```sql
71
- SELECT insert_work_item(
72
- p_title := 'Build user authentication',
73
- p_description := 'Implement OAuth2 flow...',
74
- p_status := 'todo',
75
- p_priority := 'high',
76
- p_item_type := 'task',
77
- p_parent_id := 'epic-uuid'::uuid,
78
- p_labels := ARRAY['backend', 'auth'],
79
- p_source := 'agent'
80
- );
81
- ```
82
-
83
- **Supabase JS Client:**
84
- ```ts
85
- const { data } = await supabase.rpc('insert_work_item', {
86
- p_title: 'Build user authentication',
87
- p_description: 'Implement OAuth2 flow...',
88
- p_status: 'todo',
89
- p_priority: 'high',
90
- p_item_type: 'task',
91
- p_parent_id: epicId,
92
- p_labels: ['backend', 'auth'],
93
- p_source: 'agent'
94
- });
95
- ```
96
-
97
- **All Parameters:**
98
-
99
- | Name | Type | Default | Notes |
100
- |------|------|---------|-------|
101
- | `p_title` | text | *required* | Work item name (max 255 chars) |
102
- | `p_description` | text | NULL | Long-form description |
103
- | `p_status` | text | `'todo'` | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
104
- | `p_priority` | text | `'normal'` | One of: `urgent`, `high`, `normal`, `low` |
105
- | `p_item_type` | text | `'task'` | One of: `epic`, `task`, `subtask`, `bug`, `spike` |
106
- | `p_parent_id` | uuid | NULL | Parent epic UUID for hierarchy (for subtasks) |
107
- | `p_company_id` | uuid | NULL | Foreign key to companies table |
108
- | `p_customer_id` | uuid | NULL | Foreign key to customers table |
109
- | `p_campaign_id` | uuid | NULL | Foreign key to campaigns table |
110
- | `p_contact_id` | uuid | NULL | Foreign key to contacts table |
111
- | `p_project_id` | uuid | NULL | Project identifier (project-specific) |
112
- | `p_assignee` | text | NULL | Assigned person name or email |
113
- | `p_assigned_to` | text | NULL | Same as assignee (alternate field) |
114
- | `p_due_date` | date | NULL | Due date for the task |
115
- | `p_tags` | text[] | `'{}'` | Array of tags |
116
- | `p_labels` | text[] | `'{}'` | Array of labels (used for filtering) |
117
- | `p_linked_table` | text | NULL | Name of external table to link (if any) |
118
- | `p_linked_id` | uuid | NULL | ID in linked_table |
119
- | `p_created_by` | text | NULL | Who created this item |
120
- | `p_estimated_hours` | numeric | NULL | Time estimate in hours |
121
- | `p_notes` | jsonb | `'[]'` | Array of note objects `[{ text, author, timestamp }]` |
122
- | `p_session_id` | text | NULL | Session UUID (for audit trail) |
123
- | `p_package` | text | NULL | Package/module name (e.g., '@regen/ui') |
124
- | `p_source` | text | `'manual'` | How was this created: `manual`, `agent`, `api`, `import` |
125
- | `p_checklist` | jsonb | `NULL` | Checklist items. If NULL and parent has `definition_of_done`, auto-inherited with all `checked: false` |
126
- | `p_definition_of_done` | jsonb | `NULL` | DoD template (epics only). Child tasks inherit this as their checklist at insert time |
127
-
128
- **Returns:**
129
- - Full inserted work_item row as JSONB
130
- - Includes auto-generated `id`, `created_at`, `updated_at`
131
-
132
- ---
133
-
134
- ### 3. update_work_item_status — Change status
135
-
136
- Transition a work item's status. Auto-manages `completed_at`.
137
-
138
- **Hard gate:** implementation agents do not set non-epic work directly to `done`.
139
- They submit a report and move the item to `review`. A validator closes it as
140
- `done` only after fresh verification.
141
-
142
- **Supabase SQL:**
143
- ```sql
144
- SELECT update_work_item_status(
145
- 'work-item-uuid'::uuid,
146
- 'in_progress'
147
- );
148
-
149
- SELECT update_work_item_status(
150
- 'work-item-uuid'::uuid,
151
- 'review',
152
- '["Implementation complete; ready for validator"]'::jsonb,
153
- 'agent-session-id',
154
- 'agent'
155
- );
156
-
157
- SELECT update_work_item_status(
158
- 'work-item-uuid'::uuid,
159
- 'done',
160
- '["Validator verified implementation report, CodeFlow post, and checklist evidence"]'::jsonb,
161
- 'validator-session-id',
162
- 'validator'
163
- );
164
- ```
165
-
166
- **Supabase JS Client:**
167
- ```ts
168
- const { data } = await supabase.rpc('update_work_item_status', {
169
- p_id: itemId,
170
- p_status: 'in_progress'
171
- });
172
-
173
- const { data } = await supabase.rpc('update_work_item_status', {
174
- p_id: itemId,
175
- p_status: 'review',
176
- p_notes_append: ['Implementation complete; ready for validator'],
177
- p_actor_session_id: agentSessionId,
178
- p_actor_role: 'agent'
179
- });
180
-
181
- const { data } = await supabase.rpc('update_work_item_status', {
182
- p_id: itemId,
183
- p_status: 'done',
184
- p_notes_append: ['Validator verified implementation report, CodeFlow post, and checklist evidence'],
185
- p_actor_session_id: validatorSessionId,
186
- p_actor_role: 'validator'
187
- });
188
- ```
189
-
190
- **Parameters:**
191
-
192
- | Name | Type | Required | Notes |
193
- |------|------|----------|-------|
194
- | `p_id` | uuid | yes | work_item ID |
195
- | `p_status` | text | yes | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
196
- | `p_notes_append` | jsonb | no | Array of strings appended to existing notes |
197
- | `p_actor_session_id` | text | review/done | Current agent or validator session ID |
198
- | `p_actor_role` | text | review/done | `agent` for `review`, `validator` for `done` |
199
-
200
- **Behavior:**
201
- - Setting `done` auto-sets `completed_at = now()`
202
- - Setting non-epic work to `review` raises EXCEPTION unless `implementation_report.codeflow_post` exists and caller role is `agent`
203
- - Setting non-epic work to `done` raises EXCEPTION unless current status is `review`, caller role is `validator`, `implementation_report.codeflow_post` exists, every required checklist item is checked, and required checklist evidence was ticked by the originating agent session
204
- - Setting `todo`, `in_progress`, `blocked`, or `review` clears `completed_at`
205
- - `updated_at` always refreshed to current timestamp
206
- - Raises exception if ID not found
207
-
208
- **Returns:**
209
- - Full updated work_item row as JSONB
210
-
211
- ---
212
-
213
- ### 4. update_checklist_item — Tick off a checklist item
214
-
215
- **Supabase SQL:**
216
- ```sql
217
- SELECT update_checklist_item(
218
- 'work-item-uuid'::uuid,
219
- 'tsc-clean', -- string id of the checklist item
220
- true, -- checked state
221
- 'agent-session-id',
222
- 'agent',
223
- 'rpc'
224
- );
225
- ```
226
-
227
- **Parameters:**
228
-
229
- | Name | Type | Required | Notes |
230
- |------|------|----------|-------|
231
- | `p_work_item_id` | uuid | yes | the work item ID |
232
- | `p_item_id` | text | yes | the `id` field of the checklist item |
233
- | `p_checked` | boolean | yes | `true` = checked, `false` = unchecked |
234
- | `p_actor_session_id` | text | yes for checked=true | originating implementation agent session ID |
235
- | `p_actor_role` | text | yes for checked=true | must be `agent` for completion evidence ticks |
236
- | `p_event_source` | text | no | source label, default `rpc` |
237
-
238
- Call this as each checklist item is completed — not all at once at the end.
239
- The tick is written to `work_item_checklist_events`; supervisor or validator
240
- re-ticks are rejected by the exit gate.
241
-
242
- **Returns:** updated checklist JSONB array.
243
-
244
- ---
245
-
246
- ### 5. submit_implementation_report — File agent completion narrative
247
-
248
- MUST be called BEFORE `update_work_item_status(..., 'review', ...)`.
249
-
250
- **Supabase SQL:**
251
- ```sql
252
- SELECT submit_implementation_report(
253
- 'work-item-uuid'::uuid,
254
- '{
255
- "tldr": "One-sentence summary",
256
- "assumptions": [],
257
- "deviations": [],
258
- "uncertainty": [],
259
- "detail": "Full narrative",
260
- "flags": [],
261
- "codeflow_post": {
262
- "agent_session_id": "agent-session-id",
263
- "summary": "What changed and why",
264
- "files_changed": ["path/to/file"],
265
- "verification": ["command or evidence"],
266
- "commit": "optional commit hash"
267
- }
268
- }'::jsonb
269
- );
270
- ```
271
-
272
- **Parameters:**
273
-
274
- | Name | Type | Required | Notes |
275
- |------|------|----------|-------|
276
- | `p_work_item_id` | uuid | yes | the work item ID |
277
- | `p_report` | jsonb | yes | implementation report (shape below) |
278
-
279
- **Returns:** `{ "flags_count": N, "deviations_count": N, "has_deviations": bool }` — signal only.
280
-
281
- **`implementation_report` shape:**
282
- ```json
283
- {
284
- "tldr": "string",
285
- "assumptions": ["string", "..."],
286
- "deviations": ["string — deviation from plan", "..."],
287
- "uncertainty": ["string — anything unclear", "..."],
288
- "detail": "string — full narrative",
289
- "flags": ["string — supervisor attention needed", "..."],
290
- "codeflow_post": {
291
- "agent_session_id": "string — originating implementation session",
292
- "summary": "string — agent-authored CodeFlow post",
293
- "files_changed": ["string", "..."],
294
- "verification": ["string", "..."],
295
- "commit": "string — optional"
296
- }
297
- }
298
- ```
299
-
300
- If `has_deviations` is true or `flags_count > 0`, supervisor pulls full report from DB.
301
-
302
- ---
303
-
304
- ### 6. get_work_items_by_epic — Fetch epic + children
305
-
306
- Get an epic and all its child tasks/subtasks, sorted by priority.
307
-
308
- **Supabase SQL:**
309
- ```sql
310
- SELECT get_work_items_by_epic('epic-uuid'::uuid);
311
- SELECT get_work_items_by_epic('epic-uuid'::uuid, 'todo');
312
- ```
313
-
314
- **Supabase JS Client:**
315
- ```ts
316
- const { data } = await supabase.rpc('get_work_items_by_epic', {
317
- p_epic_id: epicId
318
- });
319
-
320
- const { data } = await supabase.rpc('get_work_items_by_epic', {
321
- p_epic_id: epicId,
322
- p_status_filter: 'todo'
323
- });
324
- ```
325
-
326
- **Parameters:**
327
-
328
- | Name | Type | Required | Notes |
329
- |------|------|----------|-------|
330
- | `p_epic_id` | uuid | yes | The epic's work_item ID |
331
- | `p_status_filter` | text | no | NULL = all statuses. One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
332
-
333
- **Returns:**
334
- - JSONB array with parent epic first, then children
335
- - Sorted by: priority (urgent > high > normal > low), then created_at
336
- - Each item has same structure as returned from insert_work_item
337
-
338
- ---
339
-
340
- ### 7. bump_epic_version — Version with history
341
-
342
- Snapshot an epic's current state and assign a version number.
343
-
344
- **Supabase SQL:**
345
- ```sql
346
- SELECT bump_epic_version(
347
- 'epic-uuid'::uuid,
348
- '0.2.0',
349
- 'Added async task execution',
350
- 'agent'
351
- );
352
- ```
353
-
354
- **Supabase JS Client:**
355
- ```ts
356
- const { data } = await supabase.rpc('bump_epic_version', {
357
- p_epic_id: epicId,
358
- p_version: '0.2.0',
359
- p_change_summary: 'Added async task execution',
360
- p_changed_by: 'agent'
361
- });
362
- ```
363
-
364
- **Parameters:**
365
-
366
- | Name | Type | Required | Notes |
367
- |------|------|----------|-------|
368
- | `p_epic_id` | uuid | yes | Must be item_type = `'epic'` |
369
- | `p_version` | text | yes | Semantic version string (e.g., `'0.1.0'`, `'1.0.0'`) |
370
- | `p_change_summary` | text | no | What changed in this version |
371
- | `p_changed_by` | text | no | Who bumped the version |
372
-
373
- **Behavior:**
374
- - Snapshots the epic's current state into work_item_versions table
375
- - Updates the epic's `version` column
376
- - Raises exception if item is not an epic (item_type != 'epic')
377
-
378
- **Returns:**
379
- - JSONB object: `{ epic_id, version, version_record_id, change_summary, changed_by, bumped_at }`
380
-
381
- ---
382
-
383
- ## Common Patterns
384
-
385
- ### Create an Epic + Child Tasks
386
-
387
- ```ts
388
- // 1. Create epic
389
- const { data: epic } = await supabase.rpc('insert_work_item', {
390
- p_title: 'Implement feature X',
391
- p_item_type: 'epic',
392
- p_status: 'todo',
393
- p_priority: 'high',
394
- p_source: 'agent'
395
- });
396
- const epicId = epic[0].id;
397
-
398
- // 2. Create child tasks
399
- for (const task of tasks) {
400
- await supabase.rpc('insert_work_item', {
401
- p_title: task.title,
402
- p_item_type: 'task',
403
- p_priority: task.priority,
404
- p_parent_id: epicId,
405
- p_source: 'agent'
406
- });
407
- }
408
- ```
409
-
410
- ### Fetch Epic Tree, Filter by Status, Update Each
411
-
412
- ```ts
413
- const { data: tree } = await supabase.rpc('get_work_items_by_epic', {
414
- p_epic_id: epicId,
415
- p_status_filter: 'todo'
416
- });
417
-
418
- for (const item of tree) {
419
- if (item.item_type === 'epic') continue; // skip parent
420
-
421
- await supabase.rpc('update_work_item_status', {
422
- p_id: item.id,
423
- p_status: 'in_progress'
424
- });
425
- }
426
- ```
427
-
428
- ### Mark Epic Done with Notes
429
-
430
- ```ts
431
- const { data } = await supabase.rpc('update_work_item_status', {
432
- p_id: epicId,
433
- p_status: 'done',
434
- p_notes_append: [
435
- 'All child tasks completed',
436
- 'Code reviewed and merged to main',
437
- 'Deployed to production'
438
- ]
439
- });
440
- ```
441
-
442
- ### List All Open Work, Filter by Priority
443
-
444
- ```ts
445
- const { data: epics } = await supabase.rpc('get_open_epics', {
446
- p_priority_filter: 'urgent'
447
- });
448
-
449
- for (const epic of epics) {
450
- const { data: items } = await supabase.rpc('get_work_items_by_epic', {
451
- p_epic_id: epic.id
452
- });
453
- // process items...
454
- }
455
- ```
456
-
457
- ---
458
-
459
- ## Supabase Project Reference
460
-
461
- In production, you'll need:
462
-
463
- **Environment variables (in .env.local):**
464
- ```bash
465
- NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
466
- NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
467
- SUPABASE_SERVICE_ROLE_KEY=<service-role-key> # Server-side only
468
- ```
469
-
470
- Replace `<project-ref>` with your actual Supabase project reference (e.g., `uvojezuorjgqzmhhgluu`).
471
-
472
- **Project-specific data (from docs/guides/agent-bootstrap.md):**
473
- - SUPABASE_PROJECT_ID (if required by your project)
474
- - Any custom schema names (if work_items lives in non-public schema)
475
- - Related table names (companies, customers, contacts, campaigns, etc.)
476
-
477
- ---
478
-
479
- ## Error Handling
480
-
481
- ### RPC Not Found
482
- If `get_open_epics` returns a 404, the function doesn't exist on your Supabase instance.
483
- Run migration to add the function, or contact your DBA.
484
-
485
- ### Invalid UUID
486
- ```ts
487
- // Wrong — string passed directly
488
- p_id: "item-id"
489
-
490
- // Correct — cast to uuid
491
- p_id: itemId
492
- ```
493
-
494
- ### Status Not in Enum
495
- Check `p_status` against allowed values. Will raise a constraint error if invalid.
496
-
497
- ### Item Not Found
498
- `update_work_item_status` and `bump_epic_version` will raise an exception if ID doesn't exist.
499
- Always catch or check first:
500
- ```ts
501
- const { data: items } = await supabase.rpc('get_work_items_by_epic', { p_epic_id: id });
502
- if (!items || items.length === 0) {
503
- // Epic not found
504
- }
505
- ```
506
-
507
- ---
508
-
509
- ## Analytics (Raw SQL)
510
-
511
- Direct SELECT is acceptable for read-only analytics:
512
-
513
- ```sql
514
- SELECT status, count(*) as cnt FROM work_items GROUP BY status;
515
- SELECT priority, count(*) FROM work_items WHERE labels @> ARRAY['urgent'] GROUP BY priority;
516
- SELECT avg(EXTRACT(EPOCH FROM (completed_at - created_at))/3600)::numeric(10,2) as avg_hours
517
- FROM work_items WHERE status = 'done' AND item_type = 'task';
518
- ```
519
-
520
- For INSERT/UPDATE/DELETE: always use the RPC functions above.
1
+ # Work Items RPC Reference
2
+
3
+ > Complete reference for work_items table operations via Supabase RPC functions.
4
+ > Use these functions for ALL CRUD operations. Never write raw INSERT/UPDATE/SELECT against work_items.
5
+
6
+ ---
7
+
8
+ ## Core Rule
9
+
10
+ **Always use RPC functions.** They handle defaults, check constraints, timestamps, sorting, and return structured JSONB.
11
+
12
+ Exception: Ad-hoc analytics queries (e.g., `SELECT count(*)`) are acceptable as raw SQL.
13
+
14
+ ---
15
+
16
+ ## Valid Enum Values
17
+
18
+ | Column | Allowed Values |
19
+ |--------|---|
20
+ | `status` | `todo` · `in_progress` · `blocked` · `review` · `done` · `archived` |
21
+ | `priority` | `urgent` · `high` · `normal` · `low` |
22
+ | `item_type` | `epic` · `task` · `subtask` · `bug` · `spike` |
23
+
24
+ ---
25
+
26
+ ## RPC Functions
27
+
28
+ ### 1. get_open_epics — List open epics
29
+
30
+ Returns all non-done/archived epics sorted by priority, then created_at.
31
+
32
+ **Supabase SQL:**
33
+ ```sql
34
+ SELECT get_open_epics();
35
+ SELECT get_open_epics('urgent');
36
+ SELECT get_open_epics(p_label_filter := 'feature-x');
37
+ SELECT get_open_epics('high', 'backend');
38
+ ```
39
+
40
+ **Supabase JS Client:**
41
+ ```ts
42
+ const { data } = await supabase.rpc('get_open_epics');
43
+ const { data } = await supabase.rpc('get_open_epics', {
44
+ p_priority_filter: 'urgent'
45
+ });
46
+ const { data } = await supabase.rpc('get_open_epics', {
47
+ p_label_filter: 'cs2'
48
+ });
49
+ ```
50
+
51
+ **Parameters:**
52
+
53
+ | Name | Type | Required | Notes |
54
+ |------|------|----------|-------|
55
+ | `p_priority_filter` | text | no | NULL = all priorities. One of: `urgent`, `high`, `normal`, `low` |
56
+ | `p_label_filter` | text | no | NULL = all labels. Uses array containment (`@>`) for matching |
57
+
58
+ **Returns:**
59
+ - JSONB array of epic objects (sorted by priority then created_at)
60
+ - Empty `[]` if none found
61
+ - Each epic has: `id`, `title`, `status`, `priority`, `item_type`, `labels`, `created_at`, `updated_at`
62
+
63
+ ---
64
+
65
+ ### 2. insert_work_item — Create a work item
66
+
67
+ Create a new task, epic, subtask, bug, or spike.
68
+
69
+ **Supabase SQL:**
70
+ ```sql
71
+ SELECT insert_work_item(
72
+ p_title := 'Build user authentication',
73
+ p_description := 'Implement OAuth2 flow...',
74
+ p_status := 'todo',
75
+ p_priority := 'high',
76
+ p_item_type := 'task',
77
+ p_parent_id := 'epic-uuid'::uuid,
78
+ p_labels := ARRAY['backend', 'auth'],
79
+ p_source := 'agent'
80
+ );
81
+ ```
82
+
83
+ **Supabase JS Client:**
84
+ ```ts
85
+ const { data } = await supabase.rpc('insert_work_item', {
86
+ p_title: 'Build user authentication',
87
+ p_description: 'Implement OAuth2 flow...',
88
+ p_status: 'todo',
89
+ p_priority: 'high',
90
+ p_item_type: 'task',
91
+ p_parent_id: epicId,
92
+ p_labels: ['backend', 'auth'],
93
+ p_source: 'agent'
94
+ });
95
+ ```
96
+
97
+ **All Parameters:**
98
+
99
+ | Name | Type | Default | Notes |
100
+ |------|------|---------|-------|
101
+ | `p_title` | text | *required* | Work item name (max 255 chars) |
102
+ | `p_description` | text | NULL | Long-form description |
103
+ | `p_status` | text | `'todo'` | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
104
+ | `p_priority` | text | `'normal'` | One of: `urgent`, `high`, `normal`, `low` |
105
+ | `p_item_type` | text | `'task'` | One of: `epic`, `task`, `subtask`, `bug`, `spike` |
106
+ | `p_parent_id` | uuid | NULL | Parent epic UUID for hierarchy (for subtasks) |
107
+ | `p_company_id` | uuid | NULL | Foreign key to companies table |
108
+ | `p_customer_id` | uuid | NULL | Foreign key to customers table |
109
+ | `p_campaign_id` | uuid | NULL | Foreign key to campaigns table |
110
+ | `p_contact_id` | uuid | NULL | Foreign key to contacts table |
111
+ | `p_project_id` | uuid | NULL | Project identifier (project-specific) |
112
+ | `p_assignee` | text | NULL | Assigned person name or email |
113
+ | `p_assigned_to` | text | NULL | Same as assignee (alternate field) |
114
+ | `p_due_date` | date | NULL | Due date for the task |
115
+ | `p_tags` | text[] | `'{}'` | Array of tags |
116
+ | `p_labels` | text[] | `'{}'` | Array of labels (used for filtering) |
117
+ | `p_linked_table` | text | NULL | Name of external table to link (if any) |
118
+ | `p_linked_id` | uuid | NULL | ID in linked_table |
119
+ | `p_created_by` | text | NULL | Who created this item |
120
+ | `p_estimated_hours` | numeric | NULL | Time estimate in hours |
121
+ | `p_notes` | jsonb | `'[]'` | Array of note objects `[{ text, author, timestamp }]` |
122
+ | `p_session_id` | text | NULL | Session UUID (for audit trail) |
123
+ | `p_package` | text | NULL | Package/module name (e.g., '@regen/ui') |
124
+ | `p_source` | text | `'manual'` | How was this created: `manual`, `agent`, `api`, `import` |
125
+ | `p_checklist` | jsonb | `NULL` | Checklist items. If NULL and parent has `definition_of_done`, auto-inherited with all `checked: false` |
126
+ | `p_definition_of_done` | jsonb | `NULL` | DoD template (epics only). Child tasks inherit this as their checklist at insert time |
127
+
128
+ **Returns:**
129
+ - Full inserted work_item row as JSONB
130
+ - Includes auto-generated `id`, `created_at`, `updated_at`
131
+
132
+ ---
133
+
134
+ ### 3. update_work_item_status — Change status
135
+
136
+ Transition a work item's status. Auto-manages `completed_at`.
137
+
138
+ **Hard gate:** implementation agents do not set non-epic work directly to `done`.
139
+ They submit a report and move the item to `review`. A validator closes it as
140
+ `done` only after fresh verification.
141
+
142
+ **Supabase SQL:**
143
+ ```sql
144
+ SELECT update_work_item_status(
145
+ 'work-item-uuid'::uuid,
146
+ 'in_progress'
147
+ );
148
+
149
+ SELECT update_work_item_status(
150
+ 'work-item-uuid'::uuid,
151
+ 'review',
152
+ '["Implementation complete; ready for validator"]'::jsonb,
153
+ 'agent-session-id',
154
+ 'agent'
155
+ );
156
+
157
+ SELECT update_work_item_status(
158
+ 'work-item-uuid'::uuid,
159
+ 'done',
160
+ '["Validator verified implementation report, CodeFlow post, and checklist evidence"]'::jsonb,
161
+ 'validator-session-id',
162
+ 'validator'
163
+ );
164
+ ```
165
+
166
+ **Supabase JS Client:**
167
+ ```ts
168
+ const { data } = await supabase.rpc('update_work_item_status', {
169
+ p_id: itemId,
170
+ p_status: 'in_progress'
171
+ });
172
+
173
+ const { data } = await supabase.rpc('update_work_item_status', {
174
+ p_id: itemId,
175
+ p_status: 'review',
176
+ p_notes_append: ['Implementation complete; ready for validator'],
177
+ p_actor_session_id: agentSessionId,
178
+ p_actor_role: 'agent'
179
+ });
180
+
181
+ const { data } = await supabase.rpc('update_work_item_status', {
182
+ p_id: itemId,
183
+ p_status: 'done',
184
+ p_notes_append: ['Validator verified implementation report, CodeFlow post, and checklist evidence'],
185
+ p_actor_session_id: validatorSessionId,
186
+ p_actor_role: 'validator'
187
+ });
188
+ ```
189
+
190
+ **Parameters:**
191
+
192
+ | Name | Type | Required | Notes |
193
+ |------|------|----------|-------|
194
+ | `p_id` | uuid | yes | work_item ID |
195
+ | `p_status` | text | yes | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
196
+ | `p_notes_append` | jsonb | no | Array of strings appended to existing notes |
197
+ | `p_actor_session_id` | text | review/done | Current agent or validator session ID |
198
+ | `p_actor_role` | text | review/done | `agent` for `review`, `validator` for `done` |
199
+
200
+ **Behavior:**
201
+ - Setting `done` auto-sets `completed_at = now()`
202
+ - Setting non-epic work to `review` raises EXCEPTION unless `implementation_report.codeflow_post` exists and caller role is `agent`
203
+ - Setting non-epic work to `done` raises EXCEPTION unless current status is `review`, caller role is `validator`, `implementation_report.codeflow_post` exists, every required checklist item is checked, and required checklist evidence was ticked by the originating agent session
204
+ - Setting `todo`, `in_progress`, `blocked`, or `review` clears `completed_at`
205
+ - `updated_at` always refreshed to current timestamp
206
+ - Raises exception if ID not found
207
+
208
+ **Returns:**
209
+ - Full updated work_item row as JSONB
210
+
211
+ ---
212
+
213
+ ### 4. update_checklist_item — Tick off a checklist item
214
+
215
+ **Supabase SQL:**
216
+ ```sql
217
+ SELECT update_checklist_item(
218
+ 'work-item-uuid'::uuid,
219
+ 'tsc-clean', -- string id of the checklist item
220
+ true, -- checked state
221
+ 'agent-session-id',
222
+ 'agent',
223
+ 'rpc'
224
+ );
225
+ ```
226
+
227
+ **Parameters:**
228
+
229
+ | Name | Type | Required | Notes |
230
+ |------|------|----------|-------|
231
+ | `p_work_item_id` | uuid | yes | the work item ID |
232
+ | `p_item_id` | text | yes | the `id` field of the checklist item |
233
+ | `p_checked` | boolean | yes | `true` = checked, `false` = unchecked |
234
+ | `p_actor_session_id` | text | yes for checked=true | originating implementation agent session ID |
235
+ | `p_actor_role` | text | yes for checked=true | must be `agent` for completion evidence ticks |
236
+ | `p_event_source` | text | no | source label, default `rpc` |
237
+
238
+ Call this as each checklist item is completed — not all at once at the end.
239
+ The tick is written to `work_item_checklist_events`; supervisor or validator
240
+ re-ticks are rejected by the exit gate.
241
+
242
+ **Returns:** updated checklist JSONB array.
243
+
244
+ ---
245
+
246
+ ### 5. submit_implementation_report — File agent completion narrative
247
+
248
+ MUST be called BEFORE `update_work_item_status(..., 'review', ...)`.
249
+
250
+ **Supabase SQL:**
251
+ ```sql
252
+ SELECT submit_implementation_report(
253
+ 'work-item-uuid'::uuid,
254
+ '{
255
+ "tldr": "One-sentence summary",
256
+ "assumptions": [],
257
+ "deviations": [],
258
+ "uncertainty": [],
259
+ "detail": "Full narrative",
260
+ "flags": [],
261
+ "codeflow_post": {
262
+ "agent_session_id": "agent-session-id",
263
+ "summary": "What changed and why",
264
+ "files_changed": ["path/to/file"],
265
+ "verification": ["command or evidence"],
266
+ "commit": "optional commit hash"
267
+ }
268
+ }'::jsonb
269
+ );
270
+ ```
271
+
272
+ **Parameters:**
273
+
274
+ | Name | Type | Required | Notes |
275
+ |------|------|----------|-------|
276
+ | `p_work_item_id` | uuid | yes | the work item ID |
277
+ | `p_report` | jsonb | yes | implementation report (shape below) |
278
+
279
+ **Returns:** `{ "flags_count": N, "deviations_count": N, "has_deviations": bool }` — signal only.
280
+
281
+ **`implementation_report` shape:**
282
+ ```json
283
+ {
284
+ "tldr": "string",
285
+ "assumptions": ["string", "..."],
286
+ "deviations": ["string — deviation from plan", "..."],
287
+ "uncertainty": ["string — anything unclear", "..."],
288
+ "detail": "string — full narrative",
289
+ "flags": ["string — supervisor attention needed", "..."],
290
+ "codeflow_post": {
291
+ "agent_session_id": "string — originating implementation session",
292
+ "summary": "string — agent-authored CodeFlow post",
293
+ "files_changed": ["string", "..."],
294
+ "verification": ["string", "..."],
295
+ "commit": "string — optional"
296
+ }
297
+ }
298
+ ```
299
+
300
+ If `has_deviations` is true or `flags_count > 0`, supervisor pulls full report from DB.
301
+
302
+ ---
303
+
304
+ ### 6. get_work_items_by_epic — Fetch epic + children
305
+
306
+ Get an epic and all its child tasks/subtasks, sorted by priority.
307
+
308
+ **Supabase SQL:**
309
+ ```sql
310
+ SELECT get_work_items_by_epic('epic-uuid'::uuid);
311
+ SELECT get_work_items_by_epic('epic-uuid'::uuid, 'todo');
312
+ ```
313
+
314
+ **Supabase JS Client:**
315
+ ```ts
316
+ const { data } = await supabase.rpc('get_work_items_by_epic', {
317
+ p_epic_id: epicId
318
+ });
319
+
320
+ const { data } = await supabase.rpc('get_work_items_by_epic', {
321
+ p_epic_id: epicId,
322
+ p_status_filter: 'todo'
323
+ });
324
+ ```
325
+
326
+ **Parameters:**
327
+
328
+ | Name | Type | Required | Notes |
329
+ |------|------|----------|-------|
330
+ | `p_epic_id` | uuid | yes | The epic's work_item ID |
331
+ | `p_status_filter` | text | no | NULL = all statuses. One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
332
+
333
+ **Returns:**
334
+ - JSONB array with parent epic first, then children
335
+ - Sorted by: priority (urgent > high > normal > low), then created_at
336
+ - Each item has same structure as returned from insert_work_item
337
+
338
+ ---
339
+
340
+ ### 7. bump_epic_version — Version with history
341
+
342
+ Snapshot an epic's current state and assign a version number.
343
+
344
+ **Supabase SQL:**
345
+ ```sql
346
+ SELECT bump_epic_version(
347
+ 'epic-uuid'::uuid,
348
+ '0.2.0',
349
+ 'Added async task execution',
350
+ 'agent'
351
+ );
352
+ ```
353
+
354
+ **Supabase JS Client:**
355
+ ```ts
356
+ const { data } = await supabase.rpc('bump_epic_version', {
357
+ p_epic_id: epicId,
358
+ p_version: '0.2.0',
359
+ p_change_summary: 'Added async task execution',
360
+ p_changed_by: 'agent'
361
+ });
362
+ ```
363
+
364
+ **Parameters:**
365
+
366
+ | Name | Type | Required | Notes |
367
+ |------|------|----------|-------|
368
+ | `p_epic_id` | uuid | yes | Must be item_type = `'epic'` |
369
+ | `p_version` | text | yes | Semantic version string (e.g., `'0.1.0'`, `'1.0.0'`) |
370
+ | `p_change_summary` | text | no | What changed in this version |
371
+ | `p_changed_by` | text | no | Who bumped the version |
372
+
373
+ **Behavior:**
374
+ - Snapshots the epic's current state into work_item_versions table
375
+ - Updates the epic's `version` column
376
+ - Raises exception if item is not an epic (item_type != 'epic')
377
+
378
+ **Returns:**
379
+ - JSONB object: `{ epic_id, version, version_record_id, change_summary, changed_by, bumped_at }`
380
+
381
+ ---
382
+
383
+ ## Common Patterns
384
+
385
+ ### Create an Epic + Child Tasks
386
+
387
+ ```ts
388
+ // 1. Create epic
389
+ const { data: epic } = await supabase.rpc('insert_work_item', {
390
+ p_title: 'Implement feature X',
391
+ p_item_type: 'epic',
392
+ p_status: 'todo',
393
+ p_priority: 'high',
394
+ p_source: 'agent'
395
+ });
396
+ const epicId = epic[0].id;
397
+
398
+ // 2. Create child tasks
399
+ for (const task of tasks) {
400
+ await supabase.rpc('insert_work_item', {
401
+ p_title: task.title,
402
+ p_item_type: 'task',
403
+ p_priority: task.priority,
404
+ p_parent_id: epicId,
405
+ p_source: 'agent'
406
+ });
407
+ }
408
+ ```
409
+
410
+ ### Fetch Epic Tree, Filter by Status, Update Each
411
+
412
+ ```ts
413
+ const { data: tree } = await supabase.rpc('get_work_items_by_epic', {
414
+ p_epic_id: epicId,
415
+ p_status_filter: 'todo'
416
+ });
417
+
418
+ for (const item of tree) {
419
+ if (item.item_type === 'epic') continue; // skip parent
420
+
421
+ await supabase.rpc('update_work_item_status', {
422
+ p_id: item.id,
423
+ p_status: 'in_progress'
424
+ });
425
+ }
426
+ ```
427
+
428
+ ### Mark Epic Done with Notes
429
+
430
+ ```ts
431
+ const { data } = await supabase.rpc('update_work_item_status', {
432
+ p_id: epicId,
433
+ p_status: 'done',
434
+ p_notes_append: [
435
+ 'All child tasks completed',
436
+ 'Code reviewed and merged to main',
437
+ 'Deployed to production'
438
+ ]
439
+ });
440
+ ```
441
+
442
+ ### List All Open Work, Filter by Priority
443
+
444
+ ```ts
445
+ const { data: epics } = await supabase.rpc('get_open_epics', {
446
+ p_priority_filter: 'urgent'
447
+ });
448
+
449
+ for (const epic of epics) {
450
+ const { data: items } = await supabase.rpc('get_work_items_by_epic', {
451
+ p_epic_id: epic.id
452
+ });
453
+ // process items...
454
+ }
455
+ ```
456
+
457
+ ---
458
+
459
+ ## Supabase Project Reference
460
+
461
+ In production, you'll need:
462
+
463
+ **Environment variables (in .env.local):**
464
+ ```bash
465
+ NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
466
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
467
+ SUPABASE_SERVICE_ROLE_KEY=<service-role-key> # Server-side only
468
+ ```
469
+
470
+ Replace `<project-ref>` with your actual Supabase project reference (e.g., `uvojezuorjgqzmhhgluu`).
471
+
472
+ **Project-specific data (from docs/guides/agent-bootstrap.md):**
473
+ - SUPABASE_PROJECT_ID (if required by your project)
474
+ - Any custom schema names (if work_items lives in non-public schema)
475
+ - Related table names (companies, customers, contacts, campaigns, etc.)
476
+
477
+ ---
478
+
479
+ ## Error Handling
480
+
481
+ ### RPC Not Found
482
+ If `get_open_epics` returns a 404, the function doesn't exist on your Supabase instance.
483
+ Run migration to add the function, or contact your DBA.
484
+
485
+ ### Invalid UUID
486
+ ```ts
487
+ // Wrong — string passed directly
488
+ p_id: "item-id"
489
+
490
+ // Correct — cast to uuid
491
+ p_id: itemId
492
+ ```
493
+
494
+ ### Status Not in Enum
495
+ Check `p_status` against allowed values. Will raise a constraint error if invalid.
496
+
497
+ ### Item Not Found
498
+ `update_work_item_status` and `bump_epic_version` will raise an exception if ID doesn't exist.
499
+ Always catch or check first:
500
+ ```ts
501
+ const { data: items } = await supabase.rpc('get_work_items_by_epic', { p_epic_id: id });
502
+ if (!items || items.length === 0) {
503
+ // Epic not found
504
+ }
505
+ ```
506
+
507
+ ---
508
+
509
+ ## Analytics (Raw SQL)
510
+
511
+ Direct SELECT is acceptable for read-only analytics:
512
+
513
+ ```sql
514
+ SELECT status, count(*) as cnt FROM work_items GROUP BY status;
515
+ SELECT priority, count(*) FROM work_items WHERE labels @> ARRAY['urgent'] GROUP BY priority;
516
+ SELECT avg(EXTRACT(EPOCH FROM (completed_at - created_at))/3600)::numeric(10,2) as avg_hours
517
+ FROM work_items WHERE status = 'done' AND item_type = 'task';
518
+ ```
519
+
520
+ For INSERT/UPDATE/DELETE: always use the RPC functions above.