A TypeScript client for NullBoiler — generated from the OpenAPI 3.1 spec at nullboiler/docs/openapi.yaml (NullBoiler version 2026.3.2).
Closes the second half of P2-04 ("OpenAPI spec + generated client SDK for automation integrations") in NullBoiler's reference/todo.md. The spec lives in PR1 docs/openapi-spec; this repo is the working SDK that proves the spec generates a usable client.
No npm publish — install straight from GitHub:
npm install github:Kures/nullboiler-ts-sdk
# or
yarn add github:Kures/nullboiler-ts-sdkThe package builds itself on postinstall if dist/ is missing; or run npm run build once.
import { NullBoilerClient, StepType } from '@nullboiler/client';
const client = new NullBoilerClient({ baseUrl: 'http://localhost:8080' });
// 1. Health check
const health = await client.health.getHealth();
// 2. Submit a run
const created = await client.runs.createRun({
runCreate: {
steps: [{ id: 's1', type: StepType.Task, prompt_template: 'Reply with HELLO' }],
input: {},
},
idempotencyKey: 'demo-key-1',
});
// 3. Poll
let cur = await client.runs.getRun({ id: created.id });
while (cur.status === 'pending' || cur.status === 'running') {
await new Promise(r => setTimeout(r, 1000));
cur = await client.runs.getRun({ id: created.id });
}
// 4. Read events
const events = await client.events.listRunEvents({ id: created.id });A runnable copy lives at examples/quickstart.ts. To run it against the demo stack from this submission:
docker run --rm -v "$(pwd):/work" -w /work node:20 sh -c "npm install && npx tsx examples/quickstart.ts"The wrapper class exposes 11 typed API groups:
| Group | NullBoiler endpoints |
|---|---|
client.runs |
POST /runs, GET /runs/{id}, cancel, retry, replay, fork, resume, inject state, list |
client.workflows |
POST/GET/PUT/DELETE /workflows[/...], validate, mermaid export, run-by-id |
client.workers |
POST/GET/DELETE /workers[/...] |
client.steps |
GET /runs/{id}/steps[/{step_id}] |
client.events |
GET /runs/{id}/events, SSE GET /runs/{id}/stream |
client.checkpoints |
GET /runs/{id}/checkpoints[/{cp_id}] |
client.tracker |
GET /tracker/* (only when tracker is configured) |
client.admin |
POST /admin/drain, GET /rate-limits |
client.internal |
POST /internal/agent-events/{run}/{step} |
client.health |
GET /health |
client.metrics |
GET /metrics (Prometheus exposition) |
All response/request models preserve the original snake_case field names from the spec (no camel-case translation), so wire-format inspection in dev tools matches the TypeScript types.
const client = new NullBoilerClient({
baseUrl: 'http://orchestrator:8080',
token: process.env.NULLBOILER_TOKEN,
});When token is set, every request gets Authorization: Bearer <token>. NullBoiler's /health and /metrics accept anonymous requests; everything else requires auth when the orchestrator was started with --api-token.
The SDK ships with two layers of verification — both run in Docker, no host Node toolchain required.
docker run --rm -v "$(pwd):/work" -v ts-sdk-nm:/work/node_modules -w /work node:20 sh -c "npm install && npm test"Uses Node's built-in test runner (no separate test framework dependency) executed through tsx for TypeScript support. 11 tests cover Configuration, NullBoilerClient construction, header forwarding (Authorization, Idempotency-Key), enum exports, and snake_case wire-format round-trip. Fast, no network. The named volume ts-sdk-nm for node_modules works around Docker-on-Windows bind-mount slowness.
Each script runs against a live NullBoiler. Boot one (or use demo-stack/ from this submission) before:
| Script | What it checks |
|---|---|
verify:e2e |
At least one method from each of the 11 API groups (graceful soft-skip for endpoints not mounted on 2026.3.2: workflows, tracker, admin, checkpoints) |
verify:auth |
Bearer token: no-token → 401, wrong → 401, right → 200; /health stays public |
verify:errors |
404 on bogus run id; 503 on POST /runs after enableDrain() |
verify:sse |
text/event-stream content-type on /runs/{id}/stream; documents the Promise<string> generator quirk |
verify:regenerate |
Clean regenerate produces zero diff vs committed src/generated/ (build determinism) |
verify:all |
Runs e2e + auth + errors + sse in sequence |
Auth and error tests need a NullBoiler with --api-token=test-token-123 on port 8081. Spin one up with:
docker run -d --rm --name auth-nullboiler --user 0:0 -p 8081:8080 \
-v auth-nb-data:/nbdata \
-v "$(pwd)/test/nullboiler-auth-config.json:/nbdata/config.json:ro" \
ghcr.io/nullclaw/nullboiler:latest \
--host 0.0.0.0 --port 8080 --db /nbdata/nullboiler.db --config /nbdata/config.jsonstreamRunEventsreturnsPromise<string>instead of a real ReadableStream. This is atypescript-fetchtemplate limitation. Use rawfetchagainst/runs/{id}/streamfor true SSE; SDK is fine for "drain it once" patterns.- 5 endpoints are present in spec but not mounted on the published
ghcr.io/nullclaw/nullboiler:2026.3.2image:workflows/*,tracker/*,/rate-limits,/runs/{id}/checkpoints,/runs/{id}/stream(SSE). They will work against amain-branch build.
| This package | NullBoiler spec |
|---|---|
0.1.0 |
2026.3.2 |
The package's semver is independent of the spec version. The spec version baked into the SDK is whatever info.version was in spec/openapi.yaml at generation time.
The generator runs in Docker, no Node toolchain required on the host:
# 1. Replace spec/openapi.yaml with a newer copy
# 2. Regenerate
npm run regenerate
# (calls openapitools/openapi-generator-cli with the same flags used for v0.1.0)
# 3. Rebuild
npm run buildThe generator is pinned at the latest tag of openapitools/openapi-generator-cli. If you need a deterministic regenerate, replace :latest with a specific image digest in package.json.
This SDK is one of three submission artifacts to the NullClaw hackathon:
| Artifact | What |
|---|---|
docs/openapi-spec (PR1) |
The spec this SDK consumes |
feat/grafana-dashboards (PR2) |
Operational visibility for the same metrics this SDK can read via client.metrics.* |
Kures/nullboiler-ops-skills |
Agent skills that wrap the same operational loop |
MIT.