nexu-io/build-test
Run the project's build / typecheck / lint / test commands and emit the build.passing + tests.passing signals devloop convergence reads.
npx skills add https://github.com/nexu-io/open-design --skill build-test
Spec §20.2 / §22.4: the "subjective critique-theater panel" is
not enough on its own — a code-migration / tune-collab run must
prove the build still passes. This atom shells out to the
project's declared test commands and emits structured signals the
devloop's until evaluator reads.
code/index.json +plan.md's targetStack block).
testCommand='pnpm test'`).
| framework | typecheck | test |
| --- | --- | --- |
| next | pnpm typecheck | pnpm test |
| vite | pnpm typecheck | pnpm test |
| remix | pnpm typecheck | pnpm test |
| custom | (read from package.json.scripts) | (read from package.json.scripts) |
project-cwd/
└── critique/
├── build-test.json # { build: 'passing' | 'failing', tests: 'passing' | 'failing' | 'skipped', durationMs, commandsRun: [...], failures: [...] }
└── build-test.log # raw stdout / stderr (truncated to the runner's logBudgetBytes limit, default 1 MiB)
The atom emits two signals the devloop reads:
build.passing: boolean — the typecheck command exited 0.tests.passing: boolean — the test command exited 0.Plus the legacy critique.score so existing pipelines that read
the score keep working: 5 when both pass, 3 when only build
passes, 1 when both fail.
Pipelines wire the atom into a devloop:
{
"id": "verify",
"atoms": ["patch-edit", "build-test"],
"repeat": true,
"until": "(build.passing && tests.passing) || iterations >= 8"
}
always runs after patch-edit, and only when plan.steps's
current step is in completed state).
the rewrite-plan ownership rule.
tests: 'skipped' without a non-empty reason field.Implemented by the daemon runner in
apps/daemon/src/plugins/atoms/build-test.ts. It executes the configured
build and test commands, bounds runtime and captured logs, and persists the
report and log outputs above.
Take nexu-io/build-test from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.