@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.
- package/.claude/CLAUDE.md +15 -0
- package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
- package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
- package/.claude/agents/_shared/SKILLS.md +109 -0
- package/.claude/agents/agent-browser.md +80 -0
- package/.claude/agents/baldr.md +49 -0
- package/.claude/agents/forseti.md +51 -0
- package/.claude/agents/frigg.md +42 -0
- package/.claude/agents/heimdall.md +33 -0
- package/.claude/agents/hermod.md +53 -0
- package/.claude/agents/mimir.md +49 -0
- package/.claude/agents/odin.md +287 -0
- package/.claude/agents/quick.md +34 -0
- package/.claude/agents/semble-search.md +50 -0
- package/.claude/agents/thor.md +53 -0
- package/.claude/agents/tyr.md +56 -0
- package/.claude/agents/vidarr.md +54 -0
- package/.claude/agents/vor.md +53 -0
- package/.claude/commands/audit.md +25 -0
- package/.claude/commands/bizar.md +22 -0
- package/.claude/commands/explain.md +17 -0
- package/.claude/commands/init.md +29 -0
- package/.claude/commands/learn.md +44 -0
- package/.claude/commands/plan.md +35 -0
- package/.claude/commands/plow-through.md +50 -0
- package/.claude/commands/pr-review.md +49 -0
- package/.claude/commands/setup-provider.md +96 -0
- package/.claude/commands/tailscale-serve.md +100 -0
- package/.claude/commands/team.md +132 -0
- package/.claude/commands/test.md +62 -0
- package/.claude/commands/validate.md +68 -0
- package/.claude/commands/visual-plan.md +24 -0
- package/.claude/hooks/README.md +92 -0
- package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
- package/.claude/hooks/pretooluse-bash.mjs +81 -0
- package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
- package/.claude/hooks/sessionend-recall.mjs +74 -0
- package/.claude/hooks/sessionstart-prime.mjs +80 -0
- package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
- package/.claude/settings.json +116 -0
- package/.claude/skills/9router/SKILL.md +80 -0
- package/.claude/skills/9router-chat/SKILL.md +73 -0
- package/.claude/skills/9router-embeddings/SKILL.md +69 -0
- package/.claude/skills/9router-image/SKILL.md +86 -0
- package/.claude/skills/9router-stt/SKILL.md +79 -0
- package/.claude/skills/9router-tts/SKILL.md +80 -0
- package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
- package/.claude/skills/9router-web-search/SKILL.md +91 -0
- package/.claude/skills/bizar/README.md +9 -0
- package/.claude/skills/bizar/SKILL.md +450 -0
- package/.claude/skills/cpp-coding-standards/README.md +28 -0
- package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
- package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
- package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
- package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
- package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
- package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
- package/.claude/skills/cpp-testing/README.md +28 -0
- package/.claude/skills/cpp-testing/SKILL.md +304 -0
- package/.claude/skills/cpp-testing/references/coverage.md +370 -0
- package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
- package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
- package/.claude/skills/cpp-testing/references/mocking.md +364 -0
- package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
- package/.claude/skills/cubesandbox/SKILL.md +148 -0
- package/.claude/skills/embedded-esp-idf/README.md +41 -0
- package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
- package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
- package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
- package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
- package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
- package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
- package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
- package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
- package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
- package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
- package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
- package/.claude/skills/glyph/SKILL.md +163 -0
- package/.claude/skills/harness-engineering/SKILL.md +143 -0
- package/.claude/skills/lightrag/SKILL.md +81 -0
- package/.claude/skills/memory-protocol/SKILL.md +105 -0
- package/.claude/skills/obsidian/SKILL.md +306 -0
- package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
- package/.claude/skills/self-improvement/SKILL.md +64 -0
- package/README.md +87 -59
- package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-B58aiJiE.js} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-B58aiJiE.js.map} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js → MobileChat-BJrqwVDd.js} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-BJrqwVDd.js.map} +1 -1
- package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js → MobileSettings-CEQNJNLJ.js} +1 -1
- package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-CEQNJNLJ.js.map} +1 -1
- package/bizar-dash/dist/assets/{main-DYiZqMrn.js → main-IvfQAOfy.js} +1 -1
- package/bizar-dash/dist/assets/{main-DYiZqMrn.js.map → main-IvfQAOfy.js.map} +1 -1
- package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js → markdown-tOLaD6nm.js} +1 -1
- package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-tOLaD6nm.js.map} +1 -1
- package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js → mobile-DYCHcUpq.js} +1 -1
- package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DYCHcUpq.js.map} +1 -1
- package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js → mobile-layout-CBHjpwsb.js} +2 -2
- package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js.map → mobile-layout-CBHjpwsb.js.map} +1 -1
- package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js → useSlashCommands-Bd7_FA6U.js} +2 -2
- package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js.map → useSlashCommands-Bd7_FA6U.js.map} +1 -1
- package/bizar-dash/dist/assets/{vendor-CeHGtduv.js → vendor-C843201K.js} +12 -12
- package/bizar-dash/dist/assets/vendor-C843201K.js.map +1 -0
- package/bizar-dash/dist/index.html +6 -6
- package/bizar-dash/dist/mobile.html +2 -2
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +4 -4
- package/bizar-dash/src/server/background-store.mjs +15 -16
- package/bizar-dash/src/server/bg-poller.mjs +25 -35
- package/bizar-dash/src/server/bg-retry.mjs +66 -194
- package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
- package/bizar-dash/src/server/claude-info.mjs +412 -0
- package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
- package/bizar-dash/src/server/claude-sdk.mjs +191 -0
- package/bizar-dash/src/server/providers-store.mjs +22 -49
- package/bizar-dash/src/server/routes/background.mjs +24 -20
- package/bizar-dash/src/server/routes/chat.mjs +223 -326
- package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
- package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
- package/bizar-dash/src/server/routes/tasks.mjs +20 -28
- package/bizar-dash/src/server/task-delegator.mjs +76 -77
- package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
- package/bizar-dash/src/web/views/Chat.tsx +8 -8
- package/cli/bin.mjs +31 -18
- package/cli/commands/claude-cmd.mjs +348 -0
- package/cli/commands/install.mjs +12 -11
- package/cli/commands/sandbox.mjs +220 -0
- package/cli/commands/validate.mjs +252 -288
- package/cli/dev-link.test.mjs +11 -11
- package/cli/doctor.mjs +131 -213
- package/cli/install.mjs +33 -37
- package/cli/install.test.mjs +9 -9
- package/cli/provision-claude.mjs +893 -0
- package/cli/provision.mjs +330 -226
- package/cli/provision.test.mjs +102 -0
- package/cli/utils.mjs +72 -58
- package/config/AGENTS.md +28 -28
- package/config/agents/_shared/AGENT_BASELINE.md +104 -684
- package/config/skills/bizar/SKILL.md +197 -0
- package/config/skills/cubesandbox/SKILL.md +148 -0
- package/config/skills/harness-engineering/SKILL.md +142 -0
- package/install.sh +66 -44
- package/package.json +19 -11
- package/packages/sdk/ARCHITECTURE.md +40 -36
- package/packages/sdk/package-lock.json +32 -0
- package/packages/sdk/package.json +15 -5
- package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
- package/packages/sdk/src/fingerprint.ts +0 -0
- package/packages/sdk/src/index.ts +38 -73
- package/packages/sdk/src/mcp/bin.ts +51 -0
- package/packages/sdk/src/mcp/server.ts +498 -0
- package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
- package/packages/sdk/tests/sdk.test.mjs +148 -0
- package/packages/sdk/vitest.config.ts +1 -1
- package/scripts/bh-full-e2e.mjs +166 -363
- package/scripts/check-deps.mjs +28 -46
- package/scripts/mirror-claude-md.sh +78 -0
- package/scripts/test-in-container.sh +157 -0
- package/templates/clean-state-checklist.md +3 -3
- package/templates/sprint-contract.md +2 -2
- package/bizar-dash/.bizar/activity.log +0 -3
- package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
- package/bizar-dash/.omx/state/session.json +0 -10
- package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
- package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
- package/bizar-dash/bizar-design/canvas.html +0 -281
- package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/components.css +0 -1665
- package/bizar-dash/bizar-design/components.html +0 -557
- package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/agents.html +0 -74
- package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/memory.html +0 -75
- package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
- package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/overview.html +0 -95
- package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/settings.html +0 -70
- package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/icons.svg +0 -44
- package/bizar-dash/bizar-design/index.html +0 -192
- package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/agents.html +0 -29
- package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/memory.html +0 -28
- package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
- package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/overview.html +0 -33
- package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/settings.html +0 -28
- package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/prototype.js +0 -114
- package/bizar-dash/bizar-design/tokens.css +0 -106
- package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
- package/bizar-dash/node_modules/.package-lock.json +0 -6
- package/bizar-dash/package-lock.json +0 -6
- package/bizar-dash/src/server/cline-sdk.mjs +0 -132
- package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
- package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
- package/cli/commands/cline-cmd.mjs +0 -289
- package/cli/commands/validate.test.mjs +0 -344
- package/cli/doctor.test.mjs +0 -350
- package/config/cline.json.template +0 -342
- package/packages/sdk/src/client.ts +0 -188
- package/packages/sdk/src/cline-events.ts +0 -134
- package/packages/sdk/src/cline-types.ts +0 -66
- package/packages/sdk/src/cline.ts +0 -339
- package/packages/sdk/src/errors.ts +0 -129
- package/packages/sdk/src/events.ts +0 -153
- package/packages/sdk/src/types.ts +0 -176
- package/packages/sdk/tests/client.test.ts +0 -217
- package/packages/sdk/tests/errors.test.ts +0 -108
- package/packages/sdk/tests/events.test.ts +0 -139
- package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
- package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
- package/plugins/bizar/ARCHITECTURE.md +0 -142
- package/plugins/bizar/CONSTRAINTS.md +0 -67
- package/plugins/bizar/LICENSE +0 -21
- package/plugins/bizar/README.md +0 -448
- package/plugins/bizar/index.ts +0 -872
- package/plugins/bizar/package.json +0 -39
- package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
- package/plugins/bizar/src/background-state.ts +0 -641
- package/plugins/bizar/src/background.ts +0 -1806
- package/plugins/bizar/src/cline-runner.ts +0 -203
- package/plugins/bizar/src/clineruntime.ts +0 -227
- package/plugins/bizar/src/commands-impl.ts +0 -151
- package/plugins/bizar/src/commands.ts +0 -1799
- package/plugins/bizar/src/compaction.d.mts +0 -48
- package/plugins/bizar/src/compaction.mjs +0 -192
- package/plugins/bizar/src/dashboard-client.ts +0 -233
- package/plugins/bizar/src/event-stream.ts +0 -606
- package/plugins/bizar/src/fingerprint.ts +0 -120
- package/plugins/bizar/src/handoff.ts +0 -79
- package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
- package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
- package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
- package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
- package/plugins/bizar/src/http-client.ts +0 -467
- package/plugins/bizar/src/key-rotation.ts +0 -218
- package/plugins/bizar/src/logger.ts +0 -144
- package/plugins/bizar/src/loop-engineering.ts +0 -241
- package/plugins/bizar/src/loop.ts +0 -176
- package/plugins/bizar/src/mistake-recovery.ts +0 -98
- package/plugins/bizar/src/odin.ts +0 -227
- package/plugins/bizar/src/options.ts +0 -470
- package/plugins/bizar/src/plan-fs.ts +0 -323
- package/plugins/bizar/src/reasoning-clean.ts +0 -454
- package/plugins/bizar/src/report.ts +0 -178
- package/plugins/bizar/src/research-prompt.ts +0 -35
- package/plugins/bizar/src/serve-info.ts +0 -228
- package/plugins/bizar/src/serve.ts +0 -496
- package/plugins/bizar/src/settings.ts +0 -349
- package/plugins/bizar/src/state.ts +0 -298
- package/plugins/bizar/src/tool-discipline.ts +0 -105
- package/plugins/bizar/src/tools/agent-browser.ts +0 -315
- package/plugins/bizar/src/tools/bg-collect.ts +0 -131
- package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
- package/plugins/bizar/src/tools/bg-kill.ts +0 -116
- package/plugins/bizar/src/tools/bg-pause.ts +0 -99
- package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
- package/plugins/bizar/src/tools/bg-resume.ts +0 -94
- package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
- package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
- package/plugins/bizar/src/tools/bg-status.ts +0 -130
- package/plugins/bizar/src/tools/graph-query.ts +0 -278
- package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
- package/plugins/bizar/src/tools/memory-list.ts +0 -43
- package/plugins/bizar/src/tools/memory-read.ts +0 -69
- package/plugins/bizar/src/tools/memory-search.ts +0 -47
- package/plugins/bizar/src/tools/memory-write.ts +0 -54
- package/plugins/bizar/src/tools/open-kb.ts +0 -198
- package/plugins/bizar/src/tools/plan-action.ts +0 -785
- package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
- package/plugins/bizar/src/tools/team-spawn.ts +0 -73
- package/plugins/bizar/src/tools/team-status.ts +0 -76
- package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
- package/plugins/bizar/src/trajectory.ts +0 -104
- package/plugins/bizar/tests/README.md +0 -99
- package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
- package/plugins/bizar/tests/background-state.test.ts +0 -277
- package/plugins/bizar/tests/background.test.ts +0 -402
- package/plugins/bizar/tests/block.test.ts +0 -195
- package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
- package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
- package/plugins/bizar/tests/commands-impl.test.ts +0 -316
- package/plugins/bizar/tests/commands.test.ts +0 -584
- package/plugins/bizar/tests/compaction.test.ts +0 -264
- package/plugins/bizar/tests/config.test.ts +0 -128
- package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
- package/plugins/bizar/tests/dispose.test.ts +0 -336
- package/plugins/bizar/tests/event-stream.test.ts +0 -409
- package/plugins/bizar/tests/event.test.ts +0 -262
- package/plugins/bizar/tests/fingerprint.test.ts +0 -162
- package/plugins/bizar/tests/http-client.test.ts +0 -404
- package/plugins/bizar/tests/init-helpers.test.ts +0 -203
- package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
- package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
- package/plugins/bizar/tests/key-rotation.test.ts +0 -396
- package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
- package/plugins/bizar/tests/loop.test.ts +0 -397
- package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
- package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
- package/plugins/bizar/tests/odin.test.ts +0 -125
- package/plugins/bizar/tests/options.test.ts +0 -329
- package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
- package/plugins/bizar/tests/safety.test.ts +0 -256
- package/plugins/bizar/tests/serve.test.ts +0 -339
- package/plugins/bizar/tests/settings.test.ts +0 -351
- package/plugins/bizar/tests/stall-think.test.ts +0 -750
- package/plugins/bizar/tests/state.test.ts +0 -276
- package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
- package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
- package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
- package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
- package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
- package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
- package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
- package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
- package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
- package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
- package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
- package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
- package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
- package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
- package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
- package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
- package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
- package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
- 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.
|