@cohortapp/agent-sdk 2.3.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 (731) hide show
  1. package/.claude/commands/init-agent.md +104 -0
  2. package/.claude/commands/init-maestro.md +1187 -0
  3. package/.claude/settings.json +161 -0
  4. package/.env.example +216 -0
  5. package/README.md +632 -0
  6. package/agents/browser-operator/agent.md +52 -0
  7. package/agents/calendar-ops/agent.md +50 -0
  8. package/agents/communications/agent.md +96 -0
  9. package/agents/decision-log/agent.md +65 -0
  10. package/agents/desktop-operator/agent.md +59 -0
  11. package/agents/gmail-operator/agent.md +62 -0
  12. package/agents/inbound-dispatcher/agent.md +66 -0
  13. package/agents/inbox-processor/agent.md +39 -0
  14. package/agents/pmo-execution/agent.md +60 -0
  15. package/agents/session-spawner/agent.md +64 -0
  16. package/agents/slack-operator/agent.md +60 -0
  17. package/agents/whatsapp-operator/agent.md +60 -0
  18. package/agents/workflow-automation/agent.md +61 -0
  19. package/archetypes/altitudes/c-suite.yaml +58 -0
  20. package/archetypes/altitudes/founder.yaml +68 -0
  21. package/archetypes/altitudes/senior-manager.yaml +63 -0
  22. package/archetypes/altitudes/svp.yaml +60 -0
  23. package/archetypes/altitudes/vp.yaml +50 -0
  24. package/archetypes/archetype.schema.json +77 -0
  25. package/archetypes/base.yaml +47 -0
  26. package/archetypes/capabilities/commercial-leader.yaml +159 -0
  27. package/archetypes/capabilities/compliance-officer.yaml +159 -0
  28. package/archetypes/capabilities/executive-operator.yaml +169 -0
  29. package/archetypes/capabilities/finance-leader.yaml +162 -0
  30. package/archetypes/capabilities/operations-leader.yaml +154 -0
  31. package/archetypes/capabilities/product-leader.yaml +148 -0
  32. package/archetypes/capabilities/technical-leader.yaml +146 -0
  33. package/archetypes/functions/commercial-leader.yaml +62 -0
  34. package/archetypes/functions/compliance-officer.yaml +64 -0
  35. package/archetypes/functions/executive-operator.yaml +70 -0
  36. package/archetypes/functions/finance-leader.yaml +70 -0
  37. package/archetypes/functions/operations-leader.yaml +62 -0
  38. package/archetypes/functions/product-leader.yaml +61 -0
  39. package/archetypes/functions/technical-leader.yaml +57 -0
  40. package/bin/cohort-mcp.mjs +81 -0
  41. package/bin/maestro.mjs +3516 -0
  42. package/bin/maestro.test.mjs +1015 -0
  43. package/desktop-control/README.md +56 -0
  44. package/desktop-control/app-profiles/gmail.yaml +120 -0
  45. package/desktop-control/app-profiles/slack.yaml +315 -0
  46. package/desktop-control/app-profiles/whatsapp.yaml +107 -0
  47. package/docs/architecture/agent-topology.md +2239 -0
  48. package/docs/architecture/archetype-agent-factory.md +110 -0
  49. package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
  50. package/docs/architecture/continuous-monitoring.md +221 -0
  51. package/docs/architecture/mcp-capability-map.md +585 -0
  52. package/docs/architecture/system-architecture.md +1272 -0
  53. package/docs/company-context/README.md +40 -0
  54. package/docs/guides/agent-persona-setup.md +600 -0
  55. package/docs/guides/agents-observe-setup.md +64 -0
  56. package/docs/guides/billing-console-keys.md +88 -0
  57. package/docs/guides/ccxray-diagnostics.md +65 -0
  58. package/docs/guides/channel-bus.md +127 -0
  59. package/docs/guides/claude-mem-setup.md +79 -0
  60. package/docs/guides/claude-pace-setup.md +56 -0
  61. package/docs/guides/claudraband-sessions.md +98 -0
  62. package/docs/guides/clawteam-swarm.md +116 -0
  63. package/docs/guides/code-review-graph-setup.md +86 -0
  64. package/docs/guides/email-setup.md +431 -0
  65. package/docs/guides/mac-mini.md +119 -0
  66. package/docs/guides/media-generation-setup.md +349 -0
  67. package/docs/guides/model-routing.md +162 -0
  68. package/docs/guides/observability-otel.md +265 -0
  69. package/docs/guides/org-onboarding.md +132 -0
  70. package/docs/guides/outbound-governance-setup.md +437 -0
  71. package/docs/guides/pdf-generation-setup.md +315 -0
  72. package/docs/guides/poller-daemon-setup.md +563 -0
  73. package/docs/guides/rag-context-setup.md +459 -0
  74. package/docs/guides/self-optimization-pattern.md +82 -0
  75. package/docs/guides/setup-wizard.md +178 -0
  76. package/docs/guides/slack-setup.md +350 -0
  77. package/docs/guides/telegram-setup.md +227 -0
  78. package/docs/guides/twilio-subaccounts-setup.md +223 -0
  79. package/docs/guides/verification.md +128 -0
  80. package/docs/guides/voice-mode.md +188 -0
  81. package/docs/guides/voice-sms-setup.md +698 -0
  82. package/docs/guides/webhook-relay-setup.md +349 -0
  83. package/docs/guides/whatsapp-setup.md +288 -0
  84. package/docs/prompts/board-pack-cover-template.md +36 -0
  85. package/docs/prompts/decision-recommendation-template.md +88 -0
  86. package/docs/prompts/followup-message-template.md +141 -0
  87. package/docs/prompts/investor-letter-template.md +52 -0
  88. package/docs/prompts/morning-brief-template.md +82 -0
  89. package/docs/prompts/presentation-template.md +58 -0
  90. package/docs/prompts/weekly-strategic-memo-template.md +104 -0
  91. package/docs/research/hallucinated-tool-output-investigation.md +151 -0
  92. package/docs/runbooks/backup-restore.md +205 -0
  93. package/docs/runbooks/cohort-cutover.md +129 -0
  94. package/docs/runbooks/fleet-operations.md +200 -0
  95. package/docs/runbooks/incident-response.md +226 -0
  96. package/docs/runbooks/mac-mini-bootstrap.md +431 -0
  97. package/docs/runbooks/perpetual-operations.md +509 -0
  98. package/docs/runbooks/recovery-and-failover.md +260 -0
  99. package/framework-features.json +267 -0
  100. package/ingest/README.md +87 -0
  101. package/lib/action-executor.js +689 -0
  102. package/lib/action-executor.test.mjs +871 -0
  103. package/lib/agent-root.mjs +37 -0
  104. package/lib/archetype.mjs +236 -0
  105. package/lib/archetype.test.mjs +132 -0
  106. package/lib/autonomy.mjs +114 -0
  107. package/lib/autonomy.test.mjs +66 -0
  108. package/lib/backlog.mjs +358 -0
  109. package/lib/backlog.test.mjs +266 -0
  110. package/lib/budget-guard.mjs +279 -0
  111. package/lib/budget-guard.test.mjs +291 -0
  112. package/lib/cadence-bus-schedule.test.mjs +194 -0
  113. package/lib/cadence-bus.mjs +1120 -0
  114. package/lib/cadence-bus.test.mjs +720 -0
  115. package/lib/cadences.mjs +205 -0
  116. package/lib/cadences.test.mjs +125 -0
  117. package/lib/capability.mjs +154 -0
  118. package/lib/capability.test.mjs +78 -0
  119. package/lib/channels/base-adapter.mjs +719 -0
  120. package/lib/channels/base-adapter.test.mjs +590 -0
  121. package/lib/channels/channel.mjs +128 -0
  122. package/lib/channels/channels.test.mjs +371 -0
  123. package/lib/channels/contract.mjs +215 -0
  124. package/lib/channels/contract.test.mjs +137 -0
  125. package/lib/channels/conversation-resolver.mjs +95 -0
  126. package/lib/channels/gmail/adapter.mjs +87 -0
  127. package/lib/channels/inbox-item.mjs +255 -0
  128. package/lib/channels/inbox-item.test.mjs +335 -0
  129. package/lib/channels/index.mjs +94 -0
  130. package/lib/channels/orgmail/adapter.mjs +353 -0
  131. package/lib/channels/orgmail/adapter.test.mjs +311 -0
  132. package/lib/channels/pairing.mjs +363 -0
  133. package/lib/channels/pairing.test.mjs +270 -0
  134. package/lib/channels/registry.mjs +164 -0
  135. package/lib/channels/slack/adapter.mjs +317 -0
  136. package/lib/channels/slack-adapter.test.mjs +212 -0
  137. package/lib/channels/sms/adapter.mjs +43 -0
  138. package/lib/channels/telegram/adapter.mjs +432 -0
  139. package/lib/channels/telegram-adapter.test.mjs +306 -0
  140. package/lib/channels/voice/adapter.mjs +301 -0
  141. package/lib/channels/voice/adapter.test.mjs +278 -0
  142. package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
  143. package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
  144. package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
  145. package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
  146. package/lib/charter.mjs +256 -0
  147. package/lib/charter.test.mjs +89 -0
  148. package/lib/claude-bin.mjs +134 -0
  149. package/lib/claude-bin.test.mjs +75 -0
  150. package/lib/collective/capture.mjs +185 -0
  151. package/lib/collective/capture.test.mjs +121 -0
  152. package/lib/collective/cards.mjs +201 -0
  153. package/lib/collective/cards.test.mjs +114 -0
  154. package/lib/collective/config.mjs +186 -0
  155. package/lib/collective/config.test.mjs +123 -0
  156. package/lib/collective/global-config.mjs +113 -0
  157. package/lib/collective/global-config.test.mjs +75 -0
  158. package/lib/collective/presence.mjs +201 -0
  159. package/lib/collective/presence.test.mjs +95 -0
  160. package/lib/collective/recall.mjs +215 -0
  161. package/lib/collective/recall.test.mjs +116 -0
  162. package/lib/comms/send-gate.mjs +554 -0
  163. package/lib/comms/send-gate.test.mjs +577 -0
  164. package/lib/comms.mjs +67 -0
  165. package/lib/comms.test.mjs +41 -0
  166. package/lib/diagnostics/alerts.mjs +424 -0
  167. package/lib/diagnostics/alerts.test.mjs +318 -0
  168. package/lib/diagnostics/backup-freshness.mjs +188 -0
  169. package/lib/diagnostics/backup-freshness.test.mjs +185 -0
  170. package/lib/diagnostics/counters.mjs +269 -0
  171. package/lib/diagnostics/counters.test.mjs +206 -0
  172. package/lib/diagnostics/events.mjs +188 -0
  173. package/lib/diagnostics/events.test.mjs +290 -0
  174. package/lib/diagnostics/otel.mjs +237 -0
  175. package/lib/diagnostics/otel.test.mjs +196 -0
  176. package/lib/diagnostics/trace.mjs +216 -0
  177. package/lib/diagnostics/trace.test.mjs +251 -0
  178. package/lib/env-compat.mjs +74 -0
  179. package/lib/env-compat.test.mjs +104 -0
  180. package/lib/feature-init.mjs +331 -0
  181. package/lib/fs-atomic.mjs +112 -0
  182. package/lib/fs-atomic.test.mjs +72 -0
  183. package/lib/fs-ownership.mjs +111 -0
  184. package/lib/fs-ownership.test.mjs +158 -0
  185. package/lib/hooks/bus.mjs +347 -0
  186. package/lib/hooks/bus.test.mjs +387 -0
  187. package/lib/index.js +16 -0
  188. package/lib/learning/config.mjs +106 -0
  189. package/lib/learning/config.test.mjs +75 -0
  190. package/lib/learning/counters.mjs +156 -0
  191. package/lib/learning/counters.test.mjs +69 -0
  192. package/lib/learning/curator-consolidate.test.mjs +238 -0
  193. package/lib/learning/curator.mjs +453 -0
  194. package/lib/learning/curator.test.mjs +106 -0
  195. package/lib/learning/log.mjs +40 -0
  196. package/lib/learning/reflect.mjs +534 -0
  197. package/lib/learning/reflect.test.mjs +0 -0
  198. package/lib/learning/session-index.mjs +352 -0
  199. package/lib/learning/session-index.test.mjs +125 -0
  200. package/lib/learning/skill-writer.mjs +474 -0
  201. package/lib/learning/skill-writer.test.mjs +210 -0
  202. package/lib/mcp/server.mjs +328 -0
  203. package/lib/mcp/server.test.mjs +400 -0
  204. package/lib/model-router/auth-profiles.mjs +758 -0
  205. package/lib/model-router/auth-profiles.test.mjs +580 -0
  206. package/lib/model-router/catalog/anthropic.yaml +153 -0
  207. package/lib/model-router/catalog/deepseek.yaml +86 -0
  208. package/lib/model-router/catalog/moonshot.yaml +81 -0
  209. package/lib/model-router/catalog/qwen.yaml +114 -0
  210. package/lib/model-router/catalog.mjs +925 -0
  211. package/lib/model-router/catalog.test.mjs +385 -0
  212. package/lib/model-router/economics.mjs +564 -0
  213. package/lib/model-router/economics.test.mjs +344 -0
  214. package/lib/model-router/failover.mjs +298 -0
  215. package/lib/model-router/failover.test.mjs +439 -0
  216. package/lib/model-router/health.mjs +453 -0
  217. package/lib/model-router/health.test.mjs +338 -0
  218. package/lib/model-router/integration-coverage.test.mjs +829 -0
  219. package/lib/model-router/integration.test.mjs +564 -0
  220. package/lib/model-router/ledger.mjs +402 -0
  221. package/lib/model-router/ledger.test.mjs +382 -0
  222. package/lib/model-router/llm-task.mjs +515 -0
  223. package/lib/model-router/llm-task.test.mjs +392 -0
  224. package/lib/model-router/org-credentials.mjs +260 -0
  225. package/lib/model-router/org-credentials.test.mjs +265 -0
  226. package/lib/model-router/pricing-refresh.mjs +463 -0
  227. package/lib/model-router/pricing-refresh.test.mjs +286 -0
  228. package/lib/model-router/reconcile.mjs +429 -0
  229. package/lib/model-router/reconcile.test.mjs +316 -0
  230. package/lib/model-router/repair.mjs +471 -0
  231. package/lib/model-router/repair.test.mjs +180 -0
  232. package/lib/model-router/resolve.mjs +1206 -0
  233. package/lib/model-router/spawn.mjs +497 -0
  234. package/lib/model-router/spawn.test.mjs +425 -0
  235. package/lib/model-router/taxonomy.mjs +893 -0
  236. package/lib/model-router/taxonomy.test.mjs +410 -0
  237. package/lib/model-router.mjs +677 -0
  238. package/lib/model-router.test.mjs +907 -0
  239. package/lib/org/activity.mjs +211 -0
  240. package/lib/org/activity.test.mjs +134 -0
  241. package/lib/org/approvals.mjs +448 -0
  242. package/lib/org/approvals.test.mjs +216 -0
  243. package/lib/org/awareness.mjs +222 -0
  244. package/lib/org/awareness.test.mjs +159 -0
  245. package/lib/org/board.mjs +229 -0
  246. package/lib/org/board.test.mjs +177 -0
  247. package/lib/org/bootstrap-context.mjs +169 -0
  248. package/lib/org/bootstrap-context.test.mjs +153 -0
  249. package/lib/org/client.mjs +1628 -0
  250. package/lib/org/client.test.mjs +1107 -0
  251. package/lib/org/cohort-client.mjs +67 -0
  252. package/lib/org/cohort-client.test.mjs +126 -0
  253. package/lib/org/cost-sync.mjs +227 -0
  254. package/lib/org/cost-sync.test.mjs +153 -0
  255. package/lib/org/doctor.mjs +212 -0
  256. package/lib/org/doctor.test.mjs +212 -0
  257. package/lib/org/handoff.mjs +293 -0
  258. package/lib/org/handoff.test.mjs +269 -0
  259. package/lib/org/integration-tools.mjs +182 -0
  260. package/lib/org/integration-tools.test.mjs +160 -0
  261. package/lib/org/keys.mjs +131 -0
  262. package/lib/org/keys.test.mjs +92 -0
  263. package/lib/org/knowledge.mjs +463 -0
  264. package/lib/org/knowledge.test.mjs +319 -0
  265. package/lib/org/leases.mjs +335 -0
  266. package/lib/org/leases.test.mjs +235 -0
  267. package/lib/org/mesh-integration.test.mjs +127 -0
  268. package/lib/org/mesh.mjs +459 -0
  269. package/lib/org/mesh.test.mjs +345 -0
  270. package/lib/org/messaging.mjs +503 -0
  271. package/lib/org/messaging.test.mjs +238 -0
  272. package/lib/org/policy.mjs +345 -0
  273. package/lib/org/policy.test.mjs +237 -0
  274. package/lib/org/protocol.checksum +1 -0
  275. package/lib/org/protocol.checksum.test.mjs +90 -0
  276. package/lib/org/protocol.mjs +967 -0
  277. package/lib/org/protocol.test.mjs +264 -0
  278. package/lib/org/registry.mjs +194 -0
  279. package/lib/org/registry.test.mjs +100 -0
  280. package/lib/org/tool-surface-integration.test.mjs +120 -0
  281. package/lib/org/tool-surface.mjs +2535 -0
  282. package/lib/org/tool-surface.test.mjs +589 -0
  283. package/lib/org/ui-parity.mjs +3236 -0
  284. package/lib/org/ui-parity.test.mjs +348 -0
  285. package/lib/org/verify.mjs +176 -0
  286. package/lib/org/verify.test.mjs +194 -0
  287. package/lib/rag/embed.mjs +188 -0
  288. package/lib/rag/indexer.mjs +425 -0
  289. package/lib/rag/rag.test.mjs +505 -0
  290. package/lib/rag/search.mjs +475 -0
  291. package/lib/rate-guard.mjs +246 -0
  292. package/lib/rate-guard.test.mjs +201 -0
  293. package/lib/render.mjs +112 -0
  294. package/lib/render.test.mjs +68 -0
  295. package/lib/resource-governor.mjs +297 -0
  296. package/lib/resource-governor.test.mjs +262 -0
  297. package/lib/scheduling/dynamic-jobs.mjs +675 -0
  298. package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
  299. package/lib/scheduling/jitter.mjs +0 -0
  300. package/lib/scheduling/jitter.test.mjs +140 -0
  301. package/lib/secrets/broker.mjs +315 -0
  302. package/lib/secrets/broker.test.mjs +280 -0
  303. package/lib/secrets/providers.mjs +461 -0
  304. package/lib/secrets/providers.test.mjs +274 -0
  305. package/lib/security/audit-engine.mjs +684 -0
  306. package/lib/security/audit-engine.test.mjs +389 -0
  307. package/lib/security/coerce-args.mjs +552 -0
  308. package/lib/security/coerce-args.test.mjs +281 -0
  309. package/lib/security/dangerous-tools.mjs +97 -0
  310. package/lib/security/dangerous-tools.test.mjs +68 -0
  311. package/lib/security/external-content.mjs +145 -0
  312. package/lib/security/external-content.test.mjs +67 -0
  313. package/lib/security/redact.mjs +592 -0
  314. package/lib/security/redact.test.mjs +441 -0
  315. package/lib/security/secret-equal.mjs +73 -0
  316. package/lib/security/secret-equal.test.mjs +55 -0
  317. package/lib/session-permissions.mjs +101 -0
  318. package/lib/session-permissions.test.mjs +100 -0
  319. package/lib/setup/claude-probe.mjs +74 -0
  320. package/lib/setup/completeness.mjs +175 -0
  321. package/lib/setup/completeness.test.mjs +110 -0
  322. package/lib/setup/context-pack.mjs +173 -0
  323. package/lib/setup/context-pack.test.mjs +89 -0
  324. package/lib/setup/enrich.mjs +277 -0
  325. package/lib/setup/enrich.test.mjs +115 -0
  326. package/lib/setup/enroll-from-cohort.mjs +441 -0
  327. package/lib/setup/enroll-from-cohort.test.mjs +233 -0
  328. package/lib/setup/integration.test.mjs +162 -0
  329. package/lib/setup/io.mjs +360 -0
  330. package/lib/setup/io.test.mjs +77 -0
  331. package/lib/setup/run-generator.mjs +81 -0
  332. package/lib/setup/runner.mjs +244 -0
  333. package/lib/setup/runner.test.mjs +132 -0
  334. package/lib/setup/sections/comms.mjs +173 -0
  335. package/lib/setup/sections/company.mjs +120 -0
  336. package/lib/setup/sections/enrich.mjs +138 -0
  337. package/lib/setup/sections/identity.mjs +182 -0
  338. package/lib/setup/sections/identity.test.mjs +140 -0
  339. package/lib/setup/sections/learning.mjs +153 -0
  340. package/lib/setup/sections/learning.test.mjs +81 -0
  341. package/lib/setup/sections/messaging.mjs +219 -0
  342. package/lib/setup/sections/messaging.test.mjs +127 -0
  343. package/lib/setup/sections/model.mjs +102 -0
  344. package/lib/setup/sections/operating-model.mjs +78 -0
  345. package/lib/setup/sections/org.mjs +475 -0
  346. package/lib/setup/sections/org.test.mjs +313 -0
  347. package/lib/setup/sections/orgmail.mjs +173 -0
  348. package/lib/setup/sections/orgmail.test.mjs +118 -0
  349. package/lib/setup/sections/recovery.mjs +159 -0
  350. package/lib/setup/sections/recovery.test.mjs +98 -0
  351. package/lib/setup/sections/tools.mjs +132 -0
  352. package/lib/setup/sections/verify.mjs +97 -0
  353. package/lib/setup/sot.mjs +205 -0
  354. package/lib/setup/sot.test.mjs +81 -0
  355. package/lib/setup/state.mjs +151 -0
  356. package/lib/setup/state.test.mjs +92 -0
  357. package/lib/singleton.js +229 -0
  358. package/lib/singleton.test.mjs +135 -0
  359. package/lib/telemetry/alerts.mjs +216 -0
  360. package/lib/telemetry/alerts.test.mjs +109 -0
  361. package/lib/telemetry/collect.mjs +512 -0
  362. package/lib/telemetry/collect.test.mjs +202 -0
  363. package/lib/tool-definitions-integration.test.mjs +83 -0
  364. package/lib/tool-definitions.js +738 -0
  365. package/lib/tool-definitions.test.mjs +437 -0
  366. package/lib/util/fetch-timeout.mjs +136 -0
  367. package/lib/util/fetch-timeout.test.mjs +202 -0
  368. package/lib/util/reconnect.mjs +343 -0
  369. package/lib/util/reconnect.test.mjs +369 -0
  370. package/lib/util/unhandled.mjs +205 -0
  371. package/lib/util/unhandled.test.mjs +216 -0
  372. package/lib/voice/context-loader.mjs +466 -0
  373. package/lib/voice/index.mjs +100 -0
  374. package/lib/voice/openai-realtime.mjs +510 -0
  375. package/lib/voice/outbound.mjs +542 -0
  376. package/lib/voice/outbound.test.mjs +69 -0
  377. package/lib/voice/post-call-brief.mjs +428 -0
  378. package/lib/voice/provider.mjs +52 -0
  379. package/lib/voice/session-rotation.mjs +257 -0
  380. package/lib/voice/stt.mjs +161 -0
  381. package/lib/voice/stt.test.mjs +226 -0
  382. package/lib/voice/tool-bridge.mjs +370 -0
  383. package/lib/voice/tts.mjs +104 -0
  384. package/lib/voice/twilio-sip-bridge.mjs +288 -0
  385. package/lib/voice/voice.test.mjs +990 -0
  386. package/mcp/README.md +80 -0
  387. package/package.json +151 -0
  388. package/plugins/maestro-skills/plugin.json +139 -0
  389. package/plugins/maestro-skills/skills/agents-observe.md +110 -0
  390. package/plugins/maestro-skills/skills/board-deck.md +68 -0
  391. package/plugins/maestro-skills/skills/books-close.md +77 -0
  392. package/plugins/maestro-skills/skills/brand-steward.md +121 -0
  393. package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
  394. package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
  395. package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
  396. package/plugins/maestro-skills/skills/claude-pace.md +61 -0
  397. package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
  398. package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
  399. package/plugins/maestro-skills/skills/decision-brief.md +89 -0
  400. package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
  401. package/plugins/maestro-skills/skills/draft-comms.md +84 -0
  402. package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
  403. package/plugins/maestro-skills/skills/files-find.md +65 -0
  404. package/plugins/maestro-skills/skills/generative-ui.md +228 -0
  405. package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
  406. package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
  407. package/plugins/maestro-skills/skills/mail-triage.md +86 -0
  408. package/plugins/maestro-skills/skills/morning-brief.md +54 -0
  409. package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
  410. package/plugins/maestro-skills/skills/org-board.md +133 -0
  411. package/plugins/maestro-skills/skills/org-credential.md +68 -0
  412. package/plugins/maestro-skills/skills/org-recall.md +81 -0
  413. package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
  414. package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
  415. package/plugins/maestro-skills/skills/router-why.md +78 -0
  416. package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
  417. package/plugins/maestro-skills/skills/session-search.md +71 -0
  418. package/plugins/maestro-skills/skills/set-reminder.md +93 -0
  419. package/plugins/maestro-skills/skills/slack-followup.md +64 -0
  420. package/plugins/maestro-skills/skills/team-activity.md +86 -0
  421. package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
  422. package/policies/action-classification.yaml +114 -0
  423. package/policies/ai-disclosure.yaml +294 -0
  424. package/policies/communication-style.md +139 -0
  425. package/policies/information-barriers.yaml +118 -0
  426. package/policies/prompt-injection-defence.yaml +138 -0
  427. package/public/assets/icon-dark.png +0 -0
  428. package/public/assets/icon-dark.svg +9 -0
  429. package/public/assets/icon-light.svg +9 -0
  430. package/public/assets/logo-dark.svg +15 -0
  431. package/public/assets/logo-light.svg +15 -0
  432. package/scaffold/.mcp.json +7 -0
  433. package/scaffold/CLAUDE.md +368 -0
  434. package/scaffold/config/agent.json +55 -0
  435. package/scaffold/config/agent.ts +76 -0
  436. package/scaffold/config/agent.ts.example +89 -0
  437. package/scaffold/config/alerts.yaml +23 -0
  438. package/scaffold/config/allowlist.yaml.example +25 -0
  439. package/scaffold/config/caller-id-map.yaml +46 -0
  440. package/scaffold/config/collective.yaml +49 -0
  441. package/scaffold/config/company.json +20 -0
  442. package/scaffold/config/known-agents.json +6 -0
  443. package/scaffold/config/learning.yaml +55 -0
  444. package/scaffold/config/model-routing.yaml.example +104 -0
  445. package/scaffold/config/org.yaml +25 -0
  446. package/scaffold/config/orgmail.yaml.example +19 -0
  447. package/scaffold/config/recovery.yaml +72 -0
  448. package/scaffold/config/secrets.yaml +27 -0
  449. package/scaffold/config/slack.yaml.example +35 -0
  450. package/scaffold/config/telegram.yaml.example +38 -0
  451. package/scaffold/config/voice.yaml.example +89 -0
  452. package/scaffold/config/whatsapp.yaml.example +39 -0
  453. package/schedules/README.md +49 -0
  454. package/schedules/triggers/backlog-executor.md +102 -0
  455. package/schedules/triggers/brand-steward.md +72 -0
  456. package/schedules/triggers/daily-evening-wrap.md +159 -0
  457. package/schedules/triggers/daily-midday-sweep.md +58 -0
  458. package/schedules/triggers/daily-morning-brief.md +55 -0
  459. package/schedules/triggers/directory-hygiene.md +81 -0
  460. package/schedules/triggers/dynamic-jobs.md +40 -0
  461. package/schedules/triggers/inbox-processor.md +115 -0
  462. package/schedules/triggers/meeting-action-capture.md +60 -0
  463. package/schedules/triggers/meeting-prep.md +69 -0
  464. package/schedules/triggers/messaging-inbound.md +50 -0
  465. package/schedules/triggers/org-pulse.md +24 -0
  466. package/schedules/triggers/quarterly-self-assessment.md +54 -0
  467. package/schedules/triggers/weekly-engineering-health.md +37 -0
  468. package/schedules/triggers/weekly-execution.md +65 -0
  469. package/schedules/triggers/weekly-hiring.md +53 -0
  470. package/schedules/triggers/weekly-priorities.md +38 -0
  471. package/schedules/triggers/weekly-strategic-memo.md +124 -0
  472. package/scripts/archive-email.sh +55 -0
  473. package/scripts/cadence/cadence-status.mjs +36 -0
  474. package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
  475. package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
  476. package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
  477. package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
  478. package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
  479. package/scripts/ci/check-docs-accuracy.mjs +493 -0
  480. package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
  481. package/scripts/ci/check-exports-exist.mjs +140 -0
  482. package/scripts/ci/check-files-exist.mjs +107 -0
  483. package/scripts/ci/check-no-build-artifacts.mjs +111 -0
  484. package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
  485. package/scripts/ci/check-no-confidential.mjs +198 -0
  486. package/scripts/ci/check-no-conflict-markers.mjs +169 -0
  487. package/scripts/ci/check-no-residual-identity.mjs +163 -0
  488. package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
  489. package/scripts/ci/check-tarball-fidelity.mjs +205 -0
  490. package/scripts/ci/check-unresolved-tokens.mjs +83 -0
  491. package/scripts/ci/check.mjs +109 -0
  492. package/scripts/ci/check.test.mjs +194 -0
  493. package/scripts/ci/run-coverage.mjs +82 -0
  494. package/scripts/ci/run-tests.mjs +71 -0
  495. package/scripts/cloud-relay/README.md +59 -0
  496. package/scripts/cloud-relay/index.mjs +233 -0
  497. package/scripts/cloud-relay/package.json +15 -0
  498. package/scripts/cloud-relay/railway.json +13 -0
  499. package/scripts/cloud-relay/voice/README.md +94 -0
  500. package/scripts/cloud-relay/voice/package-lock.json +39 -0
  501. package/scripts/cloud-relay/voice/package.json +16 -0
  502. package/scripts/cloud-relay/voice/railway.json +13 -0
  503. package/scripts/cloud-relay/voice/server.mjs +532 -0
  504. package/scripts/collective/hook-runner.mjs +211 -0
  505. package/scripts/collective/hook-runner.test.mjs +90 -0
  506. package/scripts/collective/org-pulse.mjs +72 -0
  507. package/scripts/collective/org-sync.mjs +61 -0
  508. package/scripts/collective/recall.mjs +45 -0
  509. package/scripts/collective/who.mjs +30 -0
  510. package/scripts/comms-monitor.sh +288 -0
  511. package/scripts/configure-whatsapp-sandbox.sh +201 -0
  512. package/scripts/continuous-monitor.sh +91 -0
  513. package/scripts/cost/fleet-digest.mjs +407 -0
  514. package/scripts/cost/fleet-digest.test.mjs +207 -0
  515. package/scripts/cost/track-claude-usage.mjs +169 -0
  516. package/scripts/daemon/agent-daemon.mjs +989 -0
  517. package/scripts/daemon/agent-daemon.test.mjs +525 -0
  518. package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
  519. package/scripts/daemon/cadence-consumer.mjs +1080 -0
  520. package/scripts/daemon/cadence-consumer.test.mjs +770 -0
  521. package/scripts/daemon/cadence-handlers.mjs +1121 -0
  522. package/scripts/daemon/cadence-handlers.test.mjs +617 -0
  523. package/scripts/daemon/classifier.mjs +704 -0
  524. package/scripts/daemon/classifier.test.mjs +238 -0
  525. package/scripts/daemon/classify-kind.mjs +54 -0
  526. package/scripts/daemon/classify-kind.test.mjs +40 -0
  527. package/scripts/daemon/context-compiler.mjs +605 -0
  528. package/scripts/daemon/context-compiler.test.mjs +300 -0
  529. package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
  530. package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
  531. package/scripts/daemon/dispatcher.mjs +1516 -0
  532. package/scripts/daemon/health.mjs +72 -0
  533. package/scripts/daemon/inbox-deferral.mjs +210 -0
  534. package/scripts/daemon/inbox-deferral.test.mjs +242 -0
  535. package/scripts/daemon/integration.test.mjs +149 -0
  536. package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
  537. package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
  538. package/scripts/daemon/launchd-wrapper.sh +91 -0
  539. package/scripts/daemon/lib/session-router.mjs +274 -0
  540. package/scripts/daemon/lib/session-router.test.mjs +295 -0
  541. package/scripts/daemon/maestro-daemon.mjs +275 -0
  542. package/scripts/daemon/prompt-builder.mjs +685 -0
  543. package/scripts/daemon/prompt-builder.test.mjs +213 -0
  544. package/scripts/daemon/responder.mjs +854 -0
  545. package/scripts/daemon/session-lock.mjs +721 -0
  546. package/scripts/daemon/session-lock.test.mjs +252 -0
  547. package/scripts/daemon/session-outcomes.mjs +640 -0
  548. package/scripts/daemon/session-outcomes.test.mjs +533 -0
  549. package/scripts/daemon/typing-registry.mjs +90 -0
  550. package/scripts/daemon/typing-registry.test.mjs +77 -0
  551. package/scripts/daemon/voice-webhook-server.mjs +804 -0
  552. package/scripts/decisions/capture-decision.mjs +116 -0
  553. package/scripts/disclosure_assessment.py +873 -0
  554. package/scripts/disclosure_boundaries.py +562 -0
  555. package/scripts/email-signature-principal.html +52 -0
  556. package/scripts/email-signature.html +60 -0
  557. package/scripts/email_quote_thread.py +167 -0
  558. package/scripts/email_thread_dedup.py +362 -0
  559. package/scripts/emergency-stop.sh +81 -0
  560. package/scripts/healthcheck.sh +116 -0
  561. package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
  562. package/scripts/hooks/block-mcp-slack-send.sh +7 -0
  563. package/scripts/hooks/post-action-log.sh +126 -0
  564. package/scripts/hooks/pre-send-audit.sh +174 -0
  565. package/scripts/hooks/pre-send-audit.test.mjs +215 -0
  566. package/scripts/hooks/session-end-log.sh +27 -0
  567. package/scripts/hooks/session-start-banner.sh +115 -0
  568. package/scripts/huddle/audio-bridge.mjs +664 -0
  569. package/scripts/huddle/boot-slack-cdp.sh +102 -0
  570. package/scripts/huddle/huddle-controller.mjs +942 -0
  571. package/scripts/huddle/huddle-server.mjs +1229 -0
  572. package/scripts/huddle/launch-slack.sh +232 -0
  573. package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
  574. package/scripts/huddle/package-lock.json +62 -0
  575. package/scripts/huddle/package.json +22 -0
  576. package/scripts/huddle/setup-audio.sh +239 -0
  577. package/scripts/huddle/start-call.mjs +318 -0
  578. package/scripts/huddle/test-pipeline.mjs +263 -0
  579. package/scripts/learning/consolidate-skills.mjs +72 -0
  580. package/scripts/learning/session-search.mjs +125 -0
  581. package/scripts/llm_email_dedup.py +442 -0
  582. package/scripts/local-triggers/generate-plists.sh +432 -0
  583. package/scripts/local-triggers/generate-plists.test.mjs +413 -0
  584. package/scripts/local-triggers/install-all.sh +49 -0
  585. package/scripts/local-triggers/plists/.gitkeep +0 -0
  586. package/scripts/local-triggers/run-trigger.sh +63 -0
  587. package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
  588. package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
  589. package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
  590. package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
  591. package/scripts/maintenance/backup-to-cloud.sh +124 -0
  592. package/scripts/maintenance/health-check.sh +377 -0
  593. package/scripts/media-generation/README.md +105 -0
  594. package/scripts/media-generation/gemini-image-client.mjs +173 -0
  595. package/scripts/media-generation/generate-assets.mjs +289 -0
  596. package/scripts/media-generation/veo-video-client.mjs +219 -0
  597. package/scripts/org/send-orgmail.mjs +227 -0
  598. package/scripts/outbound-dedup-cleanup.sh +43 -0
  599. package/scripts/outbound-dedup.sh +477 -0
  600. package/scripts/outbound_dedup.py +115 -0
  601. package/scripts/parse-voice-transcript.mjs +481 -0
  602. package/scripts/pdf-generation/README.md +63 -0
  603. package/scripts/pdf-generation/build-document.mjs +247 -0
  604. package/scripts/pdf-generation/templates/board-pack.latex +136 -0
  605. package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
  606. package/scripts/pdf-generation/templates/memo.latex +114 -0
  607. package/scripts/poll-slack-events.sh +35 -0
  608. package/scripts/poller/calendar-poller.mjs +12 -0
  609. package/scripts/poller/gmail-poller.mjs +192 -0
  610. package/scripts/poller/imap-client.mjs +289 -0
  611. package/scripts/poller/inbox-scan-poller.mjs +156 -0
  612. package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
  613. package/scripts/poller/index.mjs +73 -0
  614. package/scripts/poller/intra-session-check.mjs +285 -0
  615. package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
  616. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
  617. package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
  618. package/scripts/poller/secondary-gmail-poller.mjs +132 -0
  619. package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
  620. package/scripts/poller/slack-poller.mjs +854 -0
  621. package/scripts/poller/slack-socket-mode.mjs +917 -0
  622. package/scripts/poller/slack-socket-mode.test.mjs +753 -0
  623. package/scripts/poller/trigger.mjs +75 -0
  624. package/scripts/poller/utils.mjs +371 -0
  625. package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
  626. package/scripts/poller/voice-poller.mjs +236 -0
  627. package/scripts/poller-launchd/install.sh +66 -0
  628. package/scripts/poller-launchd/poller.plist.template +40 -0
  629. package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
  630. package/scripts/post-interaction-indexer.py +1598 -0
  631. package/scripts/pre-draft-context.py +994 -0
  632. package/scripts/pre_draft_lookup.py +258 -0
  633. package/scripts/rag/build-index.mjs +47 -0
  634. package/scripts/rag/ingest.mjs +111 -0
  635. package/scripts/rag/search.mjs +119 -0
  636. package/scripts/rag-indexer.py +629 -0
  637. package/scripts/restore-from-backup.sh +248 -0
  638. package/scripts/restore-from-backup.test.mjs +178 -0
  639. package/scripts/resume-operations.sh +80 -0
  640. package/scripts/search-secondary-inbox.py +181 -0
  641. package/scripts/secondary-inbox-poller.py +437 -0
  642. package/scripts/self-optimization/compute-metrics.py +398 -0
  643. package/scripts/send-email-as-principal.py +369 -0
  644. package/scripts/send-email-threaded.py +392 -0
  645. package/scripts/send-email-with-attachment.py +377 -0
  646. package/scripts/send-email.sh +131 -0
  647. package/scripts/send-sms.sh +175 -0
  648. package/scripts/send-whatsapp.sh +292 -0
  649. package/scripts/session-start.sh +106 -0
  650. package/scripts/setup/boot-claude-session.sh +94 -0
  651. package/scripts/setup/configure-macos.sh +674 -0
  652. package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
  653. package/scripts/setup/configure-voice-tunnel.mjs +182 -0
  654. package/scripts/setup/generate-agent-env.mjs +92 -0
  655. package/scripts/setup/generate-agent-package-json.mjs +222 -0
  656. package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
  657. package/scripts/setup/generate-autonomy.mjs +60 -0
  658. package/scripts/setup/generate-backlog.mjs +101 -0
  659. package/scripts/setup/generate-cadences.mjs +92 -0
  660. package/scripts/setup/generate-capability.mjs +162 -0
  661. package/scripts/setup/generate-charter.mjs +76 -0
  662. package/scripts/setup/generate-comms.mjs +59 -0
  663. package/scripts/setup/generate-company.mjs +92 -0
  664. package/scripts/setup/init-agent.sh +547 -0
  665. package/scripts/setup/init-agent.test.mjs +151 -0
  666. package/scripts/setup/init-archetype.mjs +74 -0
  667. package/scripts/setup/init-backup.mjs +54 -0
  668. package/scripts/setup/init-cadence-bus.mjs +60 -0
  669. package/scripts/setup/init-channel-bus.mjs +46 -0
  670. package/scripts/setup/init-cost-tracking.mjs +45 -0
  671. package/scripts/setup/init-decision-capture.mjs +66 -0
  672. package/scripts/setup/init-known-agents.mjs +57 -0
  673. package/scripts/setup/init-learning.mjs +70 -0
  674. package/scripts/setup/init-memory-executive.mjs +45 -0
  675. package/scripts/setup/init-model-router.mjs +124 -0
  676. package/scripts/setup/init-rag.mjs +174 -0
  677. package/scripts/setup/init-session-router.mjs +38 -0
  678. package/scripts/setup/init-slack-socket-mode.mjs +260 -0
  679. package/scripts/setup/init-telegram.mjs +165 -0
  680. package/scripts/setup/init-voice-realtime.mjs +204 -0
  681. package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
  682. package/scripts/setup/install-dev-tools.sh +150 -0
  683. package/scripts/setup/lib/install-plist.mjs +95 -0
  684. package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
  685. package/scripts/setup/render-environment-yaml.mjs +133 -0
  686. package/scripts/slack-events-ctl.sh +177 -0
  687. package/scripts/slack-events-server.mjs +1045 -0
  688. package/scripts/slack-react.mjs +89 -0
  689. package/scripts/slack-responded.sh +232 -0
  690. package/scripts/slack-send.sh +287 -0
  691. package/scripts/slack-typing.mjs +196 -0
  692. package/scripts/slack-upload-v2.py +95 -0
  693. package/scripts/sms-handler.mjs +450 -0
  694. package/scripts/spawn-session.sh +120 -0
  695. package/scripts/sync-protocol.mjs +217 -0
  696. package/scripts/system-verify.sh +184 -0
  697. package/scripts/test-email-thread-dedup.py +239 -0
  698. package/scripts/test-information-barriers.py +484 -0
  699. package/scripts/test-llm-email-dedup.py +251 -0
  700. package/scripts/test-pre-draft-integration.py +203 -0
  701. package/scripts/test-rag-phase2.sh +442 -0
  702. package/scripts/test-rag-search.sh +251 -0
  703. package/scripts/test-voice-parser.mjs +316 -0
  704. package/scripts/user-context-search.py +659 -0
  705. package/scripts/validate_outbound.py +1504 -0
  706. package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
  707. package/scripts/watchdog/force-reboot.sh +157 -0
  708. package/scripts/watchdog/memory-watchdog.sh +473 -0
  709. package/scripts/whatsapp-handler.mjs +538 -0
  710. package/teams/desktop-operations.yaml +34 -0
  711. package/teams/executive-office.yaml +27 -0
  712. package/teams/legal-and-regulatory.yaml +24 -0
  713. package/teams/platform-and-engineering.yaml +23 -0
  714. package/teams/strategy-and-growth.yaml +29 -0
  715. package/workflows/continuous/backlog-executor.yaml +141 -0
  716. package/workflows/continuous/inbound-monitor.yaml +168 -0
  717. package/workflows/daily/applicant-triage.yaml +197 -0
  718. package/workflows/daily/comms-triage.yaml +80 -0
  719. package/workflows/daily/evening-wrap.yaml +105 -0
  720. package/workflows/daily/morning-brief.yaml +164 -0
  721. package/workflows/daily/slack-followup-sweep.yaml +87 -0
  722. package/workflows/event-driven/README.md +50 -0
  723. package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
  724. package/workflows/event-driven/pr-review.yaml +107 -0
  725. package/workflows/monthly/board-readiness.yaml +76 -0
  726. package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
  727. package/workflows/session-protocol.md +171 -0
  728. package/workflows/weekly/engineering-health.yaml +154 -0
  729. package/workflows/weekly/hiring-review.yaml +169 -0
  730. package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
  731. package/workflows/weekly/strategic-memo.yaml +79 -0
@@ -0,0 +1,124 @@
1
+ You are {{agent.fullName}}, {{agent.title}} to {{agent.principal.fullName}}, {{agent.principal.title}} of {{agent.company}}.
2
+
3
+ ## Workflow: Weekly Strategic Memo
4
+
5
+ ## Cadence: Friday 14:00 GST
6
+
7
+ ## Working Directory: the agent repo root (your current working directory)
8
+
9
+ ### Instructions
10
+
11
+ 1. Read `state/dashboards/executive-summary.yaml`
12
+ 2. Read `config/priorities.yaml`
13
+ 3. Read `knowledge/syntheses/strategic-synthesis.yaml`
14
+ 4. Review this week's interactions from `memory/interactions/` — key themes and signals
15
+ 5. Review this week's decisions from `knowledge/decisions/`
16
+ 6. Check `state/queues/narrative-opportunities.yaml` for content opportunities
17
+
18
+ 7. **Strategic coherence check:**
19
+ - Read `config/priorities.yaml` for the 5 strategic priorities
20
+ - Scan all queue items across all 15 queues in `state/queues/` — map each to a priority using context
21
+ - Flag and include in the memo:
22
+ - Priorities with zero active queue items (stalled — nobody working on it)
23
+ - Queue items not mappable to any priority (unlinked work — effort without strategic purpose)
24
+ - Priorities where all items are blocked (stuck — needs intervention)
25
+ - Any apparent conflicts between initiatives
26
+
27
+ 8. **Cadence quality audit:**
28
+ - Read `memory/interactions/meetings/` for all meetings this week
29
+ - For each meeting, check:
30
+ - Were actions captured? (meeting record exists with non-empty actions list)
31
+ - Were actions assigned owners and deadlines?
32
+ - Were previous meeting's actions closed?
33
+ - Calculate and include in memo:
34
+ - Meetings this week: total count
35
+ - Action capture rate: % of meetings with captured actions
36
+ - Action closure rate: % of last week's meeting actions now closed
37
+ - Flag: meetings with consistently zero outputs (suggest cancellation)
38
+ - Flag: meetings where actions captured but never closed (accountability gap)
39
+
40
+ 9. **Update living strategy state:**
41
+ - Read `knowledge/syntheses/strategy-state.yaml`
42
+ - Update based on this week's developments:
43
+ - Refresh `strategic_position` if anything material changed
44
+ - Update `key_assumptions` status based on new evidence
45
+ - Add any `emerging_signals` observed this week
46
+ - Update `strategic_risks` severity/likelihood based on new information
47
+ - Add this week's decisions to `recent_decisions`
48
+ - Refresh `next_quarter_focus` if priorities shifted
49
+ - Write updated file back
50
+
51
+ 10. **Leadership effectiveness scorecard:**
52
+ - Read `state/dashboards/leadership-accountability.yaml`
53
+ - For each leader: summarise commitments met/missed, response quality, trend
54
+ - Flag patterns: consistently missing deadlines, going silent, declining accountability
55
+ - Include {{agent.firstName}}'s candid assessment and specific recommendations
56
+ - NOTE: This section is sensitive — send via DM to {{agent.principal.firstName}}, not in any channel
57
+
58
+ 11. **Relationship pipeline update:**
59
+ - Read `state/dashboards/relationship-pipeline.yaml`
60
+ - Review `memory/interactions/` for all external interactions this week
61
+ - Update relationship stages and warmth based on interaction recency
62
+ - Flag cooling relationships (no interaction >2 weeks for active relationships)
63
+ - Flag overdue next-actions on relationships
64
+ - Write updated pipeline to `state/dashboards/relationship-pipeline.yaml`
65
+
66
+ 12. **Commercial position assessment:**
67
+ - Read market signals from `memory/precedents/market-signals/`
68
+ - Assess: ICP clarity, pipeline warmth, partner engagement, competitive positioning
69
+ - Synthesise into "Commercial Position" section in the memo
70
+
71
+ 13. **Founder dependency flag:**
72
+ - Read `state/dashboards/org-health.yaml` founder_dependency section
73
+ - If threshold_breached (>60%), include prominent flag in memo with delegation recommendations
74
+
75
+ 14. **Advisor utilisation review:**
76
+ - Read `state/dashboards/relationship-pipeline.yaml` advisors section
77
+ - For each advisor: when was last interaction? Was value extracted?
78
+ - Flag advisors not contacted in >30 days
79
+ - Recommend specific re-engagement actions for underutilised advisors
80
+
81
+ 15. **Risk register review:**
82
+ - Read `state/dashboards/risk-register.yaml`
83
+ - For each risk: is the review date approaching or past?
84
+ - Have any risk conditions changed based on this week's developments?
85
+ - Update risk severity/likelihood if warranted
86
+ - Flag any new risks identified this week
87
+ - Write updated risk register back
88
+
89
+ 16. **Capital position update:**
90
+ - Read `state/dashboards/capital-readiness.yaml`
91
+ - Update fundraising readiness components based on this week's progress
92
+ - Update investor and corp dev pipeline counts
93
+ - Note any approaching capital-related milestones
94
+ - Write updated dashboard back
95
+
96
+ 17. Synthesise a weekly strategic memo covering:
97
+ - Week in review: key accomplishments and setbacks
98
+ - Strategic position: how did we advance this week?
99
+ - Strategy scorecard: per-priority status from `state/dashboards/strategy-scorecard.yaml`
100
+ - **Coherence check findings** (stalled priorities, unlinked work, conflicts)
101
+ - Emerging signals: what changed in the environment?
102
+ - **Cadence health** (meeting → action capture rate, closure rate, flagged meetings)
103
+ - **Leadership effectiveness scorecard** ({{agent.principal.firstName}} DM only)
104
+ - **Engineering health** from `state/dashboards/engineering-health.yaml`
105
+ - **Relationship pipeline health** (warming/cooling/overdue)
106
+ - **Commercial position** (ICP, pipeline, competitive)
107
+ - **Founder dependency alert** (if >60%)
108
+ - **Advisor utilisation** (who's engaged, who's dormant, re-engagement recs)
109
+ - **Risk register update** (new risks, changed severity, overdue reviews)
110
+ - **Capital position** (runway, readiness score, pipeline, approaching milestones)
111
+ - Next week preview: what matters most?
112
+ - Recommendations: 2-3 things {{agent.firstName}} recommends the {{agent.principal.title}} focus on
113
+ 18. Write memo to `outputs/memos/{date}-strategic-memo.md`
114
+ 19. Send to {{agent.principal.firstName}} via Slack or email (executive-quality document)
115
+ 20. Update `knowledge/syntheses/strategic-synthesis.yaml` with any new insights
116
+ 21. Prepare week-ahead items: update Monday's priorities queue
117
+ 22. Log to `logs/workflows/{date}-weekly-strategic-memo.jsonl`
118
+
119
+ ### Operating Rules
120
+
121
+ - This is the most important written output of the week — quality matters
122
+ - Be analytical and forward-looking, not just retrospective
123
+ - Include {{agent.firstName}}'s own strategic observations and recommendations
124
+ - If using PDF generation, use: `npm run pdf:memo -- --input outputs/memos/{date}-strategic-memo.md`
@@ -0,0 +1,55 @@
1
+ #!/bin/bash
2
+ # archive-email.sh — Archive non-actionable Gmail messages via IMAP
3
+ # Usage: ./scripts/archive-email.sh
4
+ # Requires GMAIL_APP_PASSWORD environment variable
5
+ set -e
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ AGENT_REPO_DIR="${AGENT_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
9
+
10
+ # Pull AGENT_EMAIL + GMAIL_APP_PASSWORD from agent.env + .env
11
+ [ -f "$AGENT_REPO_DIR/config/agent.env" ] && source "$AGENT_REPO_DIR/config/agent.env"
12
+ [ -f "$AGENT_REPO_DIR/.env" ] && source "$AGENT_REPO_DIR/.env"
13
+
14
+ if [ -z "${GMAIL_APP_PASSWORD:-}" ]; then
15
+ echo "ERROR: GMAIL_APP_PASSWORD not set" >&2
16
+ exit 1
17
+ fi
18
+ export AGENT_EMAIL
19
+ export GMAIL_APP_PASSWORD
20
+
21
+ python3 << 'PYEOF'
22
+ import imaplib
23
+ import os
24
+
25
+ user = os.environ.get("AGENT_EMAIL", "")
26
+ password = os.environ["GMAIL_APP_PASSWORD"]
27
+ if not user:
28
+ raise SystemExit("AGENT_EMAIL not set — check config/agent.env")
29
+
30
+ mail = imaplib.IMAP4_SSL("imap.gmail.com")
31
+ mail.login(user, password)
32
+ mail.select("INBOX")
33
+
34
+ # Non-actionable sender domains to auto-archive
35
+ junk_domains = [
36
+ "greptile.com", "gamma.app", "linear.app", "netlify.com",
37
+ "consensus.app", "zapier.com", "calendly.com", "jam.dev",
38
+ "send.zapier.com", "mail.consensus.app", "send.calendly.com",
39
+ "noreply@netlify.com", "hello@greptile.com", "hello@gamma.app",
40
+ ]
41
+
42
+ archived = 0
43
+ for domain in junk_domains:
44
+ status, messages = mail.search(None, f'(UNSEEN FROM "{domain}")')
45
+ if status == "OK" and messages[0]:
46
+ for num in messages[0].split():
47
+ mail.store(num, '+FLAGS', '\\Seen')
48
+ mail.copy(num, '"[Gmail]/All Mail"')
49
+ mail.store(num, '+FLAGS', '\\Deleted')
50
+ archived += 1
51
+
52
+ mail.expunge()
53
+ mail.logout()
54
+ print(f"Archived {archived} non-actionable emails")
55
+ PYEOF
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cadence-status.mjs — Print the current cadence-bus depth + heartbeat.
4
+ *
5
+ * Used by `npm run cadence:status` and by `maestro doctor` for a quick
6
+ * snapshot. Reads files only; never mutates state.
7
+ *
8
+ * Output (JSON):
9
+ * {
10
+ * "depth": { "inbox": N, "claimed": N, "dlq": N, "failed": N },
11
+ * "health": { ... } | null,
12
+ * "heartbeat_age_ms": N | null
13
+ * }
14
+ *
15
+ * Exit code is always 0 — health interpretation is the caller's job.
16
+ */
17
+
18
+ import { resolve, dirname } from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+
21
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
+ const { busDepth, readHealth, getBusPaths } = await import(
23
+ resolve(__dirname, "..", "..", "lib", "cadence-bus.mjs")
24
+ );
25
+
26
+ const paths = getBusPaths();
27
+ const depth = busDepth();
28
+ const health = readHealth();
29
+ const heartbeatAgeMs = health?.ts ? Date.now() - new Date(health.ts).getTime() : null;
30
+
31
+ process.stdout.write(JSON.stringify({
32
+ agent_root: paths.agentRoot,
33
+ depth,
34
+ health,
35
+ heartbeat_age_ms: heartbeatAgeMs,
36
+ }, null, 2) + "\n");
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Maestro — enqueue-cadence-tick.mjs
4
+ *
5
+ * Lightweight cadence-bus enqueue CLI. Designed to be invoked from launchd
6
+ * plists (or manual scripting) in place of `claude --print` per tick. The
7
+ * heavy lifting — running the cadence, deciding whether to spawn a sub-
8
+ * session, etc. — is owned by the persistent Maestro daemon, which consumes
9
+ * events from the bus.
10
+ *
11
+ * Design constraints:
12
+ * • Must finish in well under a second so launchd never piles up.
13
+ * • Must never spawn Claude Code itself.
14
+ * • Must be safe to call when the daemon is down (event still lands on
15
+ * disk and is processed on next consumer startup).
16
+ * • Must honour .emergency-stop (no event lands in inbox/; suppressed
17
+ * event is still recorded in queue.jsonl for audit).
18
+ *
19
+ * Usage:
20
+ * node scripts/cadence/enqueue-cadence-tick.mjs <cadence-name> [options]
21
+ *
22
+ * Options:
23
+ * --source=<label> launchd | manual | daemon | init-maestro | upgrade (default: manual)
24
+ * --workflow=<path> e.g. continuous/inbox-processor
25
+ * --priority=<high|normal|low>
26
+ * --correlation-id=<id>
27
+ * --interval=<seconds> Cadence interval in seconds (WS4). When present,
28
+ * the bus enforces at-most-once delivery per
29
+ * interval (grace window + stale fast-forward after
30
+ * an outage). Passed by generate-plists.sh from the
31
+ * plist's StartInterval/StartCalendarInterval. Absent
32
+ * → legacy behaviour (every fire enqueues).
33
+ * --metadata=<key=value> May be repeated. Comma-separated pairs also accepted.
34
+ * --quiet Suppress stdout JSON line.
35
+ * --help Show this help.
36
+ *
37
+ * Exit codes:
38
+ * 0 — enqueued (or suppressed by emergency-stop, which is still success)
39
+ * 2 — invalid usage / missing required arg
40
+ * 3 — internal failure (disk full, permissions, etc.) — caller should retry
41
+ *
42
+ * Examples:
43
+ * # Launchd plist invokes this every 10 minutes:
44
+ * node scripts/cadence/enqueue-cadence-tick.mjs backlog-executor --source=launchd
45
+ *
46
+ * # Manual smoke-test:
47
+ * node scripts/cadence/enqueue-cadence-tick.mjs inbox-processor --source=manual --metadata=note=smoke
48
+ */
49
+
50
+ import { resolve, dirname } from "node:path";
51
+ import { fileURLToPath } from "node:url";
52
+
53
+ const __dirname = dirname(fileURLToPath(import.meta.url));
54
+
55
+ // Resolve cadence-bus relative to this script so the same enqueue works
56
+ // whether invoked from the framework repo (~/maestro/scripts/cadence/...)
57
+ // or from a generated agent repo (~/<agent>/scripts/cadence/...).
58
+ const { enqueueTick, BUS_VERSION } = await import(
59
+ resolve(__dirname, "..", "..", "lib", "cadence-bus.mjs")
60
+ );
61
+
62
+ function printHelp() {
63
+ process.stdout.write(`enqueue-cadence-tick — Maestro cadence bus producer
64
+
65
+ Usage:
66
+ node scripts/cadence/enqueue-cadence-tick.mjs <cadence-name> [options]
67
+
68
+ Options:
69
+ --source=<label> launchd | manual | daemon | init-maestro | upgrade
70
+ --workflow=<path> e.g. continuous/inbox-processor
71
+ --priority=<high|normal|low>
72
+ --correlation-id=<id>
73
+ --metadata=<key=value> repeatable, or comma-separated pairs
74
+ --quiet suppress JSON output to stdout
75
+ --version print bus version and exit
76
+ --help, -h show this help
77
+
78
+ Exits 0 on success (including emergency-stop suppression).
79
+ `);
80
+ }
81
+
82
+ function parseMetadata(raw) {
83
+ // Accept --metadata=key=value, repeated, or --metadata=k1=v1,k2=v2.
84
+ const out = {};
85
+ for (const item of raw) {
86
+ if (!item) continue;
87
+ for (const pair of String(item).split(",")) {
88
+ const idx = pair.indexOf("=");
89
+ if (idx === -1) continue;
90
+ const k = pair.slice(0, idx).trim();
91
+ const v = pair.slice(idx + 1).trim();
92
+ if (k) out[k] = v;
93
+ }
94
+ }
95
+ return out;
96
+ }
97
+
98
+ function parseArgs(argv) {
99
+ const args = { cadence: null, source: "manual", metadata: [], quiet: false };
100
+ for (const arg of argv) {
101
+ if (arg === "--help" || arg === "-h") return { help: true };
102
+ if (arg === "--version") return { version: true };
103
+ if (arg === "--quiet") { args.quiet = true; continue; }
104
+ if (arg.startsWith("--source=")) { args.source = arg.slice("--source=".length); continue; }
105
+ if (arg.startsWith("--workflow=")) { args.workflow = arg.slice("--workflow=".length); continue; }
106
+ if (arg.startsWith("--priority=")) { args.priority = arg.slice("--priority=".length); continue; }
107
+ if (arg.startsWith("--correlation-id=")) { args.correlation_id = arg.slice("--correlation-id=".length); continue; }
108
+ if (arg.startsWith("--interval=")) { args.interval = arg.slice("--interval=".length); continue; }
109
+ if (arg.startsWith("--metadata=")) { args.metadata.push(arg.slice("--metadata=".length)); continue; }
110
+ if (arg.startsWith("--")) {
111
+ process.stderr.write(`enqueue-cadence-tick: unknown flag: ${arg}\n`);
112
+ return { invalid: true };
113
+ }
114
+ if (!args.cadence) { args.cadence = arg; continue; }
115
+ process.stderr.write(`enqueue-cadence-tick: unexpected positional arg: ${arg}\n`);
116
+ return { invalid: true };
117
+ }
118
+ return args;
119
+ }
120
+
121
+ const argv = process.argv.slice(2);
122
+ const parsed = parseArgs(argv);
123
+
124
+ if (parsed.help) {
125
+ printHelp();
126
+ process.exit(0);
127
+ }
128
+ if (parsed.version) {
129
+ process.stdout.write(`${BUS_VERSION}\n`);
130
+ process.exit(0);
131
+ }
132
+ if (parsed.invalid) {
133
+ printHelp();
134
+ process.exit(2);
135
+ }
136
+ if (!parsed.cadence) {
137
+ process.stderr.write("enqueue-cadence-tick: <cadence-name> required\n");
138
+ printHelp();
139
+ process.exit(2);
140
+ }
141
+
142
+ // Convert --interval=<seconds> to milliseconds for the bus. Non-numeric or
143
+ // non-positive values are ignored (falls back to legacy every-fire behaviour).
144
+ let intervalMs;
145
+ if (parsed.interval !== undefined) {
146
+ const secs = Number(parsed.interval);
147
+ if (Number.isFinite(secs) && secs > 0) intervalMs = Math.round(secs * 1000);
148
+ }
149
+
150
+ try {
151
+ const result = enqueueTick({
152
+ cadence: parsed.cadence,
153
+ source: parsed.source,
154
+ workflow: parsed.workflow,
155
+ priority: parsed.priority,
156
+ correlation_id: parsed.correlation_id,
157
+ intervalMs,
158
+ metadata: parseMetadata(parsed.metadata),
159
+ });
160
+ if (!parsed.quiet) {
161
+ process.stdout.write(JSON.stringify({
162
+ ok: true,
163
+ id: result.id,
164
+ cadence: parsed.cadence,
165
+ path: result.path,
166
+ fallback_only: result.fallbackOnly,
167
+ skipped: result.skipped || null,
168
+ }) + "\n");
169
+ }
170
+ process.exit(0);
171
+ } catch (err) {
172
+ process.stderr.write(`enqueue-cadence-tick: ${err.message}\n`);
173
+ process.exit(3);
174
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * enqueue-cadence-tick.test.mjs — node:test coverage for the CLI enqueue
3
+ * script (the entry point used by launchd plists).
4
+ */
5
+
6
+ import { test } from "node:test";
7
+ import assert from "node:assert/strict";
8
+ import { promises as fsp } from "fs";
9
+ import { writeFileSync, readFileSync, existsSync } from "node:fs";
10
+ import { tmpdir } from "os";
11
+ import { join, resolve, dirname } from "path";
12
+ import { fileURLToPath } from "node:url";
13
+ import { spawnSync } from "node:child_process";
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const ENQUEUE_SCRIPT = resolve(__dirname, "enqueue-cadence-tick.mjs");
17
+
18
+ async function makeAgentRoot() {
19
+ const path = join(
20
+ tmpdir(),
21
+ `enqueue-cli-test-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
22
+ );
23
+ await fsp.mkdir(path, { recursive: true });
24
+ return path;
25
+ }
26
+
27
+ async function rmRoot(path) {
28
+ try { await fsp.rm(path, { recursive: true, force: true }); } catch { /* */ }
29
+ }
30
+
31
+ function run(cwd, args, env = {}) {
32
+ return spawnSync(process.execPath, [ENQUEUE_SCRIPT, ...args], {
33
+ cwd,
34
+ env: { ...process.env, AGENT_ROOT: cwd, ...env },
35
+ encoding: "utf-8",
36
+ });
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Happy path
41
+ // ---------------------------------------------------------------------------
42
+
43
+ test("CLI enqueues a tick and writes inbox JSON", async () => {
44
+ const root = await makeAgentRoot();
45
+ try {
46
+ const r = run(root, ["inbox-processor", "--source=launchd"]);
47
+ assert.equal(r.status, 0, r.stderr);
48
+ const out = JSON.parse(r.stdout.trim());
49
+ assert.equal(out.ok, true);
50
+ assert.equal(out.cadence, "inbox-processor");
51
+ assert.equal(out.fallback_only, false);
52
+ assert.ok(out.path);
53
+ assert.ok(existsSync(out.path));
54
+ const event = JSON.parse(readFileSync(out.path, "utf-8"));
55
+ assert.equal(event.source, "launchd");
56
+ assert.equal(event.cadence, "inbox-processor");
57
+ } finally { await rmRoot(root); }
58
+ });
59
+
60
+ test("CLI accepts metadata pairs (repeated and comma-separated)", async () => {
61
+ const root = await makeAgentRoot();
62
+ try {
63
+ const r = run(root, [
64
+ "weekly-strategic-memo",
65
+ "--source=manual",
66
+ "--metadata=note=launch",
67
+ "--metadata=k1=v1,k2=v2",
68
+ ]);
69
+ assert.equal(r.status, 0);
70
+ const out = JSON.parse(r.stdout.trim());
71
+ const event = JSON.parse(readFileSync(out.path, "utf-8"));
72
+ assert.equal(event.metadata.note, "launch");
73
+ assert.equal(event.metadata.k1, "v1");
74
+ assert.equal(event.metadata.k2, "v2");
75
+ } finally { await rmRoot(root); }
76
+ });
77
+
78
+ test("CLI --interval enables the at-most-once gate (duplicate fire suppressed)", async () => {
79
+ const root = await makeAgentRoot();
80
+ try {
81
+ // First fire admits.
82
+ const r1 = run(root, ["inbox-processor", "--source=launchd", "--interval=300"]);
83
+ assert.equal(r1.status, 0, r1.stderr);
84
+ const out1 = JSON.parse(r1.stdout.trim());
85
+ assert.ok(out1.path, "first interval-bearing tick admits");
86
+ // Immediate second fire (well within the grace window) is suppressed.
87
+ const r2 = run(root, ["inbox-processor", "--source=launchd", "--interval=300"]);
88
+ assert.equal(r2.status, 0, r2.stderr);
89
+ const out2 = JSON.parse(r2.stdout.trim());
90
+ assert.equal(out2.path, null);
91
+ assert.equal(out2.skipped, "before-grace-window");
92
+ // schedule.json was created.
93
+ assert.ok(existsSync(join(root, "state/cadence-bus/schedule.json")));
94
+ } finally { await rmRoot(root); }
95
+ });
96
+
97
+ test("CLI --interval=0 / non-numeric falls back to legacy every-fire behaviour", async () => {
98
+ const root = await makeAgentRoot();
99
+ try {
100
+ const a = run(root, ["inbox-processor", "--source=launchd", "--interval=0"]);
101
+ const b = run(root, ["inbox-processor", "--source=launchd", "--interval=oops"]);
102
+ assert.equal(a.status, 0);
103
+ assert.equal(b.status, 0);
104
+ assert.ok(JSON.parse(a.stdout.trim()).path);
105
+ assert.ok(JSON.parse(b.stdout.trim()).path);
106
+ // No schedule.json created when the gate is inactive.
107
+ assert.equal(existsSync(join(root, "state/cadence-bus/schedule.json")), false);
108
+ } finally { await rmRoot(root); }
109
+ });
110
+
111
+ test("CLI --quiet suppresses stdout JSON", async () => {
112
+ const root = await makeAgentRoot();
113
+ try {
114
+ const r = run(root, ["inbox-processor", "--source=launchd", "--quiet"]);
115
+ assert.equal(r.status, 0);
116
+ assert.equal(r.stdout.trim(), "");
117
+ } finally { await rmRoot(root); }
118
+ });
119
+
120
+ test("CLI --version prints bus schema version", async () => {
121
+ const r = spawnSync(process.execPath, [ENQUEUE_SCRIPT, "--version"], { encoding: "utf-8" });
122
+ assert.equal(r.status, 0);
123
+ assert.match(r.stdout, /^\d+$/m);
124
+ });
125
+
126
+ test("CLI --help prints usage and exits 0", async () => {
127
+ const r = spawnSync(process.execPath, [ENQUEUE_SCRIPT, "--help"], { encoding: "utf-8" });
128
+ assert.equal(r.status, 0);
129
+ assert.match(r.stdout, /enqueue-cadence-tick/);
130
+ });
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // Error paths
134
+ // ---------------------------------------------------------------------------
135
+
136
+ test("CLI exits 2 with no cadence", async () => {
137
+ const root = await makeAgentRoot();
138
+ try {
139
+ const r = run(root, []);
140
+ assert.equal(r.status, 2);
141
+ assert.match(r.stderr, /required/);
142
+ } finally { await rmRoot(root); }
143
+ });
144
+
145
+ test("CLI exits 2 on unknown flag", async () => {
146
+ const root = await makeAgentRoot();
147
+ try {
148
+ const r = run(root, ["x", "--what-is-this"]);
149
+ assert.equal(r.status, 2);
150
+ assert.match(r.stderr, /unknown flag/);
151
+ } finally { await rmRoot(root); }
152
+ });
153
+
154
+ // ---------------------------------------------------------------------------
155
+ // Emergency stop
156
+ // ---------------------------------------------------------------------------
157
+
158
+ test("CLI returns 0 with skipped=emergency-stop when stop flag exists", async () => {
159
+ const root = await makeAgentRoot();
160
+ try {
161
+ writeFileSync(join(root, ".emergency-stop"), "now");
162
+ const r = run(root, ["weekly-strategic-memo", "--source=launchd"]);
163
+ assert.equal(r.status, 0);
164
+ const out = JSON.parse(r.stdout.trim());
165
+ assert.equal(out.skipped, "emergency-stop");
166
+ assert.equal(out.fallback_only, true);
167
+ assert.equal(out.path, null);
168
+ // No file landed in inbox/.
169
+ assert.ok(!existsSync(join(root, "state/cadence-bus/inbox", `${out.id}.json`)));
170
+ } finally { await rmRoot(root); }
171
+ });
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Bus-handoff sanity — the CLI must finish in well under a second so launchd
175
+ // never piles up; we don't pin a number, just a generous ceiling.
176
+ // ---------------------------------------------------------------------------
177
+
178
+ test("CLI completes in well under 2 seconds", async () => {
179
+ const root = await makeAgentRoot();
180
+ try {
181
+ const t0 = Date.now();
182
+ const r = run(root, ["inbox-processor", "--source=launchd", "--quiet"]);
183
+ const dt = Date.now() - t0;
184
+ assert.equal(r.status, 0);
185
+ assert.ok(dt < 2000, `enqueue took ${dt}ms`);
186
+ } finally { await rmRoot(root); }
187
+ });
@@ -0,0 +1,85 @@
1
+ #!/bin/bash
2
+ # launchd-cadence-wrapper.sh — Bootstraps env and execs the Node cadence
3
+ # enqueue script under launchd.
4
+ #
5
+ # Usage in a plist:
6
+ # <key>ProgramArguments</key>
7
+ # <array>
8
+ # <string>/path/to/scripts/cadence/launchd-cadence-wrapper.sh</string>
9
+ # <string>/path/to/scripts/cadence/enqueue-cadence-tick.mjs</string>
10
+ # <string>cadence-name</string>
11
+ # <string>--source=launchd</string>
12
+ # </array>
13
+ #
14
+ # What it does:
15
+ # 1. Sets HOME, PATH, USER, AGENT_ROOT (launchd's bare env doesn't include them).
16
+ # 2. Picks a node binary (nvm, homebrew, system fallback).
17
+ # 3. Redirects stdout/stderr to logs/cadence-bus/launchd-YYYY-MM-DD.log.
18
+ # 4. Exec's `node <enqueue-script> "$@"`.
19
+ #
20
+ # This is a *pure enqueue* wrapper — it must NOT spawn Claude Code. The
21
+ # heavyweight cadence work happens inside the persistent daemon's cadence
22
+ # consumer, not here.
23
+
24
+ set -e
25
+
26
+ if [ $# -lt 1 ]; then
27
+ echo "[cadence-wrapper] FATAL: enqueue script path required" >&2
28
+ exit 64
29
+ fi
30
+
31
+ ENQUEUE_SCRIPT="$1"
32
+ shift
33
+
34
+ # Walk up from the enqueue script to find the agent root. AGENT_ROOT is the
35
+ # nearest ancestor with both package.json and config/.
36
+ TARGET_DIR="$(cd "$(dirname "$ENQUEUE_SCRIPT")" && pwd -P)"
37
+ CANDIDATE="$TARGET_DIR"
38
+ AGENT_ROOT=""
39
+ while [ "$CANDIDATE" != "/" ]; do
40
+ if [ -f "$CANDIDATE/package.json" ] && [ -d "$CANDIDATE/config" ]; then
41
+ AGENT_ROOT="$CANDIDATE"
42
+ break
43
+ fi
44
+ CANDIDATE="$(dirname "$CANDIDATE")"
45
+ done
46
+ AGENT_ROOT="${AGENT_ROOT:-$TARGET_DIR}"
47
+
48
+ export AGENT_ROOT
49
+ export AGENT_DIR="$AGENT_ROOT"
50
+ export HOME="${HOME:-/Users/$(whoami)}"
51
+ export USER="${USER:-$(whoami)}"
52
+ export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
53
+
54
+ cd "$AGENT_ROOT"
55
+
56
+ # Resolve node binary — prefer nvm, fall back to homebrew, then system.
57
+ NODE_BIN=""
58
+ for candidate in \
59
+ "$HOME/.nvm/versions/node/v24.11.1/bin/node" \
60
+ "$HOME/.nvm/versions/node/v24/bin/node" \
61
+ "$HOME/.nvm/versions/node/v22/bin/node" \
62
+ "$HOME/.nvm/versions/node/v20/bin/node" \
63
+ /opt/homebrew/bin/node \
64
+ /usr/local/bin/node \
65
+ /usr/bin/node; do
66
+ if [ -x "$candidate" ]; then
67
+ NODE_BIN="$candidate"
68
+ break
69
+ fi
70
+ done
71
+ if [ -z "$NODE_BIN" ] && [ -d "$HOME/.nvm/versions/node" ]; then
72
+ NODE_BIN=$(ls -1d "$HOME/.nvm/versions/node"/v*/bin/node 2>/dev/null | sort -V | tail -1)
73
+ fi
74
+ if [ -z "$NODE_BIN" ] || [ ! -x "$NODE_BIN" ]; then
75
+ echo "[cadence-wrapper] FATAL: could not find node binary" >&2
76
+ exit 127
77
+ fi
78
+
79
+ LOG_DATE="$(date +%Y-%m-%d)"
80
+ LOG_DIR="$AGENT_ROOT/logs/cadence-bus"
81
+ mkdir -p "$LOG_DIR" 2>/dev/null || true
82
+ LOG_FILE="$LOG_DIR/launchd-${LOG_DATE}.log"
83
+
84
+ # Exec the enqueue script. stdin is closed; stdout/stderr go to the log.
85
+ exec "$NODE_BIN" "$ENQUEUE_SCRIPT" "$@" >> "$LOG_FILE" 2>&1