@polderlabs/bizar 6.2.4 → 6.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 (332) hide show
  1. package/.claude/CLAUDE.md +15 -0
  2. package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
  3. package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
  4. package/.claude/agents/_shared/SKILLS.md +109 -0
  5. package/.claude/agents/agent-browser.md +80 -0
  6. package/.claude/agents/baldr.md +49 -0
  7. package/.claude/agents/forseti.md +51 -0
  8. package/.claude/agents/frigg.md +42 -0
  9. package/.claude/agents/heimdall.md +33 -0
  10. package/.claude/agents/hermod.md +53 -0
  11. package/.claude/agents/mimir.md +49 -0
  12. package/.claude/agents/odin.md +287 -0
  13. package/.claude/agents/quick.md +34 -0
  14. package/.claude/agents/semble-search.md +50 -0
  15. package/.claude/agents/thor.md +53 -0
  16. package/.claude/agents/tyr.md +56 -0
  17. package/.claude/agents/vidarr.md +54 -0
  18. package/.claude/agents/vor.md +53 -0
  19. package/.claude/commands/audit.md +25 -0
  20. package/.claude/commands/bizar.md +22 -0
  21. package/.claude/commands/explain.md +17 -0
  22. package/.claude/commands/init.md +29 -0
  23. package/.claude/commands/learn.md +44 -0
  24. package/.claude/commands/plan.md +35 -0
  25. package/.claude/commands/plow-through.md +50 -0
  26. package/.claude/commands/pr-review.md +49 -0
  27. package/.claude/commands/setup-provider.md +96 -0
  28. package/.claude/commands/tailscale-serve.md +100 -0
  29. package/.claude/commands/team.md +132 -0
  30. package/.claude/commands/test.md +62 -0
  31. package/.claude/commands/validate.md +68 -0
  32. package/.claude/commands/visual-plan.md +24 -0
  33. package/.claude/hooks/README.md +92 -0
  34. package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
  35. package/.claude/hooks/pretooluse-bash.mjs +81 -0
  36. package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
  37. package/.claude/hooks/sessionend-recall.mjs +74 -0
  38. package/.claude/hooks/sessionstart-prime.mjs +80 -0
  39. package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
  40. package/.claude/settings.json +116 -0
  41. package/.claude/skills/9router/SKILL.md +80 -0
  42. package/.claude/skills/9router-chat/SKILL.md +73 -0
  43. package/.claude/skills/9router-embeddings/SKILL.md +69 -0
  44. package/.claude/skills/9router-image/SKILL.md +86 -0
  45. package/.claude/skills/9router-stt/SKILL.md +79 -0
  46. package/.claude/skills/9router-tts/SKILL.md +80 -0
  47. package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
  48. package/.claude/skills/9router-web-search/SKILL.md +91 -0
  49. package/.claude/skills/bizar/README.md +9 -0
  50. package/.claude/skills/bizar/SKILL.md +450 -0
  51. package/.claude/skills/cpp-coding-standards/README.md +28 -0
  52. package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
  53. package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
  54. package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
  55. package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
  56. package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
  57. package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
  58. package/.claude/skills/cpp-testing/README.md +28 -0
  59. package/.claude/skills/cpp-testing/SKILL.md +304 -0
  60. package/.claude/skills/cpp-testing/references/coverage.md +370 -0
  61. package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
  62. package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
  63. package/.claude/skills/cpp-testing/references/mocking.md +364 -0
  64. package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
  65. package/.claude/skills/cubesandbox/SKILL.md +148 -0
  66. package/.claude/skills/embedded-esp-idf/README.md +41 -0
  67. package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
  68. package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
  69. package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
  70. package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
  71. package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
  72. package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
  73. package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
  74. package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
  75. package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
  76. package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
  77. package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
  78. package/.claude/skills/glyph/SKILL.md +163 -0
  79. package/.claude/skills/harness-engineering/SKILL.md +143 -0
  80. package/.claude/skills/lightrag/SKILL.md +81 -0
  81. package/.claude/skills/memory-protocol/SKILL.md +105 -0
  82. package/.claude/skills/obsidian/SKILL.md +306 -0
  83. package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
  84. package/.claude/skills/self-improvement/SKILL.md +64 -0
  85. package/README.md +87 -59
  86. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-B58aiJiE.js} +1 -1
  87. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-B58aiJiE.js.map} +1 -1
  88. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js → MobileChat-BJrqwVDd.js} +1 -1
  89. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-BJrqwVDd.js.map} +1 -1
  90. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js → MobileSettings-CEQNJNLJ.js} +1 -1
  91. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-CEQNJNLJ.js.map} +1 -1
  92. package/bizar-dash/dist/assets/{main-DYiZqMrn.js → main-IvfQAOfy.js} +1 -1
  93. package/bizar-dash/dist/assets/{main-DYiZqMrn.js.map → main-IvfQAOfy.js.map} +1 -1
  94. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js → markdown-tOLaD6nm.js} +1 -1
  95. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-tOLaD6nm.js.map} +1 -1
  96. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js → mobile-DYCHcUpq.js} +1 -1
  97. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DYCHcUpq.js.map} +1 -1
  98. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js → mobile-layout-CBHjpwsb.js} +2 -2
  99. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js.map → mobile-layout-CBHjpwsb.js.map} +1 -1
  100. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js → useSlashCommands-Bd7_FA6U.js} +2 -2
  101. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js.map → useSlashCommands-Bd7_FA6U.js.map} +1 -1
  102. package/bizar-dash/dist/assets/{vendor-CeHGtduv.js → vendor-C843201K.js} +12 -12
  103. package/bizar-dash/dist/assets/vendor-C843201K.js.map +1 -0
  104. package/bizar-dash/dist/index.html +6 -6
  105. package/bizar-dash/dist/mobile.html +2 -2
  106. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  107. package/bizar-dash/src/server/api.mjs +4 -4
  108. package/bizar-dash/src/server/background-store.mjs +15 -16
  109. package/bizar-dash/src/server/bg-poller.mjs +25 -35
  110. package/bizar-dash/src/server/bg-retry.mjs +66 -194
  111. package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
  112. package/bizar-dash/src/server/claude-info.mjs +412 -0
  113. package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
  114. package/bizar-dash/src/server/claude-sdk.mjs +191 -0
  115. package/bizar-dash/src/server/providers-store.mjs +22 -49
  116. package/bizar-dash/src/server/routes/background.mjs +24 -20
  117. package/bizar-dash/src/server/routes/chat.mjs +223 -326
  118. package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
  119. package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
  120. package/bizar-dash/src/server/routes/tasks.mjs +20 -28
  121. package/bizar-dash/src/server/task-delegator.mjs +76 -77
  122. package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
  123. package/bizar-dash/src/web/views/Chat.tsx +8 -8
  124. package/cli/bin.mjs +31 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/sandbox.mjs +220 -0
  128. package/cli/commands/validate.mjs +252 -288
  129. package/cli/dev-link.test.mjs +11 -11
  130. package/cli/doctor.mjs +131 -213
  131. package/cli/install.mjs +33 -37
  132. package/cli/install.test.mjs +9 -9
  133. package/cli/provision-claude.mjs +893 -0
  134. package/cli/provision.mjs +330 -226
  135. package/cli/provision.test.mjs +102 -0
  136. package/cli/utils.mjs +72 -58
  137. package/config/AGENTS.md +28 -28
  138. package/config/agents/_shared/AGENT_BASELINE.md +104 -684
  139. package/config/skills/bizar/SKILL.md +197 -0
  140. package/config/skills/cubesandbox/SKILL.md +148 -0
  141. package/config/skills/harness-engineering/SKILL.md +142 -0
  142. package/install.sh +66 -44
  143. package/package.json +19 -11
  144. package/packages/sdk/ARCHITECTURE.md +40 -36
  145. package/packages/sdk/package-lock.json +32 -0
  146. package/packages/sdk/package.json +15 -5
  147. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  148. package/packages/sdk/src/fingerprint.ts +0 -0
  149. package/packages/sdk/src/index.ts +38 -73
  150. package/packages/sdk/src/mcp/bin.ts +51 -0
  151. package/packages/sdk/src/mcp/server.ts +498 -0
  152. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  153. package/packages/sdk/tests/sdk.test.mjs +148 -0
  154. package/packages/sdk/vitest.config.ts +1 -1
  155. package/scripts/bh-full-e2e.mjs +166 -363
  156. package/scripts/check-deps.mjs +28 -46
  157. package/scripts/mirror-claude-md.sh +78 -0
  158. package/scripts/test-in-container.sh +157 -0
  159. package/templates/clean-state-checklist.md +3 -3
  160. package/templates/sprint-contract.md +2 -2
  161. package/bizar-dash/.bizar/activity.log +0 -3
  162. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  163. package/bizar-dash/.omx/state/session.json +0 -10
  164. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  165. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  166. package/bizar-dash/bizar-design/canvas.html +0 -281
  167. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  168. package/bizar-dash/bizar-design/components.css +0 -1665
  169. package/bizar-dash/bizar-design/components.html +0 -557
  170. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  172. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  174. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  176. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  177. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  178. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  179. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  180. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  181. package/bizar-dash/bizar-design/icons.svg +0 -44
  182. package/bizar-dash/bizar-design/index.html +0 -192
  183. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  185. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  189. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  190. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  191. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  192. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  193. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  194. package/bizar-dash/bizar-design/prototype.js +0 -114
  195. package/bizar-dash/bizar-design/tokens.css +0 -106
  196. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  197. package/bizar-dash/node_modules/.package-lock.json +0 -6
  198. package/bizar-dash/package-lock.json +0 -6
  199. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  200. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  201. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  202. package/cli/commands/cline-cmd.mjs +0 -289
  203. package/cli/commands/validate.test.mjs +0 -344
  204. package/cli/doctor.test.mjs +0 -350
  205. package/config/cline.json.template +0 -342
  206. package/packages/sdk/src/client.ts +0 -188
  207. package/packages/sdk/src/cline-events.ts +0 -134
  208. package/packages/sdk/src/cline-types.ts +0 -66
  209. package/packages/sdk/src/cline.ts +0 -339
  210. package/packages/sdk/src/errors.ts +0 -129
  211. package/packages/sdk/src/events.ts +0 -153
  212. package/packages/sdk/src/types.ts +0 -176
  213. package/packages/sdk/tests/client.test.ts +0 -217
  214. package/packages/sdk/tests/errors.test.ts +0 -108
  215. package/packages/sdk/tests/events.test.ts +0 -139
  216. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  217. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  218. package/plugins/bizar/ARCHITECTURE.md +0 -142
  219. package/plugins/bizar/CONSTRAINTS.md +0 -67
  220. package/plugins/bizar/LICENSE +0 -21
  221. package/plugins/bizar/README.md +0 -448
  222. package/plugins/bizar/index.ts +0 -872
  223. package/plugins/bizar/package.json +0 -39
  224. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  225. package/plugins/bizar/src/background-state.ts +0 -641
  226. package/plugins/bizar/src/background.ts +0 -1806
  227. package/plugins/bizar/src/cline-runner.ts +0 -203
  228. package/plugins/bizar/src/clineruntime.ts +0 -227
  229. package/plugins/bizar/src/commands-impl.ts +0 -151
  230. package/plugins/bizar/src/commands.ts +0 -1799
  231. package/plugins/bizar/src/compaction.d.mts +0 -48
  232. package/plugins/bizar/src/compaction.mjs +0 -192
  233. package/plugins/bizar/src/dashboard-client.ts +0 -233
  234. package/plugins/bizar/src/event-stream.ts +0 -606
  235. package/plugins/bizar/src/fingerprint.ts +0 -120
  236. package/plugins/bizar/src/handoff.ts +0 -79
  237. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  238. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  239. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  240. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  241. package/plugins/bizar/src/http-client.ts +0 -467
  242. package/plugins/bizar/src/key-rotation.ts +0 -218
  243. package/plugins/bizar/src/logger.ts +0 -144
  244. package/plugins/bizar/src/loop-engineering.ts +0 -241
  245. package/plugins/bizar/src/loop.ts +0 -176
  246. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  247. package/plugins/bizar/src/odin.ts +0 -227
  248. package/plugins/bizar/src/options.ts +0 -470
  249. package/plugins/bizar/src/plan-fs.ts +0 -323
  250. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  251. package/plugins/bizar/src/report.ts +0 -178
  252. package/plugins/bizar/src/research-prompt.ts +0 -35
  253. package/plugins/bizar/src/serve-info.ts +0 -228
  254. package/plugins/bizar/src/serve.ts +0 -496
  255. package/plugins/bizar/src/settings.ts +0 -349
  256. package/plugins/bizar/src/state.ts +0 -298
  257. package/plugins/bizar/src/tool-discipline.ts +0 -105
  258. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  259. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  260. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  261. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  262. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  263. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  264. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  265. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  266. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  267. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  268. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  269. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  270. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  271. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  272. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  273. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  274. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  275. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  276. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  277. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  278. package/plugins/bizar/src/tools/team-status.ts +0 -76
  279. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  280. package/plugins/bizar/src/trajectory.ts +0 -104
  281. package/plugins/bizar/tests/README.md +0 -99
  282. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  283. package/plugins/bizar/tests/background-state.test.ts +0 -277
  284. package/plugins/bizar/tests/background.test.ts +0 -402
  285. package/plugins/bizar/tests/block.test.ts +0 -195
  286. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  287. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  288. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  289. package/plugins/bizar/tests/commands.test.ts +0 -584
  290. package/plugins/bizar/tests/compaction.test.ts +0 -264
  291. package/plugins/bizar/tests/config.test.ts +0 -128
  292. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  293. package/plugins/bizar/tests/dispose.test.ts +0 -336
  294. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  295. package/plugins/bizar/tests/event.test.ts +0 -262
  296. package/plugins/bizar/tests/fingerprint.test.ts +0 -162
  297. package/plugins/bizar/tests/http-client.test.ts +0 -404
  298. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  299. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  300. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  301. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  302. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  303. package/plugins/bizar/tests/loop.test.ts +0 -397
  304. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  305. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  306. package/plugins/bizar/tests/odin.test.ts +0 -125
  307. package/plugins/bizar/tests/options.test.ts +0 -329
  308. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  309. package/plugins/bizar/tests/safety.test.ts +0 -256
  310. package/plugins/bizar/tests/serve.test.ts +0 -339
  311. package/plugins/bizar/tests/settings.test.ts +0 -351
  312. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  313. package/plugins/bizar/tests/state.test.ts +0 -276
  314. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  315. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  316. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  317. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  318. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  319. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  320. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  321. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  322. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  323. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  324. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  325. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  326. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  327. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  328. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  329. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  330. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  331. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  332. package/plugins/bizar/tsconfig.json +0 -29
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: cubesandbox
3
+ description: Use TencentCloud CubeSandbox — an E2B-compatible KVM microVM sandbox service for running untrusted AI-generated code with hardware-level isolation. Sub-60ms boot, <5MB overhead. Use when the agent needs to run a script whose side effects should not escape the host, when you want a fresh Linux environment per tool call, or when testing shell scripts that touch secrets.
4
+ ---
5
+
6
+ # CubeSandbox — sandboxed command execution
7
+
8
+ TencentCloud's [CubeSandbox](https://github.com/TencentCloud/CubeSandbox)
9
+ is an E2B-compatible KVM microVM service for AI agents. Each sandbox:
10
+
11
+ - boots in <60 ms,
12
+ - uses <5 MB overhead,
13
+ - has its own guest OS kernel (no shared-kernel escape),
14
+ - is reachable via the E2B SDK (`pypi install cubesandbox`).
15
+
16
+ It is the right host for any `Bash` call whose side effects should not
17
+ escape the sandbox: file writes, package installs, network probes, etc.
18
+
19
+ ## When to route through CubeSandbox
20
+
21
+ - Any `Bash` call that writes to disk — especially under `~/.config/`,
22
+ `/tmp/`, or `node_modules/`.
23
+ - Running untrusted user code (third-party repos, eval scripts).
24
+ - Test isolation: each session gets a fresh `/home/agent` filesystem.
25
+ - Reproducible environments — the same template boots identically.
26
+
27
+ ## When NOT to route through CubeSandbox
28
+
29
+ - Pure read-only inspection (use `Read` directly).
30
+ - Single-keystroke git plumbing (`git status`, `git diff`, `git log`).
31
+ - Heavy commands that boot a new instance — reuse an open one.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install cubesandbox
37
+ ```
38
+
39
+ Verify:
40
+
41
+ ```bash
42
+ python -c "import cubesandbox; print(cubesandbox.__version__)"
43
+ ```
44
+
45
+ Expected: `0.3.x` or `0.4.x`. Older versions lack AutoPause / Credential
46
+ Vault support (v0.5+).
47
+
48
+ ## Server URL
49
+
50
+ CubeSandbox ships the same protocol as E2B. Point the SDK at the
51
+ control-node:
52
+
53
+ ```bash
54
+ export CUBESANDBOX_API_KEY="<from cubesandbox web console>"
55
+ export CUBESANDBOX_URL="http://<control-node>:12088" # default
56
+ ```
57
+
58
+ For Bizar-managed local sandboxes, the Bizar CLI wraps the SDK and
59
+ injects both env vars from `~/.config/bizar/cubesandbox.env`.
60
+
61
+ ## Quick start (raw SDK)
62
+
63
+ ```python
64
+ from cubesandbox import Sandbox
65
+
66
+ with Sandbox(template="base", timeout=300) as box:
67
+ r = box.run("echo hello && date")
68
+ print(r.stdout)
69
+ ```
70
+
71
+ Equivalent via the Bizar CLI:
72
+
73
+ ```bash
74
+ bizar sandbox run bash 'echo hello && date'
75
+ ```
76
+
77
+ ## Templates
78
+
79
+ CubeSandbox boots from OCI templates. The "base" template is preinstalled
80
+ on every control node; install others from the Template Store UI.
81
+
82
+ For Bizar harness testing, use the `bizar-base` template which pins:
83
+
84
+ - bun 1.3.x
85
+ - node 20.x
86
+ - python 3.12
87
+ - `git`, `gh`, `ripgrep`
88
+
89
+ ## Snapshot / Clone / Rollback
90
+
91
+ CubeSandbox 0.3+ supports `snapshot()`, `clone()`, and `rollback()`:
92
+
93
+ ```python
94
+ snap = box.snapshot() # CoW checkpoint, ~ms
95
+ box2 = snap.clone() # independent twin
96
+ box.rollback(snap) # return to earlier state
97
+ ```
98
+
99
+ Bizar uses this for the `bizar_test-gate` runner: each test runs in a
100
+ clone of the base template; failures roll back so the next test starts
101
+ clean.
102
+
103
+ ## Security proxy (Credential Vault)
104
+
105
+ Since v0.4, CubeSandbox can inject credentials at the egress proxy so
106
+ they never enter the sandbox:
107
+
108
+ ```python
109
+ with Sandbox(template="base", proxy_credentials={
110
+ "OPENAI_API_KEY": "<user-key>",
111
+ }) as box:
112
+ box.run("python -c 'import openai; print(openai.api_key)'")
113
+ # prints OPENAI_API_KEY injected by CubeEgress; never logged
114
+ ```
115
+
116
+ Bizar's `bizar_sandbox_run` tool uses this when `BIZAR_PROXY_CREDS=1`.
117
+
118
+ ## Bizar integration map
119
+
120
+ | Layer | Component | Behavior |
121
+ |-------|-----------|----------|
122
+ | CLI | `bizar sandbox run` | Wraps SDK, persists last sandbox across calls |
123
+ | Plugin | `bizar_sandbox_run` | In-session tool — runs a `Bash` command in a fresh sandbox |
124
+ | Skill | `cubesandbox` (this) | Discovery + best practices |
125
+ | Agent | `@sandbox-runner` (optional) | Routes risky ops automatically |
126
+ | Hook | `PreToolUse` (v6.3+) | Detects dangerous patterns and forces sandbox routing |
127
+
128
+ See `cli/commands/sandbox.mjs` and `plugins/bizar/src/tools/sandbox.ts`.
129
+
130
+ ## Benchmarks (from upstream README)
131
+
132
+ | Metric | Docker | Traditional VM | CubeSandbox |
133
+ |--------|--------|----------------|-------------|
134
+ | Isolation | shared-kernel | dedicated kernel | dedicated kernel + eBPF |
135
+ | Cold start | 200ms | seconds | **<60ms** |
136
+ | Memory overhead | low | high | **<5MB** |
137
+ | Deploy density | high | low | extreme (thousands/node) |
138
+
139
+ P95: 90 ms. P99: 137 ms. Full agent workload benchmarked against SWE-Bench.
140
+
141
+ ## Troubleshooting
142
+
143
+ - **`SandboxError: no template`** — install a template from the WebUI
144
+ Template Store or run `bizar sandbox template install base`.
145
+ - **API key rejected** — check the URL doesn't end with a trailing slash
146
+ and the key is the long one shown in the WebUI.
147
+ - **Boot takes >5s** — usually means KVM is disabled. Run
148
+ `kvm-ok` (Debian) or `ls /dev/kvm`.
@@ -0,0 +1,41 @@
1
+ # Embedded ESP-IDF Skill
2
+
3
+ ESP-IDF v5.x C++ firmware patterns for Claude Code. Covers the `idf.py` workflow, FreeRTOS, IRAM/DRAM/PSRAM memory model, packed binary protocols with `static_assert`, Kconfig, drivers (I2C/SPI/GPIO/ADC/NVS/BLE/ESP-NOW), power management, and host-side tests that compile firmware headers without `idf.py`.
4
+
5
+ ## What it provides
6
+
7
+ - **SKILL.md** — quick start + 7 deep-dive references + 2 helper scripts
8
+ - **references/idf-py-commands.md** — every `idf.py` subcommand + exit codes
9
+ - **references/freertos-patterns.md** — task lifecycle, ISR-to-task handoff, ringbuffer streams
10
+ - **references/memory-and-iram.md** — IRAM/DRAM/PSRAM model, `IRAM_ATTR`, `MALLOC_CAP_*`
11
+ - **references/kconfig.md** — `depends on` / `select` / `imply` / `range` / `choice`
12
+ - **references/packed-structs.md** — `__attribute__((packed))` + `static_assert(sizeof == N)`
13
+ - **references/logging-discipline.md** — `ESP_LOG*` + low-rate aggregate lines
14
+ - **references/host-tests.md** — host tests without `idf.py`
15
+ - **scripts/idf_env.sh** — sources the vendored ESP-IDF env, validates `idf.py` is reachable
16
+ - **scripts/size_check.sh** — runs the project size budget check (AMS7-aware) or falls back to `idf.py size`
17
+
18
+ ## When it triggers
19
+
20
+ - Writing, reviewing, or debugging ESP-IDF C++ firmware
21
+ - Working with `idf.py build`/`flash`/`monitor`/`menuconfig`/`size`
22
+ - FreeRTOS task/queue/semaphore/mutex/ISR work
23
+ - IRAM/DRAM/PSRAM budgeting
24
+ - Packed binary protocols with `static_assert` on `sizeof`
25
+ - NVS, BLE/NimBLE, ESP-NOW
26
+ - Deep-sleep / light-sleep
27
+ - Adding Kconfig options
28
+ - Host-side C++ unit tests that compile firmware headers without `idf.py`
29
+
30
+ ## AMS7-specific extensions
31
+
32
+ This skill was first authored for the AMS7 ambulatory-monitoring firmware at `/projects/ams7_esp32`. Rules tagged `(AMS7)` are project-specific — do not silently generalize them to other ESP-IDF projects. Universal ESP-IDF rules are the default.
33
+
34
+ ## Manual install
35
+
36
+ ```bash
37
+ cp -R SKILL.md references scripts ~/.claude/skills/embedded-esp-idf/
38
+ chmod +x ~/.claude/skills/embedded-esp-idf/scripts/*.sh
39
+ ```
40
+
41
+ The BizarHarness installer can also install this automatically — select the **Embedded ESP-IDF** component.
@@ -0,0 +1,439 @@
1
+ ---
2
+ name: embedded-esp-idf
3
+ description: Write, review, or debug ESP-IDF v5.x C++ firmware. Triggers on idf.py build/flash/monitor/menuconfig/size, FreeRTOS tasks and ISRs, IRAM/DRAM/PSRAM budgeting, packed binary protocols with static_assert on sizeof, NVS, BLE/NimBLE, ESP-NOW, deep-sleep/light-sleep, Kconfig option design, or host-side C++ unit tests that compile firmware headers without idf.py. AMS7 ambulatory-monitoring firmware conventions (SD-first storage, low-rate aggregate logs, CONFIG_AMS7_* options, ESP-NOW framing discipline) are flagged as project-specific extensions.
4
+ ---
5
+
6
+ # Embedded ESP-IDF
7
+
8
+ ESP-IDF v5.x C++ firmware patterns: build/flash/monitor workflow, FreeRTOS, IRAM/DRAM memory model, packed binary protocols, drivers, and host-side testing without idf.py. Universal ESP-IDF rules are the default. Anything tagged **(AMS7)** is a project-specific extension for the `/projects/ams7_esp32` ambulatory-monitoring firmware — do not silently generalize it.
9
+
10
+ ## Quick start
11
+
12
+ ```bash
13
+ # 1. Source the ESP-IDF environment (required once per shell)
14
+ source esp/esp-idf/export.sh
15
+
16
+ # 2. Build / flash / monitor
17
+ idf.py build # compile firmware
18
+ idf.py -p /dev/ttyUSB0 flash # flash (Linux; COMx on Windows)
19
+ idf.py -p /dev/ttyUSB0 monitor # serial monitor (Ctrl-] to exit)
20
+
21
+ # 3. Configure / inspect
22
+ idf.py menuconfig # TUI Kconfig editor
23
+ idf.py size # IRAM/DRAM/flash breakdown (text)
24
+ idf.py size --format json # machine-readable for tooling
25
+ ```
26
+
27
+ `idf.py` is the single entry point: build, flash, monitor, menuconfig, size, clean, full-clean, set-target, partition-table, and OTA-related commands are all subcommands. See `references/idf-py-commands.md` for the full list and exit codes.
28
+
29
+ A helper that validates your environment is at `scripts/idf_env.sh`:
30
+
31
+ ```bash
32
+ bash scripts/idf_env.sh # prints the source line and verifies idf.py is reachable
33
+ ```
34
+
35
+ ## Project layout (typical ESP-IDF + AMS7)
36
+
37
+ ```
38
+ project-root/
39
+ ├── CMakeLists.txt # top-level: project(<name>), C++ standard, EXTRA_COMPONENT_DIRS
40
+ ├── sdkconfig # PRIMARY build configuration (Kconfig output)
41
+ ├── sdkconfig.<profile> # SECONDARY overlays (per-flow variants) — AMS7 uses these
42
+ ├── partitions.csv # flash partition table
43
+ ├── main/ # app component (idf_component_register lives here)
44
+ │ ├── CMakeLists.txt # main component sources and INCLUDE_DIRS
45
+ │ ├── Kconfig # app-level CONFIG_* options
46
+ │ ├── ams7_esp32.cpp # app_main(), task creation, system bring-up
47
+ │ └── ...
48
+ ├── components/ # first-party shared components
49
+ ├── module/ # submodules vendored into the build (set EXTRA_COMPONENT_DIRS)
50
+ ├── managed_components/ # populated by `idf.py add-dependency` (idf-component-manager)
51
+ ├── docs/ # design notes, memory budget, runbooks
52
+ └── tools/ # project-specific helpers (size budget, etc.)
53
+ ```
54
+
55
+ `(AMS7)` In the AMS7 project the top-level `CMakeLists.txt` sets:
56
+
57
+ ```cmake
58
+ set(EXTRA_COMPONENT_DIRS "./module") # pull ./module/* into the component search path
59
+ set(CMAKE_CXX_STANDARD 20) # C++20 across all components
60
+ set(PROJECT_VER "beta.studio.core.v1")
61
+ include($ENV{IDF_PATH}/tools/cmake/project.cmake)
62
+ project(ams7_esp32)
63
+ ```
64
+
65
+ ## Build profiles
66
+
67
+ `sdkconfig` is the primary, always-applied configuration. Project overlays under `sdkconfig.<name>` are layered on top for variant builds:
68
+
69
+ ```bash
70
+ # (AMS7) Build a flow-specific firmware variant in a separate build directory
71
+ idf.py -B build_espnow_flow -C . \
72
+ --sdkconfig sdkconfig.espnow_flow \
73
+ build flash
74
+ ```
75
+
76
+ `(AMS7)` AMS7 ships `sdkconfig.espnow_flow`, `sdkconfig.espnow_flow_minadv`, `sdkconfig.espnow_flow_studylock`. These toggle `CONFIG_AMS7_*` options (e.g., `CONFIG_AMS7_SUMMARY_ENABLE=y`, `CONFIG_AMS7_ESPNOW_WIFI_CHANNEL=6`) without touching the primary `sdkconfig`. Never hand-edit `sdkconfig` for flow-specific tweaks — add a profile file and merge with `--sdkconfig`.
77
+
78
+ ## Kconfig
79
+
80
+ Add options under `main/Kconfig` (or a component's `Kconfig` file). ESP-IDF auto-sources any `Kconfig` file inside a registered component.
81
+
82
+ ```kconfig
83
+ config AMS7_SUMMARY_ENABLE
84
+ bool "Enable ESP-NOW summary workflow"
85
+ default n
86
+ help
87
+ Master switch for the recording workflow that starts with BLE control
88
+ and then switches to ESP-NOW summary mode after acquisition begins.
89
+
90
+ config AMS7_BLE_VITALS_ENABLE
91
+ bool "Enable custom BLE vitals characteristic"
92
+ depends on AMS7_VITALS_ENABLE
93
+ default y
94
+
95
+ config AMS7_HR_HOLD_MS
96
+ int "Hold time for fused HR before fallback"
97
+ depends on AMS7_VITALS_ENABLE
98
+ range 0 60000
99
+ default 10000
100
+ ```
101
+
102
+ Key operators:
103
+
104
+ - `bool` / `int` / `string` / `hex` — value type
105
+ - `default y|n|"value"` — default when not explicitly set
106
+ - `depends on FOO` — option only visible when `FOO` is set
107
+ - `select BAR` — when this option is enabled, force `BAR = y`
108
+ - `imply BAR` — soft suggestion; user can still disable
109
+ - `range MIN MAX` — integer range constraint
110
+ - `choice ... endchoice` — radio group with mutually-exclusive values
111
+
112
+ `(AMS7)` AMS7 namespacing uses the `AMS7_*` prefix on every project-defined symbol. Treat `CONFIG_AMS7_*` as AMS7-specific — do not propose `CONFIG_AMS7_*` symbols for a different ESP-IDF project.
113
+
114
+ See `references/kconfig.md` for menus, sourcing custom Kconfig files, and component-level isolation.
115
+
116
+ ## Component CMakeLists.txt
117
+
118
+ Each component has a `CMakeLists.txt` with one call to `idf_component_register`:
119
+
120
+ ```cmake
121
+ idf_component_register(
122
+ SRCS
123
+ "ams7fileheader.cpp"
124
+ "ams7fileheader.h"
125
+ INCLUDE_DIRS
126
+ "."
127
+ REQUIRES # public link deps (visible in component.h)
128
+ nvs_flash
129
+ esp_wifi
130
+ PRIV_REQUIRES # private link deps (only used in component .cpp)
131
+ mbedtls
132
+ app_update
133
+ )
134
+ ```
135
+
136
+ - `SRCS` — sources for this component.
137
+ - `INCLUDE_DIRS` — headers exported to dependents.
138
+ - `REQUIRES` — other components whose public headers are used here (public dependency).
139
+ - `PRIV_REQUIRES` — used only in `.cpp` (private dependency; smaller rebuild blast radius).
140
+
141
+ `(AMS7)` The main component in AMS7 (`main/CMakeLists.txt`) registers ~50 sources and lists ~25 components under `REQUIRES` (drivers, BLE, NVS, OTA, etc.). Keep this list explicit — do not switch to glob patterns.
142
+
143
+ ## FreeRTOS patterns
144
+
145
+ ESP-IDF uses FreeRTOS. The universal rules:
146
+
147
+ - **Tasks**: `xTaskCreatePinnedToCore` to pin to core 0 or 1. App/main runs on the PRO CPU (core 1) by default; pin acquisition ISRs and time-critical tasks deliberately.
148
+ - **Priorities**: 0 is idle. 1–4 normal tasks. Real-time acquisition can use 5–24. `(AMS7)` AMS7 acquisition tasks run at priority 20+.
149
+ - **Blocking calls**: `vTaskDelay(pdMS_TO_TICKS(N))`, `xQueueReceive(..., portMAX_DELAY)`.
150
+ - **Queues**: prefer a queue over a shared buffer. Producer/consumer with `xQueueSend` / `xQueueReceive`.
151
+ - **Semaphores / mutexes**: binary/counting semaphores for ISR-to-task signaling; mutexes for shared resources. Prefer `xSemaphoreCreateBinary` and give it from `xQueueSendFromISR`/`xTaskNotifyFromISR`.
152
+ - **Timers**: `xTimerCreate` for periodic callbacks. One-shot timers for deferred work.
153
+ - **Event groups**: `xEventGroupWaitBits` for "wait until several subsystems ready" patterns.
154
+ - **Stream/ring buffers**: `xStreamBufferCreate` for variable-length byte streams; `xRingbufferCreate` for the IDF lockless variant.
155
+ - **ISR rules**: never block in an ISR. Use `xQueueSendFromISR`, `xTaskNotifyFromISR`, or `xTimerPendFunctionCallFromISR` and check the returned `BaseType_t xHigherPriorityTaskWoken` to force a context switch with `portYIELD_FROM_ISR`.
156
+
157
+ `portTICK_PERIOD_MS` is `10` by default (10 ms tick). Always convert via `pdMS_TO_TICKS(ms)` rather than multiplying by hand.
158
+
159
+ See `references/freertos-patterns.md` for task lifecycle, pinning to cores, watchdog setup, and ISR-to-task handoff patterns.
160
+
161
+ ## Memory model
162
+
163
+ ESP32 (Xtensa LX6/LX7, or RISC-V on S3/C3) has distinct address spaces:
164
+
165
+ - **IRAM** (instruction RAM, ~128 KB on classic ESP32): code marked with `IRAM_ATTR` lives here. Used for ISR handlers, flash-cache-disabled paths, and time-critical code. **Tight budget.**
166
+ - **DRAM** (data RAM, ~120 KB on classic ESP32): `.data`, `.bss`, heap, stack. Default for all variables and most code.
167
+ - **Flash** (4–16 MB): program text, read-only data (`.rodata`), filesystem. Code lives here by default; XIP cache fetches it.
168
+ - **PSRAM** (when chip has it): slow external RAM via SPI. Use `MALLOC_CAP_SPIRAM` for large buffers you cannot fit in DRAM.
169
+
170
+ Universal guidance:
171
+
172
+ - **Prefer `static` over heap.** DRAM fragmentation on ESP32 is severe; long-running firmware that `malloc`s in a loop will eventually fail.
173
+ - **Mark only what must run from IRAM**: ISR handlers, flash-cache-disabled paths (e.g., SPI drivers during DMA), and a few hot loops. Most code is fine in flash.
174
+ - **`MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT`** for buffers that must not touch PSRAM (DMA-capable memory).
175
+ - **`MALLOC_CAP_SPIRAM`** for big buffers that need not be DMA-capable (logs, JSON caches).
176
+ - **`heap_caps_print_heap_info(MALLOC_CAP_8BIT)`** in a debug build to confirm.
177
+
178
+ `(AMS7)` **IRAM is the tightest budget on AMS7.** Reference baseline (see `docs/firmware/memory_budget.md`):
179
+
180
+ ```
181
+ IRAM: 108,726 used, 22,346 free, 131,072 total
182
+ DRAM: 43,152 used, 81,428 free, 124,580 total
183
+ ```
184
+
185
+ Keep IRAM remaining ≥ 20 KiB; below 24 KiB prints a warning because new `IRAM_ATTR` code can hurt quickly. Do not add `IRAM_ATTR` unless the function is required in ISR/cache-disabled paths. Always re-run the size check after acquisition-path changes.
186
+
187
+ See `references/memory-and-iram.md` for IRAM_ATTR placement rules, PSRAM trade-offs, and the things that blow the IRAM budget (logging, format strings in IRAM, ISR deep paths).
188
+
189
+ ## Packed binary protocols
190
+
191
+ Wire-format frames over ESP-NOW, BLE, or any byte-oriented transport must be deterministic in size. AMS7 uses the same shape across all frames — see `main/connectivity/espnow_imu_frame.hpp` for a clean example:
192
+
193
+ ```cpp
194
+ #define CORE_ESPNOW_IMU_MAGIC 0x494dU // 'IM'
195
+ #define CORE_ESPNOW_IMU_VERSION 1U
196
+ #define CORE_ESPNOW_FRAME_IMU_RAW 1U
197
+
198
+ typedef struct __attribute__((packed)) {
199
+ uint16_t magic; // first 2 bytes identify the frame family
200
+ uint8_t version; // protocol version of this struct
201
+ uint8_t frame_type; // sub-type within family
202
+ uint16_t id; // sender / subject
203
+ uint16_t seq; // monotonic sequence
204
+ uint16_t age_ms; // capture age in ms (sender-stamped)
205
+ int16_t accel_x, accel_y, accel_z;
206
+ int16_t gyro_x, gyro_y, gyro_z;
207
+ } core_espnow_imu_frame_v1_t;
208
+
209
+ // Compile-time size lock — breaks the build if the struct grows or shrinks.
210
+ static_assert(sizeof(core_espnow_imu_frame_v1_t) == 22,
211
+ "core_espnow_imu_frame_v1_t must be 22 bytes");
212
+ ```
213
+
214
+ Universal rules:
215
+
216
+ - Always `__attribute__((packed))` and always back it with `static_assert(sizeof(T) == N)` (or `_Static_assert` in C linkage). Catch drift at compile time, not over the air.
217
+ - Fixed-width types only (`uint16_t`, `int16_t`, not `int`).
218
+ - First fields are `magic` (16-bit ASCII-ish) + `version` + `frame_type`. Magic is how receivers reject foreign frames; version is how they migrate.
219
+ - All multi-byte fields are **little-endian on the wire** — ESP32 is LE natively, but make byte order explicit when porting.
220
+ - Wire framing is **length-prefixed**: receiver gets a 2-byte length, then exactly that many bytes. No delimiter-scanning, no escape bytes.
221
+ - For variable payloads, define `frame_header_t` once and reuse — don't reinvent per frame family.
222
+
223
+ `(AMS7)` The naming convention `core_<transport>_<family>_frame_vN_t` and the `static_assert` on `sizeof` are non-negotiable in AMS7. Every frame header under `main/connectivity/` follows this pattern (imu, resp, resp_icg, beat_event, capability, name, protocol_status, gateway_command, marker).
224
+
225
+ See `references/packed-structs.md` for the full pattern, capability bits, and migration across versions.
226
+
227
+ ## Logging
228
+
229
+ ```cpp
230
+ static const char *TAG = "ams7driver";
231
+ ESP_LOGI(TAG, "Start acquisition stack_hw=%lu", (unsigned long)stack_hw);
232
+ ESP_LOGW(TAG, "Skipping channel-info drain wait for device without ringbuffer");
233
+ ESP_LOGE(TAG, "Failed to start stop finalization task");
234
+ ```
235
+
236
+ Universal guidance:
237
+
238
+ - Use `ESP_LOGE` for failures, `ESP_LOGW` for recoverable issues, `ESP_LOGI` for state transitions, `ESP_LOGD` for verbose debug (off by default), `ESP_LOGV` for trace.
239
+ - Pick a stable per-module tag — file-scoped `static const char *TAG = "modname";`.
240
+ - Format strings are validated against the args at compile time — `%lu` for `unsigned long`, `%" PRIu32 "` for `uint32_t`, etc.
241
+ - Gating with `CONFIG_*_LOG_ENABLE` switches lets you build a release binary with no debug logs at all (`idf.py menuconfig → Component config → Log output → Default log verbosity`).
242
+
243
+ `(AMS7)` **Logging discipline.** Acquisition builds must not log per-sample or per-frame — at 125–500 Hz that is unprintable and useless. Acceptable log rates:
244
+
245
+ - Per-event: BLE connect, ESP-NOW peer add, acquisition start/stop, file open/close.
246
+ - Periodic aggregate: low-rate counters via a `pl:` console line every N ms (e.g., `ESP_LOGI(TAG, "pl: beats=%lu rr_ms=%lu q=%u", ...)`).
247
+ - Trial-debug toggles (e.g., `CONFIG_AMS7_RESP_TRIAL_DEBUG_LOG_ENABLE=y`) gate extra lines.
248
+
249
+ For full AMS7 logging rules see `references/logging-discipline.md`.
250
+
251
+ ## Drivers
252
+
253
+ ESP-IDF v5 unified drivers (used by AMS7 modules):
254
+
255
+ - **I2C**: `i2c_master_bus_config_t` + `i2c_master_bus_handle_t`, then per-device `i2c_device_config_t`. `i2c_master_transmit`, `i2c_master_receive`, `i2c_master_transmit_receive`.
256
+ - **SPI**: `spi_bus_initialize` + `spi_device_interface_config_t` + `spi_device_queue_transfer`. Use `IRAM_ATTR` on `queueTransfer`/`getTransferResult` for DMA-completion paths.
257
+ - **GPIO**: `gpio_config`, `gpio_set_level`, `gpio_install_isr_service` (zero-arg ISR service install once at boot, then `gpio_isr_handler_add`).
258
+ - **ADC**: `esp_adc/adc_oneshot.h` for one-shot reads; `esp_adc/adc_continuous.h` for DMA-driven streams.
259
+ - **RTC**: `esp_sleep_enable_timer_wakeup`, `esp_sleep_enable_ext0_wakeup` (single GPIO), `esp_sleep_enable_ext1_wakeup` (multiple GPIOs), `esp_deep_sleep_start`.
260
+ - **NVS**: see next section.
261
+ - **BLE**: NimBLE (`nimble/`), or the Bluedroid stack. AMS7 uses NimBLE via `components/bt`.
262
+ - **Wi-Fi / ESP-NOW**: `esp_wifi_set_mode(WIFI_MODE_STA)`, `esp_wifi_set_promiscuous`, `esp_wifi_set_channel`, then `esp_now_init`, `esp_now_register_send_cb`, `esp_now_send`.
263
+
264
+ ## NVS (preferences)
265
+
266
+ `nvs_flash_init()` once at boot. Per-namespace open/get/set/commit:
267
+
268
+ ```cpp
269
+ nvs_handle_t h;
270
+ esp_err_t err = nvs_open("storage", NVS_READWRITE, &h);
271
+ if (err != ESP_OK) { /* handle */ }
272
+
273
+ uint8_t mac[6] = {};
274
+ size_t len = sizeof(mac);
275
+ err = nvs_get_blob(h, "peer_mac", mac, &len);
276
+
277
+ uint32_t counter = 0;
278
+ nvs_set_u32(h, "boot_count", counter + 1);
279
+ nvs_commit(h);
280
+ nvs_close(h);
281
+ ```
282
+
283
+ - Namespaces (`"storage"`, `"wifi"`, `"ams7cfg"`) isolate unrelated settings.
284
+ - Blobs for binary data; `nvs_set_str` / `nvs_get_str` for short strings; `nvs_set_u8/u16/u32/u64/i32` for integers.
285
+ - `nvs_commit` is required after writes; reads do not need commit.
286
+ - Flash wear is real — prefer batched writes. Use a memory cache and flush on shutdown or every N minutes.
287
+
288
+ `(AMS7)` AMS7 stores device-name, hardware-rev, last-acquisition metadata in NVS under the `"ams7cfg"` namespace, and persists peer / study-locks state.
289
+
290
+ For NVS review tasks (most common: catching `nvs_flash_init()` anti-patterns, swallowed errors, missing commits, wrong namespaces), see `references/nvs.md`. NVS issues are the highest-yield review finding for non-driver firmware code, so this reference is worth loading early.
291
+
292
+ ## Power management
293
+
294
+ - `esp_sleep_enable_timer_wakeup(seconds)` for timed wakes.
295
+ - `esp_sleep_enable_ext0_wakeup(gpio_num, level)` for one external wake pin.
296
+ - `esp_sleep_enable_ext1_wakeup(bitmask, mode)` for multiple pins (EXT1 only on classic ESP32; on S3 use `gpio_wakeup`).
297
+ - `esp_deep_sleep_start()` — full power-off; only RTC fast memory survives (`RTC_DATA_ATTR` / `RTC_IRAM_ATTR`).
298
+ - `esp_light_sleep_start()` — pause CPU, peripherals resume on wake; lower latency than deep sleep.
299
+ - `esp_sleep_pd_domain_config` to power down unused domains.
300
+ - `RTC_DATA_ATTR static uint32_t boot_count;` survives deep sleep.
301
+ - `esp_wifi_set_ps(WIFI_PS_MIN_MODEM)` for Wi-Fi connected/idle power save.
302
+
303
+ `(AMS7)` AMS7 enters deep sleep after acquisition stop with a wake-on-tap (`esp_sleep_enable_ext0_wakeup` on ICM-42688-P INT1) plus a wake-after-N-seconds safety timer.
304
+
305
+ ## Size budget
306
+
307
+ `idf.py size` shows IRAM / DRAM / flash app image. Read it after every change to acquisition-path code.
308
+
309
+ ```bash
310
+ idf.py size # text summary
311
+ idf.py size --format json # for tooling
312
+ idf.py size --output-file size.json
313
+ ```
314
+
315
+ What to watch:
316
+
317
+ - **IRAM used**: this is the dangerous one. Adding `IRAM_ATTR` to a large function or pulling logging into ISR paths inflates it.
318
+ - **DRAM used**: static `.bss` and `.data`. Large `static` buffers add here.
319
+ - **Flash app binary**: usually comfortable; check `0xfb650 bytes, 0xf49b0 bytes free in the smallest app partition`.
320
+
321
+ `(AMS7)` AMS7 ships `tools/check_idf_size_budget.py` — a hard gate that runs `idf.py size --format json` and fails if IRAM remaining drops below 20 KiB or DRAM remaining below 40 KiB. Always run it after changes:
322
+
323
+ ```bash
324
+ source esp/esp-idf/export.sh
325
+ tools/check_idf_size_budget.py --min-iram-remain 20480 --min-dram-remain 40960
326
+ ```
327
+
328
+ A non-project wrapper that delegates to it when present (and falls back to `idf.py size`) is at `scripts/size_check.sh`:
329
+
330
+ ```bash
331
+ bash scripts/size_check.sh # uses current dir as project
332
+ bash scripts/size_check.sh --project-dir build_espnow_flow
333
+ ```
334
+
335
+ ## Host-side tests
336
+
337
+ Policy modules, payload encoders/decoders, and pure-C++ algorithms can be unit-tested on the host **without `idf.py`**. ESP-IDF firmware that depends on FreeRTOS / drivers stays out of these tests.
338
+
339
+ `(AMS7)` AMS7's host tests are deliberately minimal: a `tests/<area>/<name>_test.cpp` source file plus a `run_<name>_test.sh` shell wrapper that compiles with `g++ -std=c++17`, links the firmware `.cpp` source files directly, and runs. Example:
340
+
341
+ ```bash
342
+ #!/usr/bin/env bash
343
+ set -euo pipefail
344
+ g++ -std=c++17 \
345
+ tests/connectivity/espnow_imu_frame_test.cpp \
346
+ main/connectivity/espnow_imu_frame.cpp \
347
+ -I main/connectivity \
348
+ -o /tmp/espnow_imu_frame_test
349
+ /tmp/espnow_imu_frame_test
350
+ ```
351
+
352
+ Two key distinctions vs the firmware build:
353
+
354
+ - **No `idf.py`**: pure `g++` (or `cmake --build` for larger suites). Fast, runs anywhere.
355
+ - **No FreeRTOS or driver code**: the host testable surface should not include `<freertos/FreeRTOS.h>`, `esp_log.h`, or anything that pulls in `driver/`. If a header you want to test transitively includes those, factor the pure logic out.
356
+
357
+ For larger host-test projects with fakes and a CMake build, see the **`cpp-testing`** skill — it covers GoogleTest, Catch2, host fakes for FreeRTOS, and fixture patterns. See `references/host-tests.md` for the AMS7 host-test layout and pitfalls.
358
+
359
+ ## Do / Don't
360
+
361
+ **Do**
362
+
363
+ ```cpp
364
+ // Mark an ISR handler and let it defer work to a task
365
+ void IRAM_ATTR gpio_isr(void *arg) {
366
+ BaseType_t hpw = pdFALSE;
367
+ xQueueSendFromISR(gpio_evt_queue, &pin, &hpw);
368
+ portYIELD_FROM_ISR(hpw);
369
+ }
370
+ ```
371
+
372
+ ```cpp
373
+ // Lock the wire size at compile time
374
+ typedef struct __attribute__((packed)) { /* ... */ } my_frame_v1_t;
375
+ static_assert(sizeof(my_frame_v1_t) == N, "wire size must match");
376
+ ```
377
+
378
+ ```cpp
379
+ // Aggregate, low-rate log instead of per-frame spam
380
+ ESP_LOGI(TAG, "pl: beats=%lu rr_ms=%lu q=%u", beats, rr_ms, quality);
381
+ ```
382
+
383
+ **Don't**
384
+
385
+ ```cpp
386
+ // Don't malloc in a hot path
387
+ while (running) {
388
+ auto *p = new uint8_t[256]; // DRAM fragmentation, leaks on errors
389
+ // ...
390
+ }
391
+
392
+ // Don't block inside an ISR
393
+ void IRAM_ATTR bad_isr(void *a) {
394
+ vTaskDelay(pdMS_TO_TICKS(10)); // illegal — use xTaskNotifyFromISR + task
395
+ }
396
+
397
+ // Don't add IRAM_ATTR unless required
398
+ void IRAM_ATTR slow_json_formatter(...); // pulls a big function into IRAM
399
+
400
+ // Don't hand-roll endianness
401
+ uint32_t be = (raw[0] << 24) | (raw[1] << 16) | ...; // use explicit <bit> byte-swap helpers
402
+ ```
403
+
404
+ ## Resources
405
+
406
+ ### Task-to-reference index
407
+
408
+ For most C++ review tasks on non-driver firmware code (NVS, logging, Kconfig, BLE/ESP-NOW data paths), the highest-yield references are:
409
+
410
+ | Task | Load first | Also useful |
411
+ |---|---|---|
412
+ | Reviewing NVS / persistence code | `references/nvs.md` | `logging-discipline.md` |
413
+ | Reviewing logging or `ESP_LOG*` calls | `references/logging-discipline.md` | `kconfig.md` |
414
+ | Reviewing Kconfig options | `kconfig.md` | (inline guidance in SKILL.md) |
415
+ | Reviewing packed binary frames / structs | `packed-structs.md` | (inline guidance in SKILL.md) |
416
+ | Reviewing task/queue/ISR code | `freertos-patterns.md` | `memory-and-iram.md` |
417
+ | Reviewing IRAM/disk usage after a build | `memory-and-iram.md` | `scripts/size_check.sh` |
418
+ | Building, flashing, monitoring | `idf-py-commands.md` | `scripts/idf_env.sh` |
419
+ | Writing a host-side C++ test | `host-tests.md` | `$cpp-testing` skill |
420
+
421
+ ### references/
422
+
423
+ Load on demand for deeper detail:
424
+
425
+ - `idf-py-commands.md` — full `idf.py` subcommand list, exit codes, monitor filters, partition-table flow.
426
+ - `freertos-patterns.md` — task lifecycle, pinning, priorities, queue + ISR-to-task handoff, ringbuffer for streams, watchdog, ISR rules.
427
+ - `memory-and-iram.md` — IRAM vs DRAM vs flash vs PSRAM, `iram_attr` placement, what blows the IRAM budget.
428
+ - `kconfig.md` — adding options, menus, `depends on` / `select` / `imply` / `range` / `choice`, component-level Kconfig isolation.
429
+ - `nvs.md` — NVS init/handle/error pattern, namespace hygiene, `nvs_commit`, `nvs_flash_init()` anti-patterns, AMS7 `"ams7cfg"` namespace. **High-yield for review tasks.**
430
+ - `packed-structs.md` — `__attribute__((packed))`, byte order, `static_assert`, versioning, capability bits, magic byte, length-prefixed framing. Mirrors AMS7's `main/connectivity/espnow_*_frame.hpp`.
431
+ - `logging-discipline.md` — `ESP_LOG*`, log levels, tagging, no-per-frame logs, `pl:` aggregate lines, gating with `CONFIG_*_LOG_ENABLE`. **High-yield for review tasks.**
432
+ - `host-tests.md` — pure-CMake host tests that include firmware `.cpp` from `main/`, fakes for FreeRTOS, common pitfalls.
433
+
434
+ ### scripts/
435
+
436
+ Small, runnable helpers:
437
+
438
+ - `scripts/idf_env.sh` — prints the `source esp/esp-idf/export.sh` line and validates that `idf.py` is reachable. Exits 0 if the env is good, 1 otherwise.
439
+ - `scripts/size_check.sh` — runs AMS7's `tools/check_idf_size_budget.py` if available, else falls back to `idf.py size`. Exits 0 on pass, 1 on size violation.