Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Graph-based workflow orchestrator with unified state model for NullClaw AI bot a
| File | Role |
|------|------|
| `main.zig` | CLI args (`--port`, `--db`, `--config`, `--version`, `--export-manifest`, `--from-json`), HTTP accept loop, engine thread, tracker thread |
| `api.zig` | REST API routing and 30+ endpoint handlers (runs, workers, workflows, checkpoints, state, SSE stream, tracker) |
| `api.zig` | REST API routing and 30+ endpoint handlers (runs, workers, workflows, checkpoints, state, stream snapshots, tracker) |
| `store.zig` | SQLite layer, CRUD methods for all tables, schema migrations (4 migration files) |
| `engine.zig` | Graph-based state scheduler: tick loop, 7 node type handlers, checkpoints, reducers, goto, breakpoints, deferred nodes, reconciliation |
| `state.zig` | Unified state model: 7 reducer types (last_value, append, merge, add, min, max, add_messages), overwrite bypass, ephemeral keys, state path resolution |
Expand Down Expand Up @@ -46,7 +46,7 @@ Graph-based workflow orchestrator with unified state model for NullClaw AI bot a

```sh
zig build # build
zig build test # unit tests (320 tests)
zig build test # unit tests (355 tests)
zig build && bash tests/test_e2e.sh # e2e tests (requires Python 3 for mock workers)
./zig-out/bin/nullboiler --port 8080 --db nullboiler.db --config config.json
```
Expand All @@ -68,8 +68,8 @@ zig build && bash tests/test_e2e.sh # e2e tests (requires Python 3 for mock wo
| POST | `/workers` | Register worker |
| GET | `/workers` | List workers |
| DELETE | `/workers/{id}` | Remove worker |
| POST | `/runs` | Create workflow run (legacy step-array or graph format) |
| GET | `/runs` | List runs (supports ?status= filter) |
| POST | `/runs` | Create workflow run from legacy step-array format |
| GET | `/runs` | List runs (supports ?status= and ?workflow_id= filters) |
| GET | `/runs/{id}` | Get run details |
| POST | `/runs/{id}/cancel` | Cancel run |
| POST | `/runs/{id}/retry` | Retry failed run |
Expand All @@ -82,7 +82,7 @@ zig build && bash tests/test_e2e.sh # e2e tests (requires Python 3 for mock wo
| GET | `/runs/{id}/events` | List run events |
| GET | `/runs/{id}/checkpoints` | List checkpoints for run |
| GET | `/runs/{id}/checkpoints/{cpId}` | Get checkpoint details |
| GET | `/runs/{id}/stream` | SSE stream (supports ?mode=values\|updates\|tasks\|debug) |
| GET | `/runs/{id}/stream` | JSON stream snapshot (supports ?mode=values\|updates\|tasks\|debug\|custom and ?after_seq=) |
| POST | `/workflows` | Create workflow definition |
| GET | `/workflows` | List workflow definitions |
| GET | `/workflows/{id}` | Get workflow definition |
Expand Down Expand Up @@ -136,9 +136,12 @@ MQTT listener: (conditional, for async MQTT workers)
Redis listener: (conditional, for async Redis workers)
```

### SSE Streaming
### Stream Snapshots

5 modes for real-time consumption via `GET /runs/{id}/stream?mode=X`:
`GET /runs/{id}/stream` currently returns a JSON snapshot containing persisted
events and buffered in-memory stream events. It supports `mode=X` filtering and
`after_seq=N` cursors for independent consumers. The internal stream hub uses 5
modes:
- `values` -- full state after each step
- `updates` -- node name + partial state updates
- `tasks` -- task start/finish with metadata
Expand Down
134 changes: 134 additions & 0 deletions docs/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# NullBoiler HTTP API

This directory hosts the HTTP API contract for NullBoiler.

- **Source of truth:** [`docs/openapi.yaml`](../openapi.yaml) — OpenAPI 3.1
- **Maintainer roadmap reference:** [`reference/todo.md` P2-04](../../reference/todo.md)

The spec covers all 36 HTTP operations exposed by `src/api.zig` and all
domain types from `src/types.zig`.

## At a glance

| Group | Endpoints |
|---|---|
| Health, Metrics | `GET /health`, `GET /metrics` |
| Runs | `POST /runs`, `GET /runs`, `GET /runs/{id}`, `POST /runs/{id}/{cancel,retry,resume,replay,state}`, `POST /runs/fork` |
| Steps & Events | `GET /runs/{id}/steps`, `GET /runs/{id}/steps/{step_id}`, `GET /runs/{id}/events`, `GET /runs/{id}/stream` (JSON stream snapshot) |
| Checkpoints | `GET /runs/{id}/checkpoints`, `GET /runs/{id}/checkpoints/{cp_id}` |
| Workers | `POST /workers`, `GET /workers`, `DELETE /workers/{id}` |
| Workflows | full CRUD on `/workflows`, plus `validate`, `mermaid`, `run` |
| Tracker bridge | `GET /tracker/{status,tasks,stats,tasks/{id}}`, `POST /tracker/refresh` |
| Admin | `POST /admin/drain`, `GET /rate-limits` |
| Internal | `POST /internal/agent-events/{run_id}/{step_id}` (worker callback) |

## Quick start

### View the spec

```bash
# Redoc (no install — uses npx)
npx @redocly/cli preview-docs docs/openapi.yaml

# Swagger UI (Docker)
docker run --rm -p 8088:8080 \
-e SWAGGER_JSON=/spec/openapi.yaml \
-v "$(pwd)/docs:/spec" \
swaggerapi/swagger-ui
# then open http://localhost:8088
```

### Validate locally

```bash
# Python
python -m pip install openapi-spec-validator
python -m openapi_spec_validator docs/openapi.yaml

# Node
npx @apidevtools/swagger-cli validate docs/openapi.yaml

# Redocly (also runs lint rules beyond bare OpenAPI)
npx @redocly/cli lint docs/openapi.yaml
```

### Generate client SDKs

The spec is suitable for `openapi-generator-cli`. Recommended targets and
generators:

```bash
# TypeScript (fetch-based, browser & node)
npx @openapitools/openapi-generator-cli generate \
-i docs/openapi.yaml \
-g typescript-fetch \
-o sdks/typescript-fetch \
--additional-properties=npmName=@nullboiler/client,supportsES6=true,typescriptThreePlus=true

# Python (httpx async + sync)
npx @openapitools/openapi-generator-cli generate \
-i docs/openapi.yaml \
-g python \
-o sdks/python \
--additional-properties=packageName=nullboiler_client,projectName=nullboiler-client

# Go
npx @openapitools/openapi-generator-cli generate \
-i docs/openapi.yaml \
-g go \
-o sdks/go \
--additional-properties=packageName=nullboiler,withGoMod=true
```

For first-class language coverage we recommend publishing each SDK from
its own repository (e.g. `nullboiler/nullboiler-ts-sdk`) and pinning a
spec version per release tag.

## Conventions

- **Ids** — opaque strings; do not parse (currently 22-char ULIDs but
this is not part of the contract).
- **Timestamps** — `*_ms` fields are milliseconds since the Unix epoch
(UTC), `int64`.
- **Errors** — every 4xx/5xx response uses the same envelope:
```json
{"error": {"code": "<code>", "message": "<human readable>"}}
```
See `ErrorDetail.code` for the closed enum of codes.
- **Idempotency** — `POST /runs` honors `Idempotency-Key` (preferred) or
`idempotency_key` body field. Stored-workflow launches via
`POST /workflows/{id}/run` do not currently implement idempotency.
- **Auth** — bearer token; `/health` and `/metrics` are public so that
load balancers and Prometheus scrapers can reach them without
provisioning a token.

## Versioning the spec

The spec carries the same `info.version` as `GET /health` returns. When
the API surface changes:

1. Update `src/api.zig` and the matching tests.
2. Update `docs/openapi.yaml` and bump `info.version` in lockstep with
the next NullBoiler release.
3. Re-run `python -m openapi_spec_validator docs/openapi.yaml` (or the
Node equivalent) before committing.
4. Regenerate any vendored SDKs you ship.

A future enhancement (P2-03 in `reference/todo.md`) is to validate the
spec against a running orchestrator in CI by hitting every endpoint with
a smoke client.

## Provenance

This spec was authored from the source of truth files on the `main`
branch:

- `src/api.zig` — route table (`handleRequest`) and per-handler bodies
- `src/types.zig` — all enums and DB row types
- `src/strategy.zig` — strategy expansion semantics
- `src/workflow_validation.zig` and `src/engine.zig` — graph workflow shape
and validation rules
- `src/metrics.zig` — Prometheus exposition (used in `/metrics` example)

If you change one of those files, update this spec. CI does not yet
diff them, so the discipline is currently social.
Loading
Loading