This guide shows an incremental setup:
- Use
nullclawonly for one-off work. - Add
nullTicketsfor durable backlog tracking and sequential autonomous execution. - Add an external orchestrator only when you need multi-agent coordination.
Use this when you want one task and one answer.
cd /path/to/nullclaw
zig build -Doptimize=ReleaseSmall
zig-out/bin/nullclaw onboard --interactive
zig-out/bin/nullclaw agent -m "Write a concise API design for expense tracking"This is the recommended starting point.
- You keep a durable queue of tasks in
nullTickets. - One worker loop processes tasks sequentially.
- No external orchestrator is required.
cd /path/to/nulltickets
zig build run -- --port 7700 --db runtime/nulltickets.dbIn another terminal:
BASE="http://127.0.0.1:7700"PIPELINE_PAYLOAD='{
"name": "sequential-work",
"definition": {
"initial": "todo",
"states": {
"todo": { "agent_role": "llm-executor", "description": "Ready to execute" },
"done": { "terminal": true, "description": "Completed" }
},
"transitions": [
{ "from": "todo", "to": "done", "trigger": "complete" }
]
}
}'
PIPELINE_ID=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d "$PIPELINE_PAYLOAD" \
"$BASE/pipelines" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
echo "PIPELINE_ID=$PIPELINE_ID"for i in $(seq 1 100); do
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"pipeline_id\":\"$PIPELINE_ID\",\"title\":\"Task #$i\",\"description\":\"Implement item #$i\",\"priority\":50}" \
"$BASE/tasks" >/dev/null
doneAny runtime (bash, Zig, Go, Python) can be used. The worker must do:
POST /leases/claimwithagent_idandagent_role.- On
204, sleep and retry. - On
200, runnullclawwith task title/description in prompt. POST /runs/{id}/eventsfor progress logs.POST /artifactsfor output file URI.POST /runs/{id}/transitionwith triggercomplete.- On failure,
POST /runs/{id}/fail.
This adapter is intentionally small. Replace with Zig/Go/Python when needed.
#!/usr/bin/env bash
set -euo pipefail
TRACKER_BASE="${TRACKER_BASE:-http://127.0.0.1:7700}"
ROLE="${1:?role required}" # llm-executor
AGENT_ID="${2:?agent id required}" # worker-1
MODEL="${3:-openrouter/anthropic/claude-sonnet-4}"
WORK_DIR="${WORK_DIR:-./runtime/executor-$ROLE}"
mkdir -p "$WORK_DIR"
while true; do
CLAIM=$(curl -s -X POST -H "Content-Type: application/json" \
-d "{\"agent_id\":\"$AGENT_ID\",\"agent_role\":\"$ROLE\",\"lease_ttl_ms\":300000}" \
"$TRACKER_BASE/leases/claim")
if [ -z "$CLAIM" ]; then
sleep 2
continue
fi
RUN_ID=$(printf '%s' "$CLAIM" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["run"]["id"])')
TASK_ID=$(printf '%s' "$CLAIM" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["task"]["id"])')
TOKEN=$(printf '%s' "$CLAIM" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["lease_token"])')
TITLE=$(printf '%s' "$CLAIM" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["task"]["title"])')
DESC=$(printf '%s' "$CLAIM" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["task"]["description"])')
OUT_FILE="$WORK_DIR/$RUN_ID.md"
PROMPT="Task: $TITLE
Description: $DESC
Return a concise, production-ready result."
if /path/to/nullclaw/zig-out/bin/nullclaw agent --model "$MODEL" -m "$PROMPT" > "$OUT_FILE"; then
curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-d "{\"kind\":\"step\",\"data\":{\"message\":\"completed\",\"output_file\":\"$OUT_FILE\"}}" \
"$TRACKER_BASE/runs/$RUN_ID/events" >/dev/null
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"task_id\":\"$TASK_ID\",\"run_id\":\"$RUN_ID\",\"kind\":\"result\",\"uri\":\"file://$OUT_FILE\"}" \
"$TRACKER_BASE/artifacts" >/dev/null
curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-d '{"trigger":"complete"}' \
"$TRACKER_BASE/runs/$RUN_ID/transition" >/dev/null
else
curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-d '{"error":"nullclaw execution failed"}' \
"$TRACKER_BASE/runs/$RUN_ID/fail" >/dev/null
fi
doneRun worker:
./worker.sh llm-executor worker-1 openrouter/anthropic/claude-sonnet-4A realistic sequential setup:
- Generate MVP scope with
nullclaw. - Convert scope into many tasks in
nullTickets. - Process tasks one by one with a single
llm-executorloop.
Generate scope:
cd /path/to/nullclaw
zig-out/bin/nullclaw agent -m "Give me MVP Scope for Team Expense Tracker (API + SQLite + web UI) with feature breakdown and acceptance criteria" > /tmp/mvp_scope.mdThen create tasks from scope (manual or scripted) and process sequentially in nullTickets.
You do not need an orchestrator for the baseline flow above.
Add one only if you need:
- Multiple agent pools (
dev,review,qa,devops) - Dynamic assignment and balancing
- Global retry/escalation policies