Skip to main content

Observability for agent runs — jobs, rounds, and per-step telemetry

Every task Kiwi runs is inspectable end-to-end: which rounds ran, what each one did, why a task has not started yet, and where the PR landed. Observability is built on a few primitives plus the dashboard.

Jobs

A job is one submitted task. It carries the task summary, accumulated cost, and a status that rolls up from its underlying queued task — plus, if a PR review comment resumed it, from any continuation tasks that followed. The dashboard renders a job's rounds in the job detail view.

The run timeline

The daemon runs the Architect/Implementer session in its own process, so nothing else observes it. It therefore emits an event per phase — round_start, implementer, tool, review, verify, session_end — each with its outcome, duration, and the tokens and cost it consumed. Those events are what the dashboard's task drawer renders, phase by phase: what the Implementer did, whether the Architect's review approved or asked for a revision, whether the test passed.

The Architect's review rationale is in the timeline — that is the only place a run explains itself in words. Raw test output stays out of it, as it always has, because it can carry secrets. The same events are the evidence a verified execution record is assembled from, which is why they are stored as append-only rows that outlive the queue row they describe.

Why a task has not started

A QUEUED task on its own says only "nobody has leased this yet" — the same display whether work is about to begin or can never begin at all. So each queued task also reports a blocked reason, a stable code plus a sentence:

ReasonMeaning
awaiting_runnerthe healthy case — a live daemon serves this fleet and has not picked it up yet
provisioninga Free-tier daemon is being cold-started for the org
provision_failedthe last cold-start failed outright, with the launcher's reason attached
no_runnerno daemon is registered that could ever lease it
runner_offlinedaemons are registered but none has heartbeated recently
concurrency_capthe org is at its concurrent-job limit
compute_capthe org is at its monthly agent-minute ceiling

The diagnosis reads the same code paths as the lease rules it describes, including fleet routing, so an explanation cannot drift from the enforcement. It is a pure read that never affects scheduling, and it is best-effort: an explanation of a status must never be the reason the status request fails. Two of these were previously silent by construction — an org at a cap and an org with no work at all both produced "nothing leased".

In the dashboard the reasons split by severity: waiting reasons keep the spinner, while problems get a static warning, because animating a spinner over a job nobody can run is the UI asserting progress that is not happening.

Job control

A job can be cancelled, retried, or deleted from the dashboard, and the API reports how many tasks each action actually affected — "cancel" on a job whose tasks all finished a second earlier is a success that changed nothing, and the caller should be able to tell. Cancellation reaches a running task: the Control Plane cannot call into a daemon, so it revokes the lease, and the daemon's renewal failure aborts the run in flight.

Live topology

The Next.js dashboard renders a live topology of the running system. Crucially, it hangs each running job off the executor daemon that leased it, so you can see the whole swarm at once: which daemons are alive, which fleet they belong to, and what each is working on right now.

The dashboard also surfaces jobs, fleets, models, integrations, spend, onboarding and settings — a single pane over the whole platform. Job lists can be filtered, sorted and grouped by date, with the view persisted in the URL so a filtered list is a shareable link.

Spend

Spend is computed from each call's token usage at the price of the model that actually ran, using the same model-to-provider routing the daemon used — so a job's cost cannot be attributed to a provider it did not run on. Admission itself makes no model call and costs nothing to meter: the Architect and Implementer are the only spend on a job, tracked separately so a cheap Implementer cannot be used to hide an expensive Architect.

Surfaces for automation

Beyond the dashboard, the same job state is reachable programmatically:

  • The kiwi CLI — submit, resume (kiwi submit -resume -task-id <id>), and inspect.
  • Node and Python SDKs — programmatic submission for CI/CD and auto-triage (e.g. Sentry), published as @runkiwi/sdk on npm and kiwi-sdk on PyPI.
  • The Linear webhook — issues labeled kiwi (or moved to In Progress) become planner jobs, closing the loop from issue tracker to PR.
  • The GitHub webhook — a merged PR appends a signed merge link to the job's execution record, capturing who approved it.