# Null — full documentation > A family of single-binary Zig tools for running AI agents on your own hardware. Install NullHub, add components as you need them. No cloud, no runtime dependencies. --- # Start: What is the Null ecosystem > A family of single-binary Zig tools for running AI agents on your own hardware. Null is a family of small, single-binary tools for running AI agents locally, written in Zig 0.16.0. Each tool does one job, stores its state in local files, and talks plain JSON over HTTP — so you can take one dish or the full menu. ## The idea Most agent platforms are one large runtime that does everything. Null splits the kitchen into stations: | Component | Job | Where it lives | | --- | --- | --- | | [NullClaw](https://claw.nullmenu.ai/) | The agent runtime — executes the actual AI work | `~/.nullclaw` | | [NullHub](https://hub.nullmenu.ai/) | Control plane — installs, supervises and updates the rest | `~/.nullhub` | | [NullTickets](https://tickets.nullmenu.ai/) | Durable task state — what work exists and its status | SQLite, `~/.nulltickets` | | [NullBoiler](https://boiler.nullmenu.ai/) | Orchestration — decides what runs, when, on which worker | SQLite, `~/.nullboiler` | | [NullWatch](https://watch.nullmenu.ai/) | Observability — traces, evals, token usage, cost | JSONL, `~/.nullwatch` | | [NullPantry](https://pantry.nullmenu.ai/) | Shared knowledge and long-term agent memory | SQLite, `.nullpantry/` | | [NullDesk](https://desk.nullmenu.ai/) | Human review desk — diffs, approvals, audit trail | files in your workspace | | [nllclw](https://clw.nullmenu.ai/) | A minimal, readable standalone assistant | user config dir | Every component is a static binary. No Node, no Python, no external database — SQLite is vendored where needed. Nothing phones home; there is no hosted service behind any of this. ## How the pieces relate NullClaw is the chef: it connects 50+ model providers to 19 chat channels and runs the agent loop in a 678 KB binary using about 1 MB of RAM (measured by the project). Around it, the rest of the family handles what a single runtime shouldn't: NullTickets holds the backlog, NullBoiler applies scheduling policy, NullWatch records what happened, NullPantry remembers what the team knows, and NullDesk puts a human between agent output and your disk. NullHub ties it together. It is a manifest-driven install engine with an embedded dashboard: `nullhub install nullclaw` runs a wizard, and the same binary supervises processes, checks health, streams logs, and applies updates. Today it manages four components — NullClaw, NullBoiler, NullTickets and NullWatch. The others install separately. ## What Null is not - Not a cloud product. Everything binds to loopback by default and stores state locally. - Not a cryptocurrency project. NullClaw carries an explicit no-token, no-blockchain disclaimer. - Not 1.0. Versions are CalVer (`v2026.x.y`), and licensing varies by repo — NullClaw, NullHub, NullBoiler, NullTickets and nllclw are MIT; NullPantry, NullWatch, NullDesk, NullCap and NullBuilder have no license file yet. > [!NOTE] > Pre-1.0: config and CLI may change between releases. That applies to the whole family. ## Where to go next - [Choose your setup](/docs/start/choose-your-setup/) — one agent, or the full stack. - [Install NullHub](/docs/start/install-nullhub/) — the managed path. - [Install NullClaw directly](/docs/start/install-nullclaw-directly/) — the fastest path. - [Recipes](/docs/recipes/personal-assistant/) — real setups, composed from real parts. --- # Start: Choose your setup > Decide between a single agent, the managed stack, or the minimal sibling. There are three sensible entry points into the Null ecosystem. Pick by appetite: a single dish, the tasting menu, or the recipe card you can read in one sitting. ## Path 1: just the agent If you want one autonomous agent on one machine, install NullClaw directly. It is the smoothest install in the family — Homebrew, Docker, or a Nix flake — and it works entirely on its own: providers, channels, memory, tools, scheduling and a gateway in one binary. ```bash brew install nullclaw nullclaw onboard --api-key sk-... --provider openrouter nullclaw agent -m "Hello, nullclaw!" ``` Choose this if: you are exploring, you want a chat-channel assistant, or you are deploying to small hardware. See [Install NullClaw directly](/docs/start/install-nullclaw-directly/). ## Path 2: the managed stack If you want more than one component — orchestration, durable tasks, observability — start with NullHub. It installs and supervises the core four (NullClaw, NullBoiler, NullTickets, NullWatch), gives you one dashboard for status, logs, config and updates, and registers OS services. ```bash docker run --rm -p 19800:19800 -v nullhub-data:/nullhub-data ghcr.io/nullclaw/nullhub:latest ``` Choose this if: you plan to run agents continuously, you want updates with rollback, or several components need to talk to each other. See [Install NullHub](/docs/start/install-nullhub/). > [!NOTE] > NullHub manages NullClaw, NullBoiler, NullTickets and NullWatch today. NullPantry, NullDesk, NullCap and nllclw are installed separately — do not expect `nullhub install` to know them. ## Path 3: the minimal sibling If you want a complete assistant you can read end to end, [nllclw](https://clw.nullmenu.ai/) is a standalone implementation in about 21k lines of Zig: OpenAI-compatible providers, local memory, capability-gated tools, Telegram and WebSocket. Under 1 MB. Shell access is compiled out of the default binary. ```bash # download from https://github.com/nullclaw/nllclw/releases/latest chmod +x nllclw ./nllclw init ./nllclw "what are you?" ``` Choose this if: you want a small, auditable starting point rather than a platform. ## Matching goals to recipes | You want | Components | Recipe | | --- | --- | --- | | A personal assistant on Telegram/Discord/etc. | NullClaw | [Personal assistant](/docs/recipes/personal-assistant/) | | Agents that share a knowledge base | NullClaw + NullPantry | [Shared knowledge](/docs/recipes/shared-knowledge/) | | A backlog agents work through unattended | NullTickets + NullClaw | [Durable backlog](/docs/recipes/durable-backlog/) | | Multi-step workflows across several agents | NullBoiler + NullTickets + NullClaw | [Multi-agent workflow](/docs/recipes/multi-agent-workflow/) | | Traces, evals and cost per run | NullClaw + NullWatch (+ NullHub UI) | [Observable agent stack](/docs/recipes/observable-agent-stack/) | Whichever path you take, the components compose later. A standalone NullClaw can join a hub-managed stack; a hub-managed stack can shed pieces you stop using. > [!TIP] > All paths need nothing beyond the binary itself at runtime. If you can run a static executable, you can run the stack. --- # Start: Install NullHub > Get the control plane running via Docker, a release binary, or from source. NullHub is a single binary with an embedded dashboard that installs and supervises the rest of the stack. Three ways to get it; all end at the same place: `http://nullhub.localhost:19800`. ## Option A: Docker The quickest way to try it: ```bash docker run --rm -p 19800:19800 -v nullhub-data:/nullhub-data ghcr.io/nullclaw/nullhub:latest ``` Then open [http://nullhub.localhost:19800](http://nullhub.localhost:19800). The named volume keeps hub state across container restarts. ## Option B: release binary Prebuilt binaries for 7 targets are attached to each [GitHub release](https://github.com/nullclaw/nullhub/releases) — Linux (x86_64, aarch64, riscv64), macOS (x86_64, aarch64) and Windows (x86_64, aarch64). Download the one for your platform, make it executable, and run it: ```bash chmod +x nullhub-macos-aarch64.bin ./nullhub-macos-aarch64.bin ``` Running `nullhub` with no arguments starts the server and opens your browser. Where Bonjour or Avahi is available it publishes `nullhub.local` over mDNS and prefers that name; otherwise it falls back to `nullhub.localhost` and finally `127.0.0.1`. > [!NOTE] > There is no Homebrew formula for NullHub yet. `brew install` works for NullClaw only. ## Option C: build from source Requires Zig 0.16.0 exactly, plus npm for the embedded Svelte UI: ```bash git clone https://github.com/nullclaw/nullhub.git cd nullhub zig build ./zig-out/bin/nullhub ``` The UI is compiled into the binary — no `ui/build` directory needed at runtime. ## Runtime prerequisites NullHub uses `curl` and `tar` to download and unpack components. If they are missing, it auto-installs them through whatever package manager it finds (apt, dnf, yum, pacman, zypper, apk, brew, winget, choco). ## Run it as a service Once you are happy with it, register NullHub as an OS service so it survives reboots: ```bash nullhub service install nullhub service status ``` This writes a systemd unit on Linux or a launchd agent on macOS. `nullhub service uninstall` removes it. ## Check your install ```bash nullhub version nullhub status ``` `status` prints a table of managed instances — empty for now. All hub state lives under `~/.nullhub/` (config, instances, binaries, logs, cached manifests). > [!WARNING] > Pre-1.0: config and CLI may change between releases. Read the release notes before updating the hub itself. Next: [Run your first agent](/docs/start/run-your-first-agent/) — install NullClaw through the hub and talk to it. --- # Start: Run your first agent > Install NullClaw through NullHub, start it, and send it a message. With NullHub running, installing an agent is one command and a short wizard. This page takes you from an empty hub to a running NullClaw you can talk to. ## 1. Install NullClaw ```bash nullhub install nullclaw ``` This runs a terminal wizard: it downloads the component, walks you through provider and API-key setup, and writes the instance config. The web dashboard at `http://nullhub.localhost:19800` has the same wizard if you prefer clicking — installs are manifest-driven, so both paths produce the same result. ## 2. Start and check it ```bash nullhub start nullclaw/ nullhub status ``` `status` shows every managed instance with its health. For a single instance, `nullhub status nullclaw/` prints the detail view. The dashboard shows the same as status cards, refreshed by periodic health checks. Watch the logs while it boots — with a startup measured by the project at under 2 ms, don't blink: ```bash nullhub logs nullclaw/ -f ``` ## 3. Talk to it The agent binary is on your machine now, so you can use NullClaw's own CLI directly: ```bash nullclaw agent -m "Hello, nullclaw!" nullclaw agent # interactive chat ``` For a long-running agent — chat channels, scheduler, HTTP gateway — the instance runs `nullclaw gateway` under hub supervision, listening on `127.0.0.1:3000` by default. If it crashes, the hub restarts it with backoff. ## 4. Add the rest of the stack (optional) The same install command works for the other three managed components: ```bash nullhub install nullboiler # workflow orchestration nullhub install nulltickets # durable task tracking nullhub install nullwatch # traces, evals, cost ``` The wizard links components as it goes — a local NullTickets gets wired to NullBoiler automatically. Then bring everything up at once: ```bash nullhub start-all nullhub status ``` > [!TIP] > You can run several instances of the same component side by side — for example, two NullClaw instances with different providers. Each gets its own config and logs under `~/.nullhub/`. ## What just happened NullHub read each component's `nullhub-manifest.json`, which describes installation, configuration, launch, health checks and wizard steps. The hub is a generic engine that interprets manifests — which is also why it only manages components that publish one (NullClaw, NullBoiler, NullTickets, NullWatch today). ## Next steps - Wire channels and memory: [Personal assistant](/docs/recipes/personal-assistant/) - Give agents a durable backlog: [Durable backlog](/docs/recipes/durable-backlog/) - Keep it healthy: [Updates and rollback](/docs/operate/updates-and-rollback/) --- # Start: Install NullClaw directly > The fastest path — Homebrew, Docker, Nix, or build from source. No hub required. You don't need NullHub to run an agent. NullClaw is a standalone 678 KB static binary and has the easiest install in the family. This is the à la carte order. ## Homebrew ```bash brew install nullclaw nullclaw --help ``` ## Docker An official OCI image is published to GitHub Container Registry: ```bash docker run --rm -it -v nullclaw-data:/nullclaw-data ghcr.io/nullclaw/nullclaw:latest status ``` State lives in `/nullclaw-data` inside the container — the named volume keeps it. The repo also ships a Makefile wrapper around docker-compose (`make build`, `make config`, `make up`). ## Nix The repo carries a flake (`flake.nix`) if you are on Nix. ## Build from source Requires Zig 0.16.0 — exactly that version, not newer, not older: ```bash git clone https://github.com/nullclaw/nullclaw.git cd nullclaw zig build -Doptimize=ReleaseSmall zig build test --summary all ``` `ReleaseSmall` is what produces the 678 KB binary (size measured by the project). ## First run Onboard with a provider key, then talk: ```bash nullclaw onboard --api-key sk-... --provider openrouter nullclaw agent -m "Hello, nullclaw!" ``` `onboard` writes a single JSON config to `~/.nullclaw/config.json`. Prefer a guided setup? `nullclaw onboard --interactive` walks providers, channels and memory step by step. NullClaw speaks to 50+ providers — OpenRouter, Anthropic, OpenAI, Gemini, Ollama, Groq, Mistral, DeepSeek and others, plus any OpenAI-compatible endpoint. For a long-running assistant, start the gateway — HTTP API, chat channels, heartbeat and scheduler in one process: ```bash nullclaw gateway # 127.0.0.1:3000 by default ``` ## Health checks ```bash nullclaw status nullclaw doctor ``` `doctor` diagnoses config and environment problems; run it first when something misbehaves. ## Coming from OpenClaw? NullClaw's config format is OpenClaw-compatible, and there is a one-command migration: ```bash nullclaw migrate openclaw --dry-run nullclaw migrate openclaw ``` This imports config and memory. `--dry-run` shows what would change without touching anything. > [!NOTE] > Pre-1.0: config and CLI may change between releases — NullClaw's own README says so. Pin a version if that matters to you. ## Joining the stack later A directly-installed NullClaw composes with the rest of the family whenever you are ready: point its OTLP diagnostics at [NullWatch](/docs/recipes/observable-agent-stack/), give it a backlog with [NullTickets](/docs/recipes/durable-backlog/), or hand supervision to [NullHub](/docs/start/install-nullhub/). Full agent documentation lives at [claw.nullmenu.ai](https://claw.nullmenu.ai/). --- # Recipes: Personal assistant > One NullClaw, your chat apps, local memory. The simplest complete setup. The starter recipe: a single NullClaw instance that answers you on the chat apps you already use, remembers context locally, and runs as a background service. One binary, one config file, no other components. ## Ingredients - NullClaw ([installed directly](/docs/start/install-nullclaw-directly/) or [via NullHub](/docs/start/run-your-first-agent/)) - An API key for one of 50+ providers (OpenRouter is the quick default) - A chat channel — NullClaw supports 19, including Telegram, Discord, Signal, Slack, WhatsApp, Matrix, IRC and Email ## 1. Onboard ```bash nullclaw onboard --api-key sk-... --provider openrouter ``` Already onboarded and just want to add channels? There's a flag for that: ```bash nullclaw onboard --channels-only ``` The wizard writes channel credentials into `~/.nullclaw/config.json`. Inspect what you have: ```bash nullclaw channel list nullclaw channel status ``` ## 2. Start the gateway Channels only run inside the long-running runtime: ```bash nullclaw gateway ``` This starts the HTTP gateway on `127.0.0.1:3000`, connects your channels, and runs the heartbeat and cron scheduler. Message your bot from Telegram (or wherever) and it answers. > [!NOTE] > Gateway clients must exchange a one-time 6-digit pairing code for a bearer token, and chat channels have allowlists — a stranger finding your bot cannot just start using it. Details on the [security page](/docs/operate/security/). ## 3. Make it permanent Register it as an OS service (systemd or OpenRC) so it starts at boot: ```bash nullclaw service install nullclaw service status ``` If NullHub manages your instance, skip this — the hub already supervises it and restarts it on crashes. ## 4. Season to taste **Memory.** The default engine is hybrid search — SQLite FTS5 plus vector similarity — and it works out of the box. Look inside it: ```bash nullclaw memory stats nullclaw memory search "that restaurant in Lisbon" ``` `nullclaw memory forget` and `nullclaw memory export-jsonl` are there when you need them. **Schedules.** Recurring jobs — a morning summary, a nightly cleanup — run through built-in cron: ```bash nullclaw cron list ``` `cron add`, `once`, `pause`, `resume` and `run` manage entries; the scheduler runs inside the gateway. **Skills.** Packaged capabilities install from a registry: ```bash nullclaw skills list nullclaw skills install ``` ## Why this is enough For a single-user assistant you need no orchestrator, no task tracker, no separate memory service. Resource cost is small — around 1 MB of RAM, as measured by the project — so it runs happily on a Raspberry-class board next to the router. When one agent stops being enough, the upgrades are incremental: shared memory across agents is [Shared knowledge](/docs/recipes/shared-knowledge/), and unattended work is [Durable backlog](/docs/recipes/durable-backlog/). --- # Recipes: Shared knowledge > Give agents a common, permission-aware memory with NullPantry. By default each NullClaw instance keeps its own memory. This recipe moves long-term memory into NullPantry — a headless knowledge and memory server — so several agents share one larder: the same facts, the same knowledge graph, permission-aware retrieval with citations. ## Ingredients - One or more NullClaw instances - NullPantry — not hub-managed today, so it installs separately > [!WARNING] > NullPantry is early: one tagged release (v2026.06.09), and no license file yet. Read [the compatibility matrix](/docs/reference/compatibility-matrix/) before you build on it. ## 1. Start NullPantry The published Docker image is the quickest route: ```bash docker run --rm -p 8765:8765 \ -e NULLPANTRY_TOKEN=dev-secret \ ghcr.io/nullclaw/nullpantry:latest ``` Or from source (Zig 0.16.x; SQLite is vendored, nothing to install): ```bash git clone https://github.com/nullclaw/nullpantry.git cd nullpantry zig build run -- --db .nullpantry/nullpantry.db ``` The server listens on `127.0.0.1:8765`. Confirm it is up and self-describing: ```bash curl -H "Authorization: Bearer dev-secret" http://127.0.0.1:8765/v1/openapi.json ``` ## 2. Point NullClaw at it NullPantry exposes NullClaw-compatible agent-memory routes — `/v1/agent`, `/v1/memory`, `/v1/agent-memory`, `/v1/agent-sessions`. On the NullClaw side, memory engines are swappable, and one of the ten is an API backend: configure your instance's memory section to use it, with the pantry's base URL and bearer token. The exact config walkthrough — including named stores, scoped sharing, and the feed/checkpoint/apply flow — lives in NullPantry's own guide: [`docs/nullclaw-memory-integration.md`](https://github.com/nullclaw/nullpantry/blob/main/docs/nullclaw-memory-integration.md). Follow it rather than guessing keys; the config surface is still moving pre-1.0. Repeat for each agent that should share the store. Give each its own token: NullPantry supports per-token principals with distinct capabilities (read, propose, write, verify, delete, export, feed_apply), so a researcher agent can propose facts a reviewer agent must verify. ## 3. What you get - **Shared memory.** Agents on different machines recall the same atoms and sessions. - **Permission-aware retrieval.** An answer is only valid if every source, atom, relation and citation is visible to the requesting actor — the retrieval path enforces it. - **Lifecycle, not deletion.** Knowledge moves through proposed → verified → accepted → stale → deprecated → superseded. Decisions are superseded, never silently erased, so agents can see why things changed. - **Works offline.** Without any LLM provider configured, NullPantry uses deterministic local embeddings and extractive, citation-backed answers. ## Notes for operators - Auth is not optional off-loopback: NullPantry refuses unauthenticated non-loopback binds and enforces HTTPS for remote backends. - The default profile stores everything in a single SQLite file — back it up like any other component ([Backup and restore](/docs/operate/backup-and-restore/)). - Backends are chosen at compile time (Postgres records, pgvector/Qdrant/LanceDB vectors, Redis memory and more) — the default build needs none of them. Next course: give those knowledgeable agents actual work — [Durable backlog](/docs/recipes/durable-backlog/). --- # Recipes: Durable backlog > A task rail agents claim from, report to, and never lose — NullTickets plus NullClaw. An agent loop that dies mid-task should not lose the task. This recipe adds NullTickets — a headless task tracker backed by SQLite — so work survives crashes, retries are policy, and multiple agents can pull from one rail without stepping on each other. ## Ingredients - NullTickets (`nullhub install nulltickets`, or build from source) - One or more NullClaw instances as workers - No orchestrator — this is the deliberately simple baseline. Add [NullBoiler](/docs/recipes/multi-agent-workflow/) later if you need routing policy. ## 1. Start the tracker Via NullHub it is already supervised. From source: ```bash git clone https://github.com/nullclaw/nulltickets.git cd nulltickets zig build zig build run -- --port 7700 --db tracker.db ``` Defaults are `--port 7700` and `--db nulltickets.db`. Check it: ```bash curl http://127.0.0.1:7700/health curl http://127.0.0.1:7700/openapi.json ``` That second call matters: NullTickets is self-describing. It serves its own OpenAPI 3.1 schema at `/openapi.json` (and `/.well-known/openapi.json`) precisely so agents can bootstrap themselves against it. Task-creation and pipeline endpoints are all documented there. ## 2. Define a pipeline Pipelines are finite-state machines you declare over the REST API: states, transitions, terminal states. A minimal one is `queued → in_progress → done` with a `failed` branch. Attach a retry policy — `max_attempts`, `retry_delay_ms`, and optionally a dead-letter stage for runs that keep failing. Tasks can also declare dependencies (DAG edges): a blocked task is excluded from claiming until its upstream tasks reach a terminal stage. ## 3. Run the claim loop The tracker contract is three moves, and any runtime that speaks it can be a worker: 1. **Claim** — `POST /leases/claim` with the agent's role. The lease has a TTL and returns a bearer lease token; heartbeat it while working. 2. **Report** — append progress events to the run's timeline; attach artifacts. 3. **Transition or fail** — move the task to its next stage, with optimistic checks (`expected_stage`, `expected_task_version`) so two agents can't finish the same task twice. Double-claiming is prevented at the SQL layer (`BEGIN IMMEDIATE` transactions), lease tokens are stored as SHA-256 hashes, and a worker that vanishes simply lets its lease expire — the task returns to the pool. That is the durability: no supervisor process, just state that outlives everyone. The practical NullClaw wiring — prompts and patterns for running the loop with `nullclaw` as executor — lives in the tracker repo's [`nullclaw.md`](https://github.com/nullclaw/nulltickets/blob/main/nullclaw.md) integration guide. ## 4. Watch the queue ```bash curl http://127.0.0.1:7700/ops/queue ``` Per-role queue stats, made for dashboards and orchestrators. NullHub also proxies the tracker's shared key-value store into its dashboard — a namespaced KV with SQLite FTS5 full-text search that doubles as cross-session agent memory. > [!TIP] > NullTickets ingests OTLP traces too (`/v1/traces`), and spans carrying `nulltickets.run_id` / `nulltickets.task_id` attributes get linked to their tasks. Pair this with [the observable stack](/docs/recipes/observable-agent-stack/) and every ticket knows its own story. When one queue and role-based claiming stop being enough — fan-out, multi-stage routing, worker capacity — graduate to the [multi-agent workflow](/docs/recipes/multi-agent-workflow/). --- # Recipes: Multi-agent workflow > Graph workflows across a worker fleet — NullBoiler over NullTickets and NullClaw. The full brigade: NullTickets holds the truth, NullBoiler decides what runs where, NullClaw instances do the cooking. This recipe wires all three into graph-based workflows with checkpoints, fan-out and replay. ## The separation of concerns | Layer | Component | Owns | | --- | --- | --- | | Truth | NullTickets | What work exists, its state, its history | | Policy | NullBoiler | What runs, when, on which worker | | Execution | NullClaw | Actually doing the work | Each layer is optional — that is the point of the split. This recipe uses all three. ## 1. Bring up the stack With NullHub, install all three (`nullhub install nulltickets`, `nullboiler`, `nullclaw`) — the wizard links a local NullTickets to NullBoiler automatically. From source, NullBoiler starts like this: ```bash zig build ./zig-out/bin/nullboiler --port 8080 --db nullboiler.db --config config.json ``` The repo also ships a `docker-compose.yml` with profiles for the full NullTickets + NullBoiler + NullClaw stack. ## 2. Configure workers and the tracker NullBoiler's JSON config (default `~/.nullboiler/config.json`; a `config.example.json` ships in the repo) declares your fleet and, optionally, pull-mode against the tracker: ```json { "port": 8080, "db": "nullboiler.db", "workers": [ { "id": "claw-main", "url": "http://127.0.0.1:3000", "protocol": "a2a", "tags": ["coder"], "max_concurrent": 2 } ], "tracker": { "url": "http://127.0.0.1:7700" } } ``` Workers speak one of four HTTP protocols — `webhook`, `api_chat`, `openai_chat`, `a2a` — plus async dispatch over MQTT or Redis Streams. NullClaw is the reference runtime (webhook or A2A); ZeroClaw, PicoClaw (via a bundled bridge) and any OpenAI-compatible gateway also qualify. Selection is by tags and capacity, with per-worker retries, backoff, health checks and drain mode. With a `tracker` section, NullBoiler runs pull-mode: it polls NullTickets, claims tasks, heartbeats leases, detects stalls, and manages per-task workspaces. ## 3. Define a workflow Workflows are graphs with 7 node types — `task`, `agent`, `route`, `interrupt`, `send`, `transform`, `subgraph` — over a shared state with reducers, checkpointed after every node. File-based workflows live as JSON in `workflows/` and hot-reload. Validate before running: ```bash zig build run -- validate-workflows ``` Errors exit 1; warnings pass. Then create a run over the API: ```bash curl -sS -X POST http://127.0.0.1:8080/runs \ -H 'Content-Type: application/json' \ -d '{"input": {...}, "steps": [...]}' ``` The REST API has 30+ endpoints (runs, workflows, workers, checkpoints, streams, tracker) described by an OpenAPI 3.1 spec — see [APIs and OpenAPI](/docs/reference/apis-and-openapi/). ## 4. Use the grown-up features - **Fan-out**: a `send` node maps over `items_key` — one node, N parallel branches. - **Interrupts**: `interrupt_before`/`interrupt_after` pause a run for human input; inject state and resume. - **Replay and forking**: rerun any run from any checkpoint. - **Overnight mode**: the built-in loop strategy iterates (up to 1000 times) until a worker returns `BACKLOG_DONE` — a backlog-burning agent that runs while you sleep. - **Metrics**: Prometheus `/metrics` out of the box, with Grafana dashboards and AlertManager rules in the repo. > [!NOTE] > Pre-1.0: config and CLI may change between releases. Workflow JSON is validated at load, so `validate-workflows` in CI is cheap insurance. To see what your fleet actually did — spans, cost, verdicts — add [the observable stack](/docs/recipes/observable-agent-stack/). --- # Recipes: Observable agent stack > Traces, evals and cost per run — NullClaw into NullWatch, rendered by NullHub. Agents fail quietly unless something writes down what happened. This recipe adds NullWatch — a sub-megabyte local OTLP sink with evals built in — and NullHub's Flight Recorder UI on top. Every span, verdict and dollar stays on your machine as JSONL. ## Ingredients - A running NullClaw (any install path) - NullWatch (`nullhub install nullwatch`, a [release binary](https://github.com/nullclaw/nullwatch/releases), or source) - Optionally NullHub, for the UI ## 1. Start NullWatch Hub-installed instances are already running. From source: ```bash git clone https://github.com/nullclaw/nullwatch.git cd nullwatch zig build run -- serve ``` The JSON HTTP API listens on `127.0.0.1:7710` (`--host`/`--port` to change). Check it: ```bash curl http://127.0.0.1:7710/health ``` ## 2. See it working before wiring anything NullWatch ships a deterministic demo dataset — no API keys, no agent workload: ```bash zig build run -- demo-seed zig build run -- runs --limit 20 ``` `demo-seed` is idempotent and creates three recognizable runs: a passing code-review, a failed tool call, and a handoff with retries. Useful for checking the whole pipeline, including the UI, before any real traffic. ## 3. Point NullClaw at it NullWatch accepts OTLP/HTTP JSON traces on `/v1/traces` (also `/otlp/v1/traces`), so it works as a tiny local OpenTelemetry sink. Point NullClaw's OTLP diagnostics endpoint at `http://127.0.0.1:7710/v1/traces` — see the ops section of [NullClaw's docs](https://claw.nullmenu.ai/) for the config key. Model calls, tool invocations, retries and memory lookups arrive as spans; NullWatch computes run-level summaries: latency, errors, token usage, cost, pass/fail verdicts. Eval results (scorers, rubrics, regression checks) ingest through `/v1/evals`, or from the command line: ```bash nullwatch ingest-eval --json '' ``` There is also a community Python SDK, `nullwatch-python-sdk`, with zero required dependencies and built-in scorers for RAG hallucination detection and tool-call schema validation. ## 4. Add the Flight Recorder UI NullWatch is deliberately headless. NullHub renders the UI: install NullWatch through the hub (or set `NULLWATCH_URL=http://127.0.0.1:7710` for an existing one) and open the dashboard's Flight Recorder page — run summaries, span timelines, eval results, token usage, cost, error context. The hub proxies your local NullWatch; nothing is sent to any hosted service. ## 5. Query from the terminal The CLI covers the same ground as the API: ```bash nullwatch summary nullwatch runs --verdict fail --limit 10 nullwatch run nullwatch spans --tool-name shell nullwatch evals --dataset regression ``` Data lives as JSONL under `~/.nullwatch/data` — greppable, backupable, yours. > [!NOTE] > NullWatch is the youngest of the hub-managed four: one release, and its README calls it a bootstrap implementation — intentionally small but already usable. No license file yet. Sizes are small even by family standards: 313–653 KB per platform, as measured by the project. Related: NullTickets [ingests OTLP too](/docs/recipes/durable-backlog/) and links spans to tasks — run both sinks and you get observability stitched to your backlog. --- # Operate: Updates and rollback > Keep components current with NullHub, and recover when an update misbehaves. Everything in the family is versioned with CalVer (`v2026.x.y`) and pre-1.0, so updates deserve a little ceremony. NullHub handles the mechanics for managed components; the rest update the way they were installed. ## Hub-managed components Check what is stale, then update: ```bash nullhub check-updates nullhub update nullclaw/ nullhub update-all ``` An update downloads the new binary, migrates the instance config, and — if anything fails — rolls back to the previous version. That rollback is built in; you don't have to arrange it. The dashboard exposes the same one-click updates with the same migration-and-rollback behavior. > [!WARNING] > Pre-1.0 means config and CLI may change between releases across the whole family. Skim the release notes on GitHub before `update-all` on a stack you care about. CalVer tags tell you when something was released, not how mature it is. ## NullHub itself The hub does not update itself through `nullhub update`. Refresh it the way you installed it: - **Docker**: pull the new image and recreate the container. State survives in the `nullhub-data` volume. ```bash docker pull ghcr.io/nullclaw/nullhub:latest ``` - **Release binary**: download the new binary from [GitHub releases](https://github.com/nullclaw/nullhub/releases) and replace the old one. State lives under `~/.nullhub/`, separate from the binary. - **Source**: `git pull && zig build`. If you registered an OS service (`nullhub service install`), restart it after replacing the binary. ## Standalone NullClaw NullClaw has a self-updater: ```bash nullclaw update --check # see what's available nullclaw update --yes # apply without prompting ``` If you installed via Homebrew, update through Homebrew instead, so the formula and binary stay in sync. Docker installs update by pulling the newer image tag. ## Non-managed components NullPantry, nllclw, NullDesk and NullCap are outside the hub's reach: | Component | Update path | | --- | --- | | NullPantry | Pull a newer image: `docker pull ghcr.io/nullclaw/nullpantry:latest` (or a pinned tag like `v2026.06.09`); or rebuild from source | | nllclw | Download the newer release binary and replace | | NullDesk, NullCap | No releases yet — `git pull` and rebuild | ## Rolling back by hand For anything the hub does not manage, rollback is manual but simple because state and binary are separate: 1. Stop the component. 2. Put back the previous binary (or pin the previous image tag — CalVer tags like `v2026.5.29` stay available). 3. Restore the component's state directory from [backup](/docs/operate/backup-and-restore/) if the newer version migrated data. 4. Start it and verify with its health check (`nullclaw doctor`, `curl .../health`). Step 3 is the one people skip. A newer version may have rewritten SQLite schemas or config keys; an old binary reading new state is undefined territory. Back up before updating and rollbacks stay boring. ## A sensible cadence Nightly builds exist (NullClaw publishes rolling prereleases) but tagged releases are the ones to run. Update the hub first, then managed components via `update-all`, then standalone pieces. One course at a time. --- # Operate: Backup and restore > Every component stores state in local files. Know where, copy them, sleep well. No component in the family uses an external database or a cloud store. State is files in predictable places — which makes backup a matter of knowing the places. ## Where state lives | Component | State | Contents | | --- | --- | --- | | NullHub | `~/.nullhub/` | Config, instances, downloaded binaries, logs, cached manifests, Mission Control replays | | NullClaw | `~/.nullclaw/` | `config.json` (providers, channels, secrets), memory (SQLite by default), workspaces | | NullBoiler | `~/.nullboiler/` + its SQLite db | Config, workflow files, run/checkpoint state | | NullTickets | `~/.nulltickets/` + its SQLite db | Config; the db holds pipelines, tasks, leases, events, KV store | | NullWatch | `~/.nullwatch/` | `config.json` plus `data/` — spans, runs, evals as JSONL | | NullPantry | `.nullpantry/nullpantry.db` | Knowledge, memory atoms, vectors (default profile) | | nllclw | user config + state dirs | `~/.config/nllclw/config.json`; state in the platform state dir | | NullDesk | `/.nulldesk/` | Tasks, patches, memory, artifacts, `events.jsonl` audit log | Docker installs keep the same state in named volumes: `nullhub-data`, `nullclaw-data`, and for NullPantry's container, `/var/lib/nullpantry`. Instance homes are movable: `NULLBOILER_HOME` and `NULLTICKETS_HOME` relocate those components' directories, `--home` does it for NullPantry. If you set these, your backup paths move too. ## Taking a backup SQLite databases (NullTickets, NullBoiler, NullClaw memory, NullPantry) should not be copied mid-write — NullBoiler runs WAL mode, and a half-copied WAL is a corrupt restore. Stop first: ```bash nullhub stop-all ``` Then copy the directories with whatever you trust: ```bash tar czf null-backup-$(date +%F).tar.gz \ ~/.nullhub ~/.nullclaw ~/.nullboiler ~/.nulltickets ~/.nullwatch ``` Bring everything back up: ```bash nullhub start-all && nullhub status ``` For Docker volumes, run a throwaway container that tars the volume, or use your volume-backup tooling of choice. > [!WARNING] > `~/.nullclaw/config.json` contains provider API keys and channel credentials, and other components' configs hold API tokens. Treat backups as secrets: encrypt them, and keep them off shared storage. See [Secrets and networking](/docs/operate/secrets-and-networking/). > [!TIP] > NullWatch's JSONL files are append-only, which makes them friendly to incremental backup tools — only new lines change. NullDesk's `events.jsonl` behaves the same way. ## Restoring 1. Stop everything (`nullhub stop-all`, plus any standalone components). 2. Unpack the backup over the state directories. 3. Match binary versions to the backup: state written by `v2026.5.29` should be read by `v2026.5.29`. Pre-1.0, schema compatibility across versions is not promised. Pin image tags or keep old release binaries around. 4. Start and verify: `nullhub status`, `nullclaw doctor`, `curl` the health endpoints. ## What you can skip - `~/.nullhub/` cached binaries — the hub re-downloads them. - Logs, unless you want the history. - Anything reproducible from your own git repos (NullBoiler workflow JSON is better versioned in git than in backups — it hot-reloads from `workflows/` anyway). The one file to never skip: the NullTickets database. It is the source of truth for what your agents were doing — lose it and the backlog is gone, which rather defeats [the durable backlog](/docs/recipes/durable-backlog/). --- # Operate: Secrets and networking > Default ports, loopback-first binding, tokens, CORS and tunnels across the stack. The family's networking posture is consistent: bind to loopback, require tokens for anything that mutates, and make you opt in explicitly before anything is reachable from elsewhere. ## Default ports | Component | Default bind | Purpose | | --- | --- | --- | | NullHub | `nullhub.localhost:19800` | Dashboard + API | | NullClaw gateway | `127.0.0.1:3000` | HTTP gateway, channels, scheduler | | NullBoiler | `:8080` (quickstart) | Orchestrator REST API | | NullTickets | `:7700` | Tracker REST API | | NullWatch | `127.0.0.1:7710` | Ingest + query API | | NullPantry | `127.0.0.1:8765` | Knowledge/memory API | | nllclw WebSocket | `ws://127.0.0.1:8765/ws` | Local UI channel | > [!NOTE] > NullPantry and nllclw's WebSocket channel both default to port 8765. If you run both on one machine, move one (`--port` for NullPantry). ## Tokens Each service has its own token story; none of them shares a global credential. | Component | Mechanism | | --- | --- | | NullHub | Optional bearer-token auth; per-proxy tokens via `NULLBOILER_TOKEN`, `NULLTICKETS_TOKEN`, `NULLWATCH_TOKEN` | | NullClaw | `NULLCLAW_GATEWAY_TOKEN` and `NULLCLAW_WEB_TOKEN`; secrets in config encrypted with ChaCha20-Poly1305 | | NullBoiler | `api_token` in config; per-worker tokens in the `workers` array | | NullTickets | `api_token`, plus per-lease bearer tokens (stored server-side as SHA-256 hashes) | | NullWatch | Optional `api_token` in `~/.nullwatch/config.json` | | NullPantry | `NULLPANTRY_TOKEN` / `NULLPANTRY_TOKEN_PRINCIPALS` — per-token actors with scoped capabilities | | nllclw | WebSocket token required even on loopback | NullPantry is the strictest of the set: it refuses to bind off-loopback without auth at all (there is a `--allow-no-auth-non-loopback` flag; its name is the warning), and requires HTTPS for remote backends. ## Provider API keys Model-provider keys live in NullClaw's config (`~/.nullclaw/config.json`, written by `nullclaw onboard`) or nllclw's config/env. Two implications: - Back these files up encrypted — see [Backup and restore](/docs/operate/backup-and-restore/). - Components downstream of NullClaw never need provider keys. NullBoiler dispatches to workers by URL and worker token; NullCap by design stores no provider keys and talks only to NullHub on `127.0.0.1:19800`. ## Exposing things deliberately **CORS on the hub.** If a browser app on another origin needs the hub API: ```bash nullhub serve --allowed-origin https://your.origin ``` or set `NULLHUB_ALLOWED_ORIGINS` (comma-separated). **Reaching an agent from outside.** Do not port-forward the gateway. NullClaw has first-class tunnel support — Cloudflare Tunnel, Tailscale, ngrok, or a custom tunnel — configured in its `tunnel` section, so the machine never accepts inbound connections directly. **Hub reverse proxies.** The dashboard reaches NullBoiler, NullTickets and NullWatch through `NULLBOILER_URL`, `NULLTICKETS_URL`, `NULLWATCH_URL` — those services can stay bound to loopback while the hub fronts them. **Bind addresses.** `NULLCLAW_BIND` / `NULLCLAW_PORT` control the gateway; NullWatch and NullPantry take `--host`/`--port`. Binding to `0.0.0.0` is a decision, not a default — set the relevant token first. > [!WARNING] > Every default in this table assumes a single-user machine. The moment a second user or a second host enters the picture, set tokens everywhere. They exist for exactly that moment. For sandboxing, pairing codes and the rest of the trust model, continue to [Security](/docs/operate/security/). --- # Operate: Security > Sandboxing, pairing, encrypted secrets and the trust model across the family. Autonomous agents run tools, read files and talk to strangers on chat networks. The family's answer is layered: gate who can talk to an agent, constrain what the agent can touch, and record what it did. This page describes those layers as the projects document them — self-reported, pre-1.0, not independently audited. ## Who can talk to an agent - **Pairing codes.** NullClaw's gateway hands out bearer tokens only in exchange for a one-time 6-digit pairing code (`POST /pair`) — reaching the port is not enough. - **Allowlists.** Channels restrict who may interact; nllclw's Telegram channel is allowlist-only by chat id or username. - **Tokens on every API.** See [Secrets and networking](/docs/operate/secrets-and-networking/) for the per-component table. ## What the agent can touch NullClaw runs tools under multi-backend sandboxing — Landlock, Firejail, Bubblewrap, or Docker, depending on what the host offers — with workspace scoping so an agent operates inside its own directory rather than your home. Each agent profile gets its own workspace and memory namespace. nllclw takes the compile-time route: the shell tool exists only in a `-Dshell-tool=true` build and is absent from the default binary; filesystem tools are capability-gated, restricted to CWD-relative paths, and secret-looking paths (`.env`, `.ssh`, `.aws`, private keys) are denied outright. NullDesk adds the human boundary for code work: agents cannot write files directly — every change is a reviewable patch, shell commands carry low/medium/high risk classification, and high-risk patterns (`curl | sh`, `rm -rf`) are architecturally blocked from approval, not just flagged. ## Secrets at rest NullClaw encrypts stored secrets with ChaCha20-Poly1305. NullTickets never stores lease tokens in plaintext — SHA-256 hashes only. NullPantry sanitizes child-process environments before invoking external CLIs. Config files still hold what they hold: treat `~/.nullclaw/config.json` and friends as sensitive files with appropriate permissions and encrypted backups. ## Who may know what NullPantry's retrieval is permission-aware end to end: bearer tokens map to principals with distinct capabilities (read, propose, write, verify, delete, export, feed_apply), and an answer is only valid if every source, atom, relation, chunk and citation is visible to the requesting actor. Agents with different clearances can share one knowledge base without leaking across the boundary. ## What actually happened - NullClaw keeps a signed audit log. - NullDesk appends every task, run, file read, review, approval, command and commit to `events.jsonl` — append-only. - NullWatch and NullTickets record spans and run events, useful as a forensic timeline as much as an ops tool. ## Network posture Loopback-first everywhere; nothing is exposed by default, and nothing reports to a hosted service — there isn't one. Exposure is explicit: tunnels for agents, `--allowed-origin` for the hub, and NullPantry flatly refuses unauthenticated non-loopback binds. > [!WARNING] > These mechanisms are the projects' own descriptions of their behavior. Pre-1.0 software changes; no third-party audit exists yet. Size your trust accordingly — and for anything sensitive, add your own outer layer (VM, container, dedicated user) around the agent's sandbox. ## Reporting NullClaw ships a `SECURITY.md` in its repository with the disclosure process. For other components, open an issue on the relevant [nullclaw org repo](https://github.com/nullclaw) — or better, a private report if the repo has security advisories enabled. --- # Operate: Troubleshooting > The diagnostic tour — health checks, logs, and the failures people actually hit. Most problems in the stack yield to the same four moves: check status, read logs, run the doctor, curl the health endpoint. Start here before opening an issue. ## The diagnostic tour ```bash nullhub status # all managed instances at a glance nullhub logs nullclaw/ -f # follow a misbehaving instance nullclaw doctor # agent-side diagnostics curl http://127.0.0.1:7700/health # nulltickets curl http://127.0.0.1:7710/health # nullwatch ``` The dashboard shows the same health data as status cards, and streams logs live over SSE. For poking the hub's API directly: ```bash nullhub api GET /api/... --pretty ``` ## Common failures ### The dashboard won't open `nullhub` prefers `nullhub.local` (published over mDNS), then falls back to `nullhub.localhost`, then `127.0.0.1` — if a hostname fails, try `http://127.0.0.1:19800` directly. Behind Docker, confirm you published the port (`-p 19800:19800`). The `nullhub.local` name only exists where Bonjour/Avahi mDNS is available. ### Build from source fails immediately Check your Zig version first. Every repo in the family pins **Zig 0.16.0 exactly** — not 0.15.x, not whatever is newer. `zig version` before anything else. NullHub additionally needs npm at build time for its embedded UI. ### Component install fails in the hub NullHub downloads with `curl` and unpacks with `tar`, auto-installing them if missing via your package manager. On a minimal container image with no package manager, install both by hand first. Also confirm the component is one the hub can manage: NullClaw, NullBoiler, NullTickets, NullWatch — nothing else has a manifest today. ### Port already in use Check the [default port table](/docs/operate/secrets-and-networking/). The classic collision: NullPantry and nllclw's WebSocket both default to 8765. Everything takes a `--port` or config equivalent. ### The agent starts but won't answer `nullclaw doctor`, then `nullclaw status`. Usual suspects: an invalid or unfunded provider API key, or channels configured but the gateway not running (channels only live inside `nullclaw gateway`). Verify channels with `nullclaw channel status`. ### Workflow won't run in NullBoiler Validate before blaming the engine: ```bash zig build run -- validate-workflows ``` Errors exit 1 with details. If workers never pick tasks up, check worker health in the API, tags matching between workflow and worker, and `max_concurrent` — a saturated worker looks a lot like a broken one. ### Tasks stuck in NullTickets `curl http://127.0.0.1:7700/ops/queue` shows per-role queue depth. A task that is claimed but not moving usually has a live lease from a dead worker — leases expire on TTL, so it will return to the pool. Blocked tasks with unmet dependencies are excluded from claiming by design. ### Nothing showing in NullWatch Seed known-good data to split the problem in half: ```bash nullwatch demo-seed && nullwatch runs --limit 20 ``` If demo runs appear, ingestion and storage work — the problem is on the sending side (NullClaw's OTLP endpoint config, or a mismatched `api_token`). ### After an update, config errors Pre-1.0: config and CLI may change between releases. Hub-managed updates migrate config and roll back on failure; manual updates don't. Restore from [backup](/docs/operate/backup-and-restore/) and match binary versions to state. ## Still stuck Each component's repo has issues open to the public — [github.com/nullclaw](https://github.com/nullclaw). Attach the output of the diagnostic tour above; it answers the first five questions anyone will ask. --- # Reference: CLI reference > Every documented command across the family, one component per table. The family's command surfaces, as documented by each project at its latest release. Deep flag documentation lives on each product's own site; this page is the cross-stack index. > [!NOTE] > Pre-1.0: config and CLI may change between releases. When in doubt, `--help` on your installed binary outranks this page. ## nullhub | Command | Does | | --- | --- | | `nullhub` | Start server and open the dashboard | | `nullhub serve [--host H] [--port N] [--allowed-origin ORIGIN]` | Start server with explicit binding/CORS | | `nullhub install ` | Terminal install wizard | | `nullhub uninstall /` | Remove an instance | | `nullhub start\|stop\|restart /` | Instance lifecycle (also `start-all` / `stop-all`) | | `nullhub status [/]` | All instances, or one in detail | | `nullhub logs / [-f]` | Tail logs; `-f` to follow | | `nullhub check-updates` | Version checks across instances | | `nullhub update /` / `update-all` | Update with config migration and rollback | | `nullhub config / [--edit]` | View or edit instance config | | `nullhub api GET /api/... --pretty` | Raw API access from the CLI | | `nullhub service install\|uninstall\|status` | systemd/launchd service management | | `nullhub version` | Print version | `/` is `component/instance-name` — multi-instance is first-class. ## nullclaw | Command | Does | | --- | --- | | `nullclaw onboard` | Setup wizard (`--api-key`/`--provider`, `--interactive`, `--channels-only`) | | `nullclaw agent [-m "..."]` | Chat: one message with `-m`, interactive without | | `nullclaw gateway` | Long-running runtime: HTTP gateway, channels, heartbeat, scheduler (default `127.0.0.1:3000`) | | `nullclaw channel list\|info\|start\|status\|add\|remove` | Manage messaging channels | | `nullclaw service install\|start\|stop\|restart\|status\|uninstall` | Background service (systemd/OpenRC) | | `nullclaw cron list\|add\|once\|remove\|pause\|resume\|run` | Scheduled tasks | | `nullclaw memory stats\|search\|export-jsonl\|forget\|reindex` | Inspect and maintain memory | | `nullclaw skills list\|install\|remove\|info` | Skill packs with registry search | | `nullclaw status` / `nullclaw doctor` | System status, diagnostics | | `nullclaw acp` | Agent Client Protocol stdio adapter for editors | | `nullclaw hardware scan\|flash\|monitor` | Hardware device management | | `nullclaw migrate openclaw [--dry-run]` | Import config and memory from OpenClaw | | `nullclaw auth login\|status\|logout` | OAuth authentication | | `nullclaw update [--check] [--yes]` | Self-update | ## nullboiler | Command | Does | | --- | --- | | `nullboiler --config --port --db ` | Start the orchestrator HTTP server | | `nullboiler validate-workflows [dir]` | Preflight-validate workflow JSON (errors exit 1, warnings pass) | | `nullboiler --version` | Print version | | `nullboiler --export-manifest` | Export the NullHub manifest | | `nullboiler --from-json` | Import a workflow from JSON | ## nulltickets NullTickets is a headless HTTP service, not a multi-command CLI: | Invocation | Does | | --- | --- | | `zig build run -- --port 7700 --db tracker.db` | Start the server | | `--port` (default 7700), `--db` (default `nulltickets.db`), `--config ` | The documented flags | | `zig build test` / `bash tests/test_e2e.sh` | Unit and end-to-end tests | Everything else happens over its [REST API](/docs/reference/apis-and-openapi/). ## nullwatch | Command | Does | | --- | --- | | `nullwatch serve` | JSON HTTP API server (default `127.0.0.1:7710`; `--host`/`--port`) | | `nullwatch summary` | Aggregate summary | | `nullwatch runs [--verdict V] [--limit N]` | List runs | | `nullwatch run ` | Inspect one run | | `nullwatch spans [--source S] [--tool-name T] [--limit N]` | List spans | | `nullwatch evals [--dataset D] [--verdict V]` | List evals | | `nullwatch ingest-span --json ''` / `ingest-eval --json ''` | Ingest from the CLI | | `nullwatch demo-seed` | Seed deterministic, idempotent demo data | | `nullwatch --export-manifest` / `--from-json ''` | NullHub manifest / config bootstrap | ## nllclw | Command | Does | | --- | --- | | `nllclw ""` | One-shot question | | `nllclw` | Interactive terminal chat | | `nllclw init` | Setup wizard (`init --env` for a global `.env`) | | `nllclw telegram` / `nllclw websocket` | Start a channel | | `nllclw status` / `nllclw doctor` | Health checks | | `nllclw memory list` / `nllclw schedule list` | Inspect memory and schedules | | `nllclw heartbeat` / `nllclw daemon` | Heartbeat / schedule-running daemon | | `nllclw uninstall` | Remove config and state directories | ## Not covered here NullPantry runs via `zig build run -- --db ` with runtime flags (`--host`, `--port`, `--config`, `--home`, `--backend postgres`); NullDesk (`nulldesk gui|tui|web --workspace `) and NullCap have rich pre-release command surfaces documented in their repos. Their commands stabilize when they cut releases. --- # Reference: Configuration and environment > Config file locations, formats, and environment variables for every component. Every component follows the same pattern: a JSON config file in a predictable home directory, optionally relocated by an env var, with a handful of runtime environment variables on top. This page maps them all. ## Config files at a glance | Component | Default config | Home override | Format | | --- | --- | --- | --- | | NullHub | `~/.nullhub/` | — | JSON, edited via UI or `nullhub config / --edit` | | NullClaw | `~/.nullclaw/config.json` | — | JSON (OpenClaw-compatible, snake_case) | | NullBoiler | `~/.nullboiler/config.json` | `NULLBOILER_HOME` or `--config ` | JSON | | NullTickets | `~/.nulltickets/config.json` | `NULLTICKETS_HOME` or `--config ` | JSON | | NullWatch | `~/.nullwatch/config.json` | — | JSON | | NullPantry | `${NULLPANTRY_HOME}/nullpantry.json` | `NULLPANTRY_HOME`, `--config`, `NULLPANTRY_CONFIG` | JSON, strict (unknown fields rejected) | | nllclw | `~/.config/nllclw/config.json` | `$XDG_CONFIG_HOME` (Windows: `%APPDATA%\nllclw`) | Flat JSON, unknown keys rejected, 16 KiB cap | | NullDesk | `/.nulldesk/config.json` | per-workspace | JSON | For `NULLBOILER_HOME` and `NULLTICKETS_HOME`, relative paths inside the config (like `db`) resolve relative to that directory. ## Environment variables ### NullHub | Variable | Purpose | | --- | --- | | `NULLHUB_ALLOWED_ORIGINS` | Comma-separated CORS origins | | `NULLBOILER_URL` / `NULLBOILER_TOKEN` | Reverse proxy target for the NullBoiler UI | | `NULLTICKETS_URL` / `NULLTICKETS_TOKEN` | Reverse proxy target for the store browser | | `NULLWATCH_URL` / `NULLWATCH_TOKEN` | Reverse proxy target for the Flight Recorder | ### NullClaw Config values are literal (no `${VAR}` expansion inside `config.json`), but some runtime env vars apply: | Variable | Purpose | | --- | --- | | `NULLCLAW_PORT` / `NULLCLAW_BIND` | Gateway port and bind address | | `NULLCLAW_WEB_TOKEN` / `NULLCLAW_GATEWAY_TOKEN` | Access tokens | | `BRAVE_API_KEY`, `TAVILY_API_KEY`, etc. | Web-search providers | Config sections: providers under `models.providers`, default model under `agents.defaults.model.primary`, plus `memory`, `gateway`, `autonomy`, `runtime`, `tunnel`, `secrets`, `security`, `mcp_servers`, `bindings`, `a2a`. The repo ships `config.example.json` and `.env.example`. ### NullWatch Defaults, verbatim: ```json { "host": "127.0.0.1", "port": 7710, "data_dir": "data", "api_token": null } ``` `data_dir` resolves relative to the config file, so data lands in `~/.nullwatch/data`. ### NullPantry Layered precedence: defaults < home defaults < config file < environment < CLI flags. | Variable | Purpose | | --- | --- | | `NULLPANTRY_TOKEN` / `NULLPANTRY_TOKEN_PRINCIPALS` | Auth tokens and per-token principals | | `NULLPANTRY_SCOPES` / `NULLPANTRY_CAPABILITIES` | Default scopes and capabilities | | `NULLPANTRY_DATABASE_URL` | Postgres canonical store | | `NULLPANTRY_AGENT_MEMORY_BACKEND` / `NULLPANTRY_VECTOR_BACKEND` | Backend selection | | `NULLPANTRY_AGENT_MEMORY_STORES` / `NULLPANTRY_VECTOR_STORES` | Named multi-store JSON configs | | `NULLPANTRY_REDIS_URL` / `NULLPANTRY_HOME` / `NULLPANTRY_CONFIG` | Redis, home dir, config path | ### nllclw Precedence: OS environment > `config.json` > `.env`; environment always wins. Config keys are `NLLCLW_*` names lowercased without the prefix (`api_key` for `NLLCLW_API_KEY`). | Variable | Purpose | | --- | --- | | `NLLCLW_PROVIDER` | `openai` \| `openrouter` \| `compatible` (required) | | `NLLCLW_API_KEY` / `NLLCLW_MODEL` | Credentials and model (required) | | `NLLCLW_BASE_URL` | Endpoint for `compatible` (HTTPS required; loopback HTTP needs `NLLCLW_ALLOW_HTTP_BASE_URL=on`) | | `NLLCLW_TOOLS`, `NLLCLW_FILE_READ`, `NLLCLW_FILE_WRITE`, `NLLCLW_SCHEDULE_TOOLS`, `NLLCLW_SHELL` | Capability gates | | `NLLCLW_SEARCH_BRAVE_KEY` | Web search | | `NLLCLW_TOOL_MAX_ROUNDS` / `NLLCLW_TOOL_OUTPUT_MAX_BYTES` | Tool-loop bounds | | `NLLCLW_PERSONA` | `neutral` \| `friendly` \| `technical` \| `witty` | ## Editing hub-managed instances For components under NullHub, prefer the hub's paths — structured editors in the dashboard, raw JSON when needed, or: ```bash nullhub config nullclaw/ --edit ``` The hub knows each component's config schema from its manifest, which is how updates can migrate configs. > [!WARNING] > Pre-1.0: config keys may change between releases. After any manual edit, restart the instance and check `nullhub status` or the component's health endpoint. --- # Reference: APIs and OpenAPI > HTTP surfaces, self-describing schemas, and agent protocols across the stack. Everything in the family speaks JSON over HTTP/1.1, and the services agents talk to describe themselves: point a client at the schema endpoint and it can bootstrap without docs. This page lists what serves what, where. ## Self-describing services | Service | Schema endpoint | Spec | | --- | --- | --- | | NullTickets | `GET /openapi.json`, also `/.well-known/openapi.json` | OpenAPI 3.1 | | NullPantry | `GET /v1/openapi.json` | OpenAPI manifest | | NullBoiler | `docs/openapi.yaml` in the repo | OpenAPI 3.1, 30+ endpoints | NullTickets is explicit about the intent: agents are expected to fetch the schema and figure out the API themselves. The server documents itself to its own users. ## Endpoint summaries ### NullTickets (`:7700`) Pipelines (FSM definitions), tasks and bulk creation, cursor-paginated listing, lease claiming (`POST /leases/claim`), run events and artifacts, a namespaced KV store with FTS5 search, plus: | Endpoint | Purpose | | --- | --- | | `GET /health` | Service health | | `GET /ops/queue` | Per-role queue stats | | `POST /v1/traces`, `/otlp/v1/traces` | OTLP trace ingest, span-to-task linkage via `nulltickets.run_id` / `nulltickets.task_id` attributes | Run mutations require the Bearer lease token issued at claim time. ### NullWatch (`127.0.0.1:7710`) | Endpoint | Purpose | | --- | --- | | `POST /v1/spans`, `/v1/spans/bulk` | Native span ingest | | `POST /v1/evals` | Eval result ingest | | `GET /v1/runs`, `/v1/runs/:id` | Run summaries and detail | | `GET /v1/capabilities` | Feature discovery | | `POST /v1/traces`, `/otlp/v1/traces` | OTLP/HTTP JSON trace ingest | | `GET /health` | Service health | ### NullBoiler (`:8080`) Runs, workflows, workers, checkpoints, streams and tracker endpoints — 30+ in total, per the OpenAPI 3.1 spec. Stream snapshots come in 5 modes (`values`, `updates`, `tasks`, `debug`, `custom`) with `after_seq` cursors; `/metrics` serves Prometheus. Creating a run: ```bash curl -sS -X POST http://127.0.0.1:8080/runs \ -H 'Content-Type: application/json' \ -d '{"input": {...}, "steps": [...]}' ``` ### NullPantry (`127.0.0.1:8765`) Retrieval: `/v1/search`, `/v1/ask`, `/v1/context-packs`, `/v1/vector/*`. Agent memory, NullClaw-compatible: `/v1/agent`, `/v1/memory`, `/v1/agent-memory`, `/v1/agent-sessions`. All retrieval runs one shared path: ACL filter → keyword + vector candidates → graph expansion → fusion/rerank → citation-safe results. ### NullHub (`:19800`) The dashboard's own API, reachable from the CLI without writing a client: ```bash nullhub api GET /api/... --pretty ``` The hub also reverse-proxies its managed neighbors — `/api/nullboiler/*`, `/api/nulltickets/store/*`, `/api/nullwatch/*` — so browser UIs reach loopback-bound services through one origin. Managed NullClaw instances get instance-scoped admin routes (status, config, models, cron, channels, skills). ### NullClaw gateway (`127.0.0.1:3000`) The gateway's HTTP API is documented in NullClaw's own [`gateway-api` docs](https://claw.nullmenu.ai/). Live log streaming from the hub side uses SSE. ## Agent protocols Beyond plain REST, three protocols matter for interop: | Protocol | Where | Use | | --- | --- | --- | | A2A v0.3.0 (Google's agent-to-agent JSON-RPC) | NullClaw implements it; NullBoiler dispatches over it | Agent-to-agent and orchestrator-to-agent calls | | ACP (Agent Client Protocol, stdio JSON-RPC) | `nullclaw acp`; NullDesk drives NullClaw with it | Editor and desk integrations | | MCP (stdio and HTTP) | NullClaw as client | Attaching external tool servers | NullBoiler additionally dispatches to workers over `webhook`, `api_chat` and `openai_chat` (any OpenAI-compatible gateway), plus async MQTT and Redis Streams. > [!TIP] > The OTLP overlap is deliberate: NullWatch and NullTickets both accept OTLP/HTTP JSON. Send traces to NullWatch for observability, to NullTickets for task linkage — or to both. --- # Reference: Compatibility matrix > Versions, licenses, platforms, install paths and hub-manageability, per component. The honest state of the family as of July 2026. All components are pre-1.0, versioned with CalVer (`v2026.x.y` — a date, not a maturity score), and built with Zig 0.16.0 exactly. ## Components | Component | Latest release | License | Status | Hub-managed | | --- | --- | --- | --- | --- | | NullClaw | v2026.5.29 (+ nightlies) | MIT | beta | yes | | NullHub | v2026.5.29 | MIT | beta | is the hub | | NullBoiler | v2026.5.29 | MIT | beta | yes | | NullTickets | v2026.5.29 | MIT | beta | yes | | NullWatch | v2026.5.29 | none yet | early | yes | | NullPantry | v2026.06.09 (+ nightlies) | none yet | early | no | | nllclw | v2026.6.1 | MIT | early | no | | NullDesk | no releases | none yet | pre-release | no | | NullCap | no releases | none yet | experimental | no | | NullBuilder | no releases (`v1` branch) | none yet | maintainer infra | no | > [!WARNING] > "None yet" means the repo has no license file — which legally means all rights reserved, whatever the intent. Check the repo before building anything commercial on NullWatch, NullPantry, NullDesk or NullCap. ## Install paths | Component | Homebrew | Docker (ghcr.io) | Nix | Prebuilt binaries | Source | | --- | --- | --- | --- | --- | --- | | NullClaw | yes | `nullclaw/nullclaw` | flake | yes | zig build | | NullHub | no | `nullclaw/nullhub` | no | 7 targets | zig build (+ npm) | | NullBoiler | no | Dockerfile + compose in repo | no | releases on GitHub | zig build | | NullTickets | no | Dockerfile in repo | no | releases on GitHub | zig build | | NullWatch | no | no | no | 7 targets | zig build | | NullPantry | no | `nullclaw/nullpantry` (multi-arch) | no | no | zig build | | nllclw | no | `nullclaw/nllclw` | no | Linux/macOS/Windows/Android | zig build | | NullDesk | no | no | no | no | zig build only | | NullCap | no | no | flake | no | zig build only | ## Platforms Prebuilt binaries, where published, cover: | Component | Targets | | --- | --- | | NullHub | 7 targets: Linux x86_64/aarch64/riscv64, macOS x86_64/aarch64, Windows x86_64/aarch64 | | NullWatch | 7 targets: Linux x86_64/aarch64/riscv64, macOS x86_64/aarch64, Windows x86_64/aarch64 | | NullClaw | Linux, macOS, Windows across ARM, x86 and RISC-V | | nllclw | Linux, macOS, Windows, Android | NullClaw additionally documents Android via Termux. The shared release pipeline (NullBuilder) cross-compiles up to 12 targets across 5 OS families — Linux (incl. arm32 and riscv64), Android, macOS, Windows — so coverage tends to widen with each release. NullDesk's CI builds its TUI/core for macOS, Linux, FreeBSD, Windows and Android, but publishes no artifacts yet. ## Toolchain | Requirement | Value | | --- | --- | | Zig | **0.16.0 exactly** — repos pin it; newer or older will not build | | Runtime dependencies | none (static binaries; SQLite vendored where used) | | NullHub build extra | npm (embedded Svelte UI) | | NullHub runtime extra | curl, tar (auto-installed if missing) | ## What composes with what | Integration | Status | | --- | --- | | NullHub manages NullClaw / NullBoiler / NullTickets / NullWatch | shipped (manifest-driven) | | NullHub manages NullPantry / NullDesk / NullCap / nllclw | not today | | NullBoiler ↔ NullTickets pull-mode | shipped | | NullBoiler → NullClaw dispatch (webhook, A2A) | shipped | | NullBoiler → third-party workers (openai_chat, api_chat, MQTT, Redis Streams) | shipped | | NullClaw → NullWatch traces (OTLP) | shipped | | NullClaw → NullTickets task loop | shipped (integration guide in tracker repo) | | NullClaw → NullPantry remote memory | shipped (integration guide in pantry repo) | | NullDesk → NullClaw over ACP | pre-release | | NullCap → NullHub-routed model work | experimental | Binary sizes quoted around the family (678 KB NullClaw, 313–653 KB NullWatch, 795 KB nllclw stripped) and the ~1 MB RAM figure are measured by the projects themselves. --- # Develop: Architecture > How the family divides responsibility, and the design rules every component follows. The ecosystem is a set of small services with a strict division of labor, joined by plain JSON over HTTP. Understanding two things — the layer split and the manifest contract — explains most of how it fits together. ## The layer split The core stack separates three concerns that most agent platforms fuse into one process: ``` NullHub (control plane: install, supervise, update, dashboard) │ ┌───────────┼───────────────┬──────────────┐ ▼ ▼ ▼ ▼ NullTickets NullBoiler NullClaw NullWatch (truth) (policy) (execution) (telemetry) ▲ │ │ ▲ └── claims ───┘ └── spans ─────┘ ``` - **NullTickets owns truth.** What work exists, its state machine, its history. It stores the graph and the events; it never runs agents or decides scheduling. - **NullBoiler owns policy.** What runs, when, on which worker — routing, concurrency, retries, fan-out, checkpoints. It polls the tracker, claims tasks, and dispatches. - **NullClaw owns execution.** Providers, tools, sandboxing, channels. It does the work and reports back. Each layer is optional. One agent loop plus NullTickets is a valid stack; so is NullClaw alone. Around the core: NullWatch records what happened (spans, evals, cost), NullPantry holds what the team knows (permission-aware knowledge and memory), and NullDesk puts a human at the pass — reviewing every plate before it leaves the kitchen. ## The manifest contract NullHub is not hard-coded to its components. Each managed component publishes a `nullhub-manifest.json` describing its installation, configuration schema, launch command, health checks, wizard steps and UI modules. The hub is a generic engine that interprets manifests — components export theirs with `--export-manifest`, and bootstrap config from wizard answers with `--from-json` (NullWatch, NullTickets and NullBoiler all ship both). This is why the managed set is exactly NullClaw, NullBoiler, NullTickets and NullWatch: those are the four that publish manifests today. ## Protocols | Protocol | Used for | | --- | --- | | JSON over HTTP/1.1 | Every service API | | OpenAPI | Self-describing schemas — 3.1 for NullTickets and NullBoiler; NullPantry serves an OpenAPI manifest | | SSE | Live log streaming (NullHub) | | OTLP/HTTP JSON | Trace ingest (NullWatch, NullTickets) | | A2A v0.3.0 | Agent-to-agent JSON-RPC (NullClaw, NullBoiler dispatch) | | ACP over stdio | Editor/desk integration (`nullclaw acp`, NullDesk) | | MCP | External tool servers (NullClaw client, stdio + HTTP) | No message broker is required anywhere in the core; MQTT and Redis Streams are optional NullBoiler dispatch paths. ## Design rules The same decisions recur across every repo: - **One static binary per component.** No runtime dependency on Node, Python, or provider SDKs. NullHub even embeds its Svelte dashboard into the binary via `@embedFile`. - **Vendored persistence.** Where a database is needed, it is SQLite compiled in — no external DB to run. NullWatch skips even that: append-only JSONL files. - **Local-first state.** Everything under a home directory: `~/.nullhub`, `~/.nullclaw`, `~/.nulltickets`, `~/.nullboiler`, `~/.nullwatch`. No hosted service exists to sync to. - **Interfaces over plugins.** NullClaw makes everything a swappable vtable interface — providers, channels, tools, memory engines, tunnels, runtimes, peripherals. NullPantry moves the same idea to compile time: engine profiles (`nullclaw`/`minimal`/`full`/`custom`) build in only the backends you chose. - **Loopback by default, tokens for the rest.** See [Security](/docs/operate/security/). - **Zig 0.16.0, CalVer, shared CI.** Every repo pins the same toolchain and releases through [NullBuilder](https://github.com/nullclaw/nullbuilder)'s reusable workflows. > [!NOTE] > The deeper per-component architecture docs are worth reading in the repos: NullClaw's `docs/en/architecture.md`, NullTickets' `docs/architecture.md`, NullPantry's `docs/product-architecture.md`, NullDesk's 39 KB `docs/architecture.md`. Next: the seams you can build against — [Integrations](/docs/develop/integrations/). --- # Develop: Integrations > The extension seams — worker protocols, tracker contract, OTLP, MCP, A2A, manifests. You don't need to write Zig to build on the ecosystem. Every component exposes a documented seam — a protocol or contract that outside software can implement. This page catalogs them, roughly in order of usefulness. ## Bring your own worker (NullBoiler) NullBoiler dispatches to anything that speaks one of its worker protocols: | Protocol | Implement this if | | --- | --- | | `webhook` | You have an HTTP endpoint that accepts a task and returns a result | | `openai_chat` | Your worker is any OpenAI-compatible gateway (set `model` in the worker config) | | `api_chat` | Your worker exposes a chat-style API (ZeroClaw does) | | `a2a` | Your worker speaks Google's A2A JSON-RPC (NullClaw does) | | MQTT / Redis Streams | You want async dispatch through a broker you already run | A bundled bridge (`tools/picoclaw_webhook_bridge.py`) shows the webhook pattern for adapting a runtime that doesn't natively fit. Workers declare tags and capacity; the engine handles selection, retries, backoff and health checks. ## Implement the tracker contract (NullTickets) Any runtime becomes a NullTickets worker by implementing three moves: claim (`POST /leases/claim` by role, keep the lease heartbeated), report (append run events, attach artifacts), transition or fail (with optimistic `expected_stage` / `expected_task_version` checks). The full schema is served by the tracker itself at `/openapi.json` — agents are expected to bootstrap from it. See [Durable backlog](/docs/recipes/durable-backlog/) for the semantics. ## Send telemetry (OTLP) NullWatch (`127.0.0.1:7710`) and NullTickets (`:7700`) both accept OTLP/HTTP JSON on `/v1/traces` and `/otlp/v1/traces`. Anything that emits OpenTelemetry traces can use them as local sinks. For NullTickets, add `nulltickets.run_id` / `nulltickets.task_id` span attributes to link traces to tasks. For NullWatch there is also a community Python SDK — `nullwatch-python-sdk`, zero required dependencies, with built-in eval scorers for RAG hallucination detection and tool-call schema validation. ## Extend the agent (NullClaw) - **MCP servers.** NullClaw is an MCP client over stdio and HTTP — the standard way to add tools without touching the binary. - **Skills.** Packaged capabilities, installable from a registry: `nullclaw skills install `. - **A2A v0.3.0.** NullClaw exposes Google's agent-to-agent JSON-RPC, so external agents can call yours as a peer. - **ACP.** `nullclaw acp` speaks the Agent Client Protocol over stdio for ACP-compatible editors; NullDesk drives NullClaw the same way. - **Providers.** Any OpenAI-compatible endpoint works via `custom:https://...` — local inference servers included. - **Vtable interfaces.** In-tree, everything is swappable: providers, channels, tools, memory engines, tunnels, runtimes, peripherals (Arduino, Raspberry Pi GPIO, STM32). ## Serve memory (NullPantry) NullPantry exposes NullClaw-compatible memory routes (`/v1/agent`, `/v1/memory`, `/v1/agent-memory`, `/v1/agent-sessions`) — and conversely, its agent-memory layer proxies to 10+ external memory services (Mem0, Zep, Supermemory, Honcho and others) plus Redis, ClickHouse and Markdown workspaces. If you run a memory service, there may already be an adapter; backends are selected at compile time. ## Join the hub (manifest contract) A component becomes hub-manageable by publishing a `nullhub-manifest.json` describing install, config, launch, health checks and wizard steps, and by supporting `--export-manifest` / `--from-json`. NullWatch is the smallest worked example of the pattern. ## Build UIs Everything headless is deliberately headless so UIs can be thin: - `nullhub api GET /api/... --pretty` — the hub API, plus its reverse proxies to NullBoiler, the NullTickets store, and NullWatch. - nllclw's WebSocket channel (`ws://127.0.0.1:8765/ws?token=...`) with `chat`, `status`, `ping`, `close` message types — made for custom dashboards. - NullWatch's query API for observability frontends; NullHub's Flight Recorder is one client of it, not the only possible one. > [!NOTE] > Pre-1.0: contracts can shift between releases. The OpenAPI-first services (NullTickets, NullBoiler, NullPantry) are the safest to code against, because the schema you fetch is the schema you get. --- # Develop: Contributing > Toolchain, test culture, shared CI, and how releases work across the repos. All development happens in the open at [github.com/nullclaw](https://github.com/nullclaw). The repos share one toolchain, one CI system and one release convention, so contributing to a second component feels like the first. ## Toolchain One version, everywhere: | Requirement | Value | | --- | --- | | Zig | **0.16.0 exactly** — every repo pins it | | Node/npm | Only for NullHub's embedded Svelte UI | | Anything else | No — SQLite and C deps are vendored | The standard loop is the same in every repo: ```bash git clone https://github.com/nullclaw/.git cd zig build zig build test ``` NullClaw uses `zig build test --summary all`; NullTickets adds `bash tests/test_e2e.sh`; NullPantry has suite targets (`zig build test-api`, `test-agent-memory`, `test-vector`) plus opt-in contract tests against external backends (`zig build qdrant-contract` and friends). ## Test culture Tests are the family's main quality gate, and the numbers are taken seriously: NullClaw runs 5,300+ tests, NullBoiler 355 unit tests plus an e2e suite with mock workers, nllclw passes 385/385 (390 with the shell tool compiled in), and NullHub runs backend integration tests against a real hub process in a temporary home directory. A PR without tests for its change will be asked for them. ## Shared CI: NullBuilder CI, nightlies and releases are reusable GitHub Actions workflows in [nullclaw/nullbuilder](https://github.com/nullclaw/nullbuilder), referenced at the `v1` branch. A consuming repo's CI is a few lines: ```yaml jobs: ci: uses: nullclaw/nullbuilder/.github/workflows/zig-ci.yml@v1 permissions: contents: read with: binary_name: nullclaw artifact_prefix: nullclaw ``` The CI workflow runs tests, cross-compiles `ReleaseSmall` binaries for a configurable target matrix, and reports test count, MaxRSS and binary size in the job summary — binary size is a tracked metric here, not an afterthought. `zig-nightly.yml` and `zig-release.yml` cover nightly builds (12-target default matrix, including Android via the NDK) and tag-driven releases with optional multi-arch Docker publish to ghcr.io. All third-party actions are pinned to commit SHAs. ## Releases Versions are CalVer: pushing a `v2026.x.y` tag triggers the release workflow, which injects the version, builds the matrix, and publishes binaries with generated notes. Most repos carry a `RELEASING.md` with their specifics — NullClaw, NullHub, NullBoiler, NullTickets and NullWatch all do. ## Where to contribute - **Code and issues.** NullClaw ships a `CONTRIBUTING.md`; NullHub has `TESTING.md` describing its testing strategy and roadmap, plus multiple external contributors already. `AGENTS.md` / `CLAUDE.md` files in most repos carry conventions for coding agents — read them, whichever kind of contributor you are. - **Docs.** NullClaw maintains English and Chinese docs; nllclw is localized into 11 languages. Translation fixes are welcome, low-risk first PRs. - **Integrations.** Bridges, SDKs and adapters (like the community `nullwatch-python-sdk`) can live outside the org entirely — see [Integrations](/docs/develop/integrations/). > [!WARNING] > Check the license before contributing substantial code: NullClaw, NullHub, NullBoiler, NullTickets and nllclw are MIT, but NullPantry, NullWatch, NullDesk, NullCap and NullBuilder currently have **no license file**, which leaves contributions to them in an unclear legal position. If that blocks you, an issue asking for a license is itself a useful contribution. > [!NOTE] > Pre-1.0: config and CLI may change between releases — including because of your PR. Breaking changes are allowed; silent ones are not. Note them in the changelog.