nullTickets is a headless task tracker and lease coordinator for AI agents.
- Single-process Zig service
- SQLite persistence
- JSON REST API
- Lease-based run ownership
- No built-in global orchestrator
In scope:
- Pipeline/task state and durable history
- Lease ownership and retries
- Run events and artifacts
- Task dependencies (DAG)
- Optional task assignments
- Key-value store with full-text search
- Orchestrator-facing queue metrics (
/ops/queue)
Out of scope:
- Starting/stopping agent processes
- Scheduling and balancing policy across many agents
- External orchestrator logic
main.zig: process lifecycle, CLI flags, socket listener, request loopapi.zig: route dispatch, auth checks, JSON validation and response formattingstore.zig: SQL operations, transactions, migrations, data ownership helpersdomain.zig: pipeline FSM parse/validate and transition lookup
pipelines: workflow state machine definitionstasks: units of work with current stage and metadataruns: execution attempts for tasksleases: short-lived ownership locks with token hashevents: append-only run timelineartifacts: task/run outputstask_dependencies: DAG edges (task -> depends_on_task)task_assignments: optional explicit owner binding for agentsstore: namespaced key-value entries with FTS5 searchidempotency_keys: deduplication store for write retries
- Agent claims work using role (
/leases/claim). - Service starts a new run and grants a lease token.
- Agent sends events and periodic heartbeats.
- Agent either transitions the run to the next stage or fails it.
- Transition can enforce optimistic checks (
expected_stage,expected_task_version). - Failures apply retry policy and optional dead-letter routing.
- Lease is released on transition/failure or expires automatically.
- State-changing paths use SQL transactions (
BEGIN IMMEDIATE) to avoid double-claim races. - Lease tokens are stored as SHA-256 hashes, not plaintext.
- Pipeline transitions are validated against declared FSM definitions.
- Claim excludes blocked dependencies, non-eligible retries, and foreign assignments.
- API string fields are JSON-escaped at serialization time.