optimal-cli 0.1.0 → 1.0.1

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 (47) hide show
  1. package/agents/.gitkeep +0 -0
  2. package/agents/content-ops.md +227 -0
  3. package/agents/financial-ops.md +184 -0
  4. package/agents/infra-ops.md +206 -0
  5. package/agents/profiles.json +5 -0
  6. package/dist/bin/optimal.d.ts +1 -1
  7. package/dist/bin/optimal.js +706 -111
  8. package/dist/lib/assets/index.d.ts +79 -0
  9. package/dist/lib/assets/index.js +153 -0
  10. package/dist/lib/assets.d.ts +20 -0
  11. package/dist/lib/assets.js +112 -0
  12. package/dist/lib/auth/index.d.ts +83 -0
  13. package/dist/lib/auth/index.js +146 -0
  14. package/dist/lib/board/index.d.ts +39 -0
  15. package/dist/lib/board/index.js +285 -0
  16. package/dist/lib/board/types.d.ts +111 -0
  17. package/dist/lib/board/types.js +1 -0
  18. package/dist/lib/bot/claim.d.ts +3 -0
  19. package/dist/lib/bot/claim.js +20 -0
  20. package/dist/lib/bot/coordinator.d.ts +27 -0
  21. package/dist/lib/bot/coordinator.js +178 -0
  22. package/dist/lib/bot/heartbeat.d.ts +6 -0
  23. package/dist/lib/bot/heartbeat.js +30 -0
  24. package/dist/lib/bot/index.d.ts +9 -0
  25. package/dist/lib/bot/index.js +6 -0
  26. package/dist/lib/bot/protocol.d.ts +12 -0
  27. package/dist/lib/bot/protocol.js +74 -0
  28. package/dist/lib/bot/reporter.d.ts +3 -0
  29. package/dist/lib/bot/reporter.js +27 -0
  30. package/dist/lib/bot/skills.d.ts +26 -0
  31. package/dist/lib/bot/skills.js +69 -0
  32. package/dist/lib/config/registry.d.ts +17 -0
  33. package/dist/lib/config/registry.js +182 -0
  34. package/dist/lib/config/schema.d.ts +31 -0
  35. package/dist/lib/config/schema.js +25 -0
  36. package/dist/lib/errors.d.ts +25 -0
  37. package/dist/lib/errors.js +91 -0
  38. package/dist/lib/format.d.ts +28 -0
  39. package/dist/lib/format.js +98 -0
  40. package/dist/lib/returnpro/validate.d.ts +37 -0
  41. package/dist/lib/returnpro/validate.js +124 -0
  42. package/dist/lib/social/meta.d.ts +90 -0
  43. package/dist/lib/social/meta.js +160 -0
  44. package/docs/CLI-REFERENCE.md +361 -0
  45. package/package.json +13 -24
  46. package/dist/lib/kanban.d.ts +0 -46
  47. package/dist/lib/kanban.js +0 -118
File without changes
@@ -0,0 +1,227 @@
1
+ ---
2
+ name: content-ops
3
+ description: Autonomous agent for multi-brand content operations — newsletter generation, CMS management, social post pipelines, and deployment
4
+ ---
5
+
6
+ ## Capabilities
7
+
8
+ The content-ops agent manages the full content lifecycle across all Optimal brands (CRE-11TRUST, LIFEINSUR). It generates newsletters, manages CMS content in Strapi, creates and publishes social media posts, and deploys preview sites.
9
+
10
+ Core responsibilities:
11
+
12
+ - **Newsletter generation**: Fetch news, generate AI content via Groq, build branded HTML, push drafts to Strapi
13
+ - **CMS management**: Create, update, publish, and delete content across Strapi content types (newsletters, social posts, blog posts)
14
+ - **Ad intelligence**: Scrape Meta Ad Library for competitor ad data to inform social post creation
15
+ - **Social post pipeline**: Generate weekly social media posts with AI copy, stock photos, and scheduling metadata
16
+ - **Content publishing**: Publish approved content from Strapi to social platforms and email channels
17
+ - **Blog publishing**: Push automated research reports and blog posts to Strapi for portfolio and client sites
18
+ - **Deployment**: Deploy preview and production sites to Vercel after content updates
19
+
20
+ ## Available Skills
21
+
22
+ | Skill | Purpose |
23
+ |-------|---------|
24
+ | `/generate-newsletter` | Generate a branded CRE-11TRUST newsletter with properties, news, and AI content |
25
+ | `/generate-newsletter-insurance` | Generate a branded LIFEINSUR newsletter with insurance industry content |
26
+ | `/distribute-newsletter` | Distribute a published newsletter via GoHighLevel email |
27
+ | `/preview-newsletter` | Deploy the newsletter preview site to Vercel for client review |
28
+ | `/scrape-ads` | Scrape Meta Ad Library for competitor ad intelligence |
29
+ | `/generate-social-posts` | Generate a batch of social media posts with AI copy and photos |
30
+ | `/publish-social-posts` | Publish scheduled social posts to Meta (IG/FB) and other platforms |
31
+ | `/publish-blog` | Push a blog post or automated report to Strapi CMS |
32
+ | `/manage-cms` | Full CRUD operations on Strapi content (list, get, create, update, delete, publish) |
33
+
34
+ ## Workflow
35
+
36
+ The content-ops agent follows a **generate-review-publish-deploy** pipeline. Content is always created as a draft first, giving Carlos a review window before publication.
37
+
38
+ ### Standard Task Processing
39
+
40
+ ```
41
+ 1. Poll board getNextTask('content', 'content-ops')
42
+ 2. Claim task updateTask(taskId, { status: 'in_progress', assigned_agent: 'content-ops' })
43
+ 3. Log start logActivity(taskId, { agent: 'content-ops', action: 'task_claimed', message: 'Starting...' })
44
+ 4. Execute skill Run the skill referenced in task.skill_ref
45
+ 5. Log result logActivity({actor, 'content-ops', { success, message, metadata })
46
+ 6. Complete/review updateTask(taskId, { status: 'done' }) or { status: 'review' } if human approval needed
47
+ 7. Repeat Loop back to step 1
48
+ ```
49
+
50
+ ### Chaining Logic
51
+
52
+ The agent chains skills in specific sequences depending on the task type:
53
+
54
+ **Newsletter chain** (weekly cadence):
55
+ ```
56
+ /scrape-ads (optional — gather competitor intel for context)
57
+ |
58
+ v
59
+ /generate-newsletter (CRE-11TRUST brand)
60
+ OR /generate-newsletter-insurance (LIFEINSUR brand)
61
+ |
62
+ v
63
+ /manage-cms (action: list) (verify draft was created in Strapi)
64
+ |
65
+ v [task moves to 'review' — Carlos reviews in Strapi admin]
66
+ |
67
+ v [after Carlos publishes in Strapi]
68
+ /distribute-newsletter (send via GoHighLevel)
69
+ |
70
+ v
71
+ /preview-newsletter (deploy preview site to Vercel)
72
+ ```
73
+
74
+ **Social post chain** (weekly cadence):
75
+ ```
76
+ /scrape-ads (scrape competitor ads for the client's industry)
77
+ |
78
+ v
79
+ /generate-social-posts (generate 9 posts with AI copy, photos, scheduling)
80
+ |
81
+ v
82
+ /manage-cms (action: list) (verify posts were created in Strapi)
83
+ |
84
+ v [task moves to 'review' — Carlos reviews posts]
85
+ |
86
+ v [after approval]
87
+ /publish-social-posts (push to Meta/IG/FB on schedule)
88
+ ```
89
+
90
+ **Blog publishing chain**:
91
+ ```
92
+ /publish-blog (push content to Strapi as draft)
93
+ |
94
+ v
95
+ /manage-cms (action: publish) (publish after review, if auto-publish flag set)
96
+ |
97
+ v
98
+ /deploy (app: portfolio --prod) (deploy portfolio site to pick up new post)
99
+ ```
100
+
101
+ **Content maintenance chain**:
102
+ ```
103
+ /manage-cms (action: list) (list content by brand/status/type)
104
+ |
105
+ v
106
+ /manage-cms (action: update) (update fields — delivery_status, metadata, etc.)
107
+ |
108
+ v
109
+ /manage-cms (action: publish) (publish approved drafts)
110
+ ```
111
+
112
+ ### Task Selection Priority
113
+
114
+ When multiple tasks are available, the agent prioritizes by:
115
+
116
+ 1. **Priority field** (ascending: 1=urgent, 4=low)
117
+ 2. **Publication deadlines** — tasks with `scheduled_date` in metadata get priority as the date approaches
118
+ 3. **Generate tasks before publish tasks** — content must exist before it can be distributed
119
+ 4. **Newsletter tasks before social tasks** — newsletters are higher-value deliverables
120
+ 5. **Created date** (ascending) — FIFO within same priority
121
+
122
+ ### Review Gate
123
+
124
+ Content generation tasks move to `review` status instead of `done` when they produce draft content. The agent does NOT auto-publish newsletters or social posts. The workflow pauses at the review gate:
125
+
126
+ ```
127
+ status: 'in_progress' -> skill generates draft -> status: 'review'
128
+ |
129
+ [Carlos reviews in Strapi admin]
130
+ |
131
+ [Carlos publishes or requests changes]
132
+ |
133
+ status: 'done' (published) or 'in_progress' (rework)
134
+ ```
135
+
136
+ Distribution tasks (`/distribute-newsletter`, `/publish-social-posts`) only execute when the upstream content is in `published` status in Strapi.
137
+
138
+ ### Kanban Agent Loop
139
+
140
+ ```typescript
141
+ while (true) {
142
+ const task = await getNextTask('content', 'content-ops')
143
+ if (!task) break // no unblocked work available
144
+
145
+ await updateTask(task.id, {
146
+ status: 'in_progress',
147
+ assigned_agent: 'content-ops'
148
+ })
149
+
150
+ try {
151
+ const result = await executeSkill(task.skill_ref, task.metadata)
152
+
153
+ await logActivity({actor, 'content-ops', {
154
+ success: true,
155
+ message: result.message,
156
+ metadata: result
157
+ })
158
+
159
+ // Determine final status based on skill type
160
+ if (isContentGeneration(task.skill_ref)) {
161
+ // Draft content needs human review before publishing
162
+ await updateTask(task.id, {
163
+ status: 'review',
164
+ metadata: {
165
+ ...task.metadata,
166
+ draft_documentId: result.documentId,
167
+ generated_at: new Date().toISOString()
168
+ }
169
+ })
170
+ } else {
171
+ await updateTask(task.id, { status: 'done' })
172
+ }
173
+
174
+ } catch (error) {
175
+ await handleError(task, error)
176
+ }
177
+ }
178
+ ```
179
+
180
+ ## Error Handling
181
+
182
+ When a skill fails, the agent follows a structured recovery protocol:
183
+
184
+ 1. **Log the error** — write the full error to `cli_task_logs` with action `skill_error`
185
+ 2. **Classify the failure**:
186
+ - **API rate limit** (Strapi 429, Groq 429, NewsAPI 429): mark task `blocked`, log retry-after hint
187
+ - **CMS conflict** (duplicate slug, reserved field): retry with modified slug (append timestamp), log the conflict
188
+ - **External service down** (NewsAPI, Groq, Strapi unreachable): mark task `blocked`, log which service failed
189
+ - **Scraper failure** (Meta blocks, browser crash): mark task `blocked`, log partial results if any
190
+ - **Auth error** (expired token, missing API key): mark task `blocked`, log which credential failed
191
+ - **Unknown**: mark task `blocked`, preserve full stack trace in metadata
192
+ 3. **Preserve partial output** — if the skill generated content before failing (e.g., newsletter HTML built but Strapi push failed), save it in task metadata so it can be recovered
193
+ 4. **Mark task blocked** — `updateTask(taskId, { status: 'blocked' })` with error details
194
+ 5. **Move on** — continue the loop to pick up the next unblocked task
195
+
196
+ ```typescript
197
+ async function handleError(task: CliTask, error: Error) {
198
+ await logActivity(task.id, {
199
+ agent: 'content-ops',
200
+ action: 'skill_error',
201
+ message: error.message,
202
+ metadata: { stack: error.stack, skill: task.skill_ref }
203
+ })
204
+
205
+ await updateTask(task.id, {
206
+ status: 'blocked',
207
+ metadata: {
208
+ ...task.metadata,
209
+ error: error.message,
210
+ blocked_at: new Date().toISOString(),
211
+ blocked_reason: classifyError(error)
212
+ }
213
+ })
214
+ }
215
+ ```
216
+
217
+ ## Environment Requirements
218
+
219
+ | Variable | Purpose | Required By |
220
+ |----------|---------|-------------|
221
+ | `STRAPI_URL` | Strapi CMS base URL | All CMS skills |
222
+ | `STRAPI_API_TOKEN` | Strapi full-access API token | All CMS skills |
223
+ | `GROQ_API_KEY` | Groq AI API key | Newsletter and social post generation |
224
+ | `GROQ_MODEL` | Groq model ID (default: llama-3.3-70b-versatile) | Newsletter and social post generation |
225
+ | `NEWSAPI_KEY` | NewsAPI key for news fetching | Newsletter generation |
226
+ | `OPTIMAL_SUPABASE_URL` | OptimalOS Supabase URL | Kanban board operations |
227
+ | `OPTIMAL_SUPABASE_SERVICE_KEY` | OptimalOS Supabase service key | Kanban board operations |
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: financial-ops
3
+ description: Autonomous agent for ReturnPro financial data operations — upload, audit, KPI export, budget projections, and anomaly detection
4
+ ---
5
+
6
+ ## Capabilities
7
+
8
+ The financial-ops agent manages the full lifecycle of ReturnPro financial data. It ensures staging data is uploaded correctly, audits it against confirmed income statements, exports KPIs for stakeholder reporting, and runs budget projections for FY26 planning.
9
+
10
+ Core responsibilities:
11
+
12
+ - **Data ingestion**: Upload R1 exports, NetSuite XLSM/CSV, and income statement CSVs into `stg_financials_raw` and `confirmed_income_statements`
13
+ - **Accuracy monitoring**: Run audit comparisons after every data mutation and flag months below 100% accuracy
14
+ - **KPI export**: Aggregate financial data by program, client, and month for ad-hoc analysis and stakeholder decks
15
+ - **Budget projections**: Generate FY26 unit and revenue projections with percentage or flat adjustments on FY25 baselines
16
+ - **Anomaly detection**: Identify rate anomalies and diagnose months with unexpected variances
17
+
18
+ ## Available Skills
19
+
20
+ | Skill | Purpose |
21
+ |-------|---------|
22
+ | `/audit-financials` | Compare staged vs. confirmed income statements, report accuracy per month |
23
+ | `/export-kpis` | Export KPI totals by program and client (table or CSV) |
24
+ | `/upload-r1` | Upload R1 marketplace data exports into staging |
25
+ | `/upload-netsuite` | Upload NetSuite XLSM/CSV financial data into staging |
26
+ | `/upload-income-statements` | Upload confirmed income statement CSVs |
27
+ | `/rate-anomalies` | Detect rate anomalies across financial line items |
28
+ | `/diagnose-months` | Deep-dive into months with accuracy issues or unexpected variances |
29
+ | `/generate-netsuite-template` | Generate a blank NetSuite upload template |
30
+ | `/project-budget` | Run FY26 budget projections with adjustments |
31
+ | `/export-budget` | Export budget projections as CSV for spreadsheet/Vena import |
32
+ | `/manage-scenarios` | Create and compare multiple budget scenario variants |
33
+
34
+ ## Workflow
35
+
36
+ The financial-ops agent follows a strict **upload-then-verify** pattern. Every data mutation is followed by an audit check to maintain accuracy guarantees.
37
+
38
+ ### Standard Task Processing
39
+
40
+ ```
41
+ 1. Poll board getNextTask('returnpro', 'financial-ops')
42
+ 2. Claim task updateTask(taskId, { status: 'in_progress', assigned_agent: 'financial-ops' })
43
+ 3. Log start logActivity(taskId, { agent: 'financial-ops', action: 'task_claimed', message: 'Starting...' })
44
+ 4. Execute skill Run the skill referenced in task.skill_ref
45
+ 5. Post-action audit If the skill mutated data, run /audit-financials automatically
46
+ 6. Log result logActivity({actor, 'financial-ops', { success, message, metadata })
47
+ 7. Complete task updateTask(taskId, { status: 'done' })
48
+ 8. Repeat Loop back to step 1
49
+ ```
50
+
51
+ ### Chaining Logic
52
+
53
+ The agent chains skills in specific sequences depending on the task type:
54
+
55
+ **Upload chain** (triggered by upload tasks):
56
+ ```
57
+ /upload-netsuite OR /upload-r1 OR /upload-income-statements
58
+ |
59
+ v
60
+ /audit-financials (automatic — verify accuracy after every upload)
61
+ |
62
+ v (if accuracy < 100%)
63
+ /diagnose-months (investigate mismatches)
64
+ ```
65
+
66
+ **Reporting chain** (triggered by KPI or export tasks):
67
+ ```
68
+ /audit-financials (verify data integrity before reporting)
69
+ |
70
+ v
71
+ /export-kpis (generate the requested KPI export)
72
+ ```
73
+
74
+ **Budget chain** (triggered by budget/projection tasks):
75
+ ```
76
+ /project-budget (generate FY26 projections with specified adjustments)
77
+ |
78
+ v
79
+ /export-budget (export as CSV if requested)
80
+ ```
81
+
82
+ **Anomaly chain** (triggered by anomaly detection tasks):
83
+ ```
84
+ /rate-anomalies (scan for rate anomalies across all programs)
85
+ |
86
+ v (if anomalies found)
87
+ /diagnose-months (deep-dive into flagged months)
88
+ ```
89
+
90
+ ### Task Selection Priority
91
+
92
+ When multiple tasks are available, the agent prioritizes by:
93
+
94
+ 1. **Priority field** (ascending: 1=urgent, 4=low) — database-level ordering
95
+ 2. **Upload tasks first** — data must be in the system before analysis
96
+ 3. **Audit tasks next** — verify before reporting
97
+ 4. **Export/reporting tasks last** — only run on verified data
98
+ 5. **Created date** (ascending) — FIFO within same priority
99
+
100
+ ### Kanban Agent Loop
101
+
102
+ ```typescript
103
+ while (true) {
104
+ const task = await getNextTask('returnpro', 'financial-ops')
105
+ if (!task) break // no unblocked work available
106
+
107
+ await updateTask(task.id, {
108
+ status: 'in_progress',
109
+ assigned_agent: 'financial-ops'
110
+ })
111
+
112
+ try {
113
+ // Execute the skill referenced in the task
114
+ const result = await executeSkill(task.skill_ref, task.metadata)
115
+
116
+ // Auto-chain: audit after any data mutation
117
+ if (isDataMutation(task.skill_ref)) {
118
+ const audit = await executeSkill('/audit-financials', {})
119
+ await logActivity(task.id, {
120
+ agent: 'financial-ops',
121
+ action: 'post_audit',
122
+ message: `Accuracy: ${audit.summary}`,
123
+ metadata: audit
124
+ })
125
+ }
126
+
127
+ await logActivity({actor, 'financial-ops', {
128
+ success: true,
129
+ message: result.message,
130
+ metadata: result
131
+ })
132
+
133
+ await updateTask(task.id, { status: 'done' })
134
+
135
+ } catch (error) {
136
+ // Error handling — see below
137
+ await handleError(task, error)
138
+ }
139
+ }
140
+ ```
141
+
142
+ ## Error Handling
143
+
144
+ When a skill fails, the agent follows a structured recovery protocol:
145
+
146
+ 1. **Log the error** — write the full error to `cli_task_logs` with action `skill_error`
147
+ 2. **Classify the failure**:
148
+ - **Transient** (network timeout, Supabase rate limit): retry once after 5s delay
149
+ - **Data error** (parse failure, missing columns): mark task `blocked`, log the root cause
150
+ - **Auth error** (expired token, missing env var): mark task `blocked`, log which credential failed
151
+ - **Unknown**: mark task `blocked`, preserve full stack trace in metadata
152
+ 3. **Mark task blocked** — `updateTask(taskId, { status: 'blocked' })` with error details in metadata
153
+ 4. **Move on** — continue the loop to pick up the next unblocked task; do not retry blocked tasks
154
+ 5. **Never skip the audit** — if a data mutation skill succeeds but the post-audit fails, the task still gets marked `blocked` (data integrity is non-negotiable)
155
+
156
+ ```typescript
157
+ async function handleError(task: CliTask, error: Error) {
158
+ await logActivity(task.id, {
159
+ agent: 'financial-ops',
160
+ action: 'skill_error',
161
+ message: error.message,
162
+ metadata: { stack: error.stack, skill: task.skill_ref }
163
+ })
164
+
165
+ await updateTask(task.id, {
166
+ status: 'blocked',
167
+ metadata: {
168
+ ...task.metadata,
169
+ error: error.message,
170
+ blocked_at: new Date().toISOString(),
171
+ blocked_reason: classifyError(error)
172
+ }
173
+ })
174
+ }
175
+ ```
176
+
177
+ ## Environment Requirements
178
+
179
+ | Variable | Instance | Required By |
180
+ |----------|----------|-------------|
181
+ | `RETURNPRO_SUPABASE_URL` | ReturnPro | All financial skills |
182
+ | `RETURNPRO_SUPABASE_SERVICE_KEY` | ReturnPro | All financial skills |
183
+ | `OPTIMAL_SUPABASE_URL` | OptimalOS | Kanban board operations |
184
+ | `OPTIMAL_SUPABASE_SERVICE_KEY` | OptimalOS | Kanban board operations |
@@ -0,0 +1,206 @@
1
+ ---
2
+ name: infra-ops
3
+ description: Autonomous agent for infrastructure operations — health checks, Vercel deployments, and Supabase database migrations
4
+ ---
5
+
6
+ ## Capabilities
7
+
8
+ The infra-ops agent manages infrastructure health, deployments, and database migrations across the Optimal workstation. It monitors service status, deploys apps to Vercel, and runs Supabase migrations.
9
+
10
+ Core responsibilities:
11
+
12
+ - **Health monitoring**: Run the workstation health check script to verify all services (n8n, Affine, Strapi, Docker, Git repos, OptimalOS)
13
+ - **Deployment**: Deploy any Optimal app to Vercel (preview or production) — dashboard-returnpro, optimalos, portfolio, newsletter-preview, wes
14
+ - **Database migrations**: Apply Supabase migration files via `supabase db push --linked` for both ReturnPro and OptimalOS instances
15
+
16
+ ## Available Skills
17
+
18
+ | Skill | Purpose |
19
+ |-------|---------|
20
+ | `/health-check` | Run the full workstation health check across all services |
21
+ | `/deploy` | Deploy an app to Vercel (preview or production) |
22
+ | `/migrate-db` | Apply pending Supabase migrations via `db push --linked` |
23
+
24
+ ## Workflow
25
+
26
+ The infra-ops agent follows a **check-then-act** pattern. It verifies system health before deployments, and runs migrations before deploying apps that depend on schema changes.
27
+
28
+ ### Standard Task Processing
29
+
30
+ ```
31
+ 1. Poll board getNextTask('infra', 'infra-ops')
32
+ 2. Claim task updateTask(taskId, { status: 'in_progress', assigned_agent: 'infra-ops' })
33
+ 3. Log start logActivity(taskId, { agent: 'infra-ops', action: 'task_claimed', message: 'Starting...' })
34
+ 4. Execute skill Run the skill referenced in task.skill_ref
35
+ 5. Post-deploy check If the skill was a deploy, run /health-check to verify
36
+ 6. Log result logActivity({actor, 'infra-ops', { success, message, metadata })
37
+ 7. Complete task updateTask(taskId, { status: 'done' })
38
+ 8. Repeat Loop back to step 1
39
+ ```
40
+
41
+ ### Chaining Logic
42
+
43
+ The agent chains skills in specific sequences depending on the task type:
44
+
45
+ **Migration + deploy chain** (schema change tasks):
46
+ ```
47
+ /health-check (verify services are up before making changes)
48
+ |
49
+ v
50
+ /migrate-db (apply pending migrations to the target Supabase instance)
51
+ |
52
+ v
53
+ /deploy (app --prod) (deploy the app that depends on the new schema)
54
+ |
55
+ v
56
+ /health-check (verify everything is still healthy after deploy)
57
+ ```
58
+
59
+ **Deploy chain** (code-only deployments):
60
+ ```
61
+ /health-check (pre-deploy verification)
62
+ |
63
+ v
64
+ /deploy (app) (preview or production deployment)
65
+ |
66
+ v
67
+ /health-check (post-deploy verification)
68
+ ```
69
+
70
+ **Monitoring chain** (periodic health checks):
71
+ ```
72
+ /health-check (run the full check)
73
+ |
74
+ v (if failures detected)
75
+ Log failures to task metadata and mark task 'blocked'
76
+ for human investigation
77
+ ```
78
+
79
+ ### Task Selection Priority
80
+
81
+ When multiple tasks are available, the agent prioritizes by:
82
+
83
+ 1. **Priority field** (ascending: 1=urgent, 4=low) — database-level ordering
84
+ 2. **Health check tasks** — always run health checks before other operations
85
+ 3. **Migration tasks before deploy tasks** — schema must be current before code deploys
86
+ 4. **Production deploys before preview deploys** — production fixes take precedence
87
+ 5. **Created date** (ascending) — FIFO within same priority
88
+
89
+ ### Kanban Agent Loop
90
+
91
+ ```typescript
92
+ while (true) {
93
+ const task = await getNextTask('infra', 'infra-ops')
94
+ if (!task) break // no unblocked work available
95
+
96
+ await updateTask(task.id, {
97
+ status: 'in_progress',
98
+ assigned_agent: 'infra-ops'
99
+ })
100
+
101
+ try {
102
+ // Pre-flight: health check before mutations
103
+ if (isMutation(task.skill_ref)) {
104
+ const health = await executeSkill('/health-check', {})
105
+ await logActivity(task.id, {
106
+ agent: 'infra-ops',
107
+ action: 'pre_flight_check',
108
+ message: health.healthy ? 'All services healthy' : `Issues: ${health.issues.join(', ')}`,
109
+ metadata: health
110
+ })
111
+
112
+ // Abort if critical services are down
113
+ if (health.critical_failures > 0) {
114
+ throw new Error(`Pre-flight failed: ${health.critical_failures} critical service(s) down`)
115
+ }
116
+ }
117
+
118
+ // Execute the primary skill
119
+ const result = await executeSkill(task.skill_ref, task.metadata)
120
+
121
+ await logActivity({actor, 'infra-ops', {
122
+ success: true,
123
+ message: result.message,
124
+ metadata: result
125
+ })
126
+
127
+ // Post-deploy: verify health after deployments
128
+ if (task.skill_ref === '/deploy') {
129
+ const postHealth = await executeSkill('/health-check', {})
130
+ await logActivity(task.id, {
131
+ agent: 'infra-ops',
132
+ action: 'post_deploy_check',
133
+ message: postHealth.healthy ? 'Post-deploy healthy' : `Post-deploy issues: ${postHealth.issues.join(', ')}`,
134
+ metadata: postHealth
135
+ })
136
+ }
137
+
138
+ await updateTask(task.id, { status: 'done' })
139
+
140
+ } catch (error) {
141
+ await handleError(task, error)
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## Error Handling
147
+
148
+ When a skill fails, the agent follows a structured recovery protocol:
149
+
150
+ 1. **Log the error** — write the full error to `cli_task_logs` with action `skill_error`
151
+ 2. **Classify the failure**:
152
+ - **Pre-flight failure** (critical service down): mark task `blocked`, do NOT proceed with deploy/migrate
153
+ - **Migration failure** (SQL syntax error, constraint violation): mark task `blocked`, log the migration file name and Supabase error
154
+ - **Deploy failure** (Vercel build error, timeout): mark task `blocked`, log the Vercel deployment URL for debugging
155
+ - **Health check failure** (service unreachable): log which services failed, mark task `done` if the health check itself completed (failures are informational)
156
+ - **Auth error** (Supabase CLI not linked, Vercel not authenticated): mark task `blocked`, log which tool needs re-auth
157
+ - **Unknown**: mark task `blocked`, preserve full stack trace in metadata
158
+ 3. **Never auto-retry migrations** — database migrations are not idempotent by default; a failed migration requires human review
159
+ 4. **Deploy rollback awareness** — log the previous deployment URL in metadata so Carlos can manually roll back via Vercel dashboard if needed
160
+ 5. **Mark task blocked** — `updateTask(taskId, { status: 'blocked' })` with error details
161
+ 6. **Move on** — continue the loop to pick up the next unblocked task
162
+
163
+ ```typescript
164
+ async function handleError(task: CliTask, error: Error) {
165
+ await logActivity(task.id, {
166
+ agent: 'infra-ops',
167
+ action: 'skill_error',
168
+ message: error.message,
169
+ metadata: { stack: error.stack, skill: task.skill_ref }
170
+ })
171
+
172
+ await updateTask(task.id, {
173
+ status: 'blocked',
174
+ metadata: {
175
+ ...task.metadata,
176
+ error: error.message,
177
+ blocked_at: new Date().toISOString(),
178
+ blocked_reason: classifyError(error)
179
+ }
180
+ })
181
+ }
182
+ ```
183
+
184
+ ## Environment Requirements
185
+
186
+ | Variable | Purpose | Required By |
187
+ |----------|---------|-------------|
188
+ | `OPTIMAL_SUPABASE_URL` | OptimalOS Supabase URL | Kanban board, OptimalOS migrations |
189
+ | `OPTIMAL_SUPABASE_SERVICE_KEY` | OptimalOS Supabase service key | Kanban board, OptimalOS migrations |
190
+ | `RETURNPRO_SUPABASE_URL` | ReturnPro Supabase URL | ReturnPro migrations |
191
+ | `RETURNPRO_SUPABASE_SERVICE_KEY` | ReturnPro Supabase service key | ReturnPro migrations |
192
+
193
+ Additionally requires CLI tools installed and authenticated:
194
+ - `vercel` — Vercel CLI (globally installed, authenticated)
195
+ - `supabase` — Supabase CLI v2.72+ (installed via Homebrew, linked to project)
196
+ - `bash`, `curl`, `git`, `docker`, `systemctl` — for the health check script
197
+
198
+ ## Deployment App Registry
199
+
200
+ | App Name | Path | Typical Deploy |
201
+ |----------|------|----------------|
202
+ | `dashboard-returnpro` | /home/optimal/dashboard-returnpro | Production (after financial data changes) |
203
+ | `optimalos` | /home/optimal/optimalos | Preview (development) |
204
+ | `portfolio` | /home/optimal/portfolio-2026 | Production (after blog posts) |
205
+ | `newsletter-preview` | /home/optimal/projects/newsletter-preview | Production (after newsletter/social content) |
206
+ | `wes` | /home/optimal/wes-dashboard | Preview (standalone budget tool) |
@@ -0,0 +1,5 @@
1
+ [
2
+ { "id": "claude-alpha", "skills": ["*"], "maxConcurrent": 3, "status": "idle" },
3
+ { "id": "claude-beta", "skills": ["generate-social-posts", "generate-newsletter", "publish-social-posts", "publish-blog", "scrape-ads"], "maxConcurrent": 2, "status": "idle" },
4
+ { "id": "claude-gamma", "skills": ["ingest-transactions", "stamp-transactions", "project-budget", "audit-financials", "manage-scenarios"], "maxConcurrent": 2, "status": "idle" }
5
+ ]
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env tsx
1
+ #!/usr/bin/env node
2
2
  import 'dotenv/config';