Watching a run
Monitor a running workflow as a person through the Viewer, or as an agent through JSON.
Workflow authoring, execution, monitoring, and approval are available as commands with --json
forms, so the thing driving Kilin can equally be a person at a terminal or an outer agent runtime
supervising work it delegated. Non-interactive setup uses an explicit provider selection such as
kilin skills link --providers agents. The Viewer remains a human inspection surface, while an
outer agent can launch and supervise its attached CLI process through --json.
┌─────────────────────────────────────────────────────────────────┐
│ OUTER AGENT RUNTIME │
│ a person at a terminal · or Codex / Claude Code / a script │
└─────────────────────────────────────────────────────────────────┘
│ ▲
│ create kilin workflow init │ monitor runs list · runs show
│ update edit WORKFLOW.yaml │ track runs wait --json
│ start kilin run · kilin trigger │ inspect kilin ui
│ decide runs approve · runs reject │
▼ │
┌─────────────────────────────────────────────────────────────────┐
│ KILIN │
│ validate → compile → immutable revision → execute │
│ SQLite history · captured logs · JSONL event stream │
└─────────────────────────────────────────────────────────────────┘
│ ▲
│ spawns provider subprocesses │ results · logs · decisions
▼ │
┌─────────────────────────────────────────────────────────────────┐
│ INNER WORKFLOW — one run │
│ │
│ analyze ──▶ implement ──▶ [approval] ──▶ verify │
│ read_only workspace_write barrier read_only │
│ Claude Code Codex Codex │
└─────────────────────────────────────────────────────────────────┘The outer runtime stays outside the run. It cannot reach into a running node, and no edit to
WORKFLOW.yaml can change what this run executes, because Kilin records an immutable revision
before the first node starts.
Both views below read the same local SQLite history. Neither is a reduced version of the other.
As a person
Open the Viewer for the workflow you are running:
kilin ui change-review --cwd /absolute/path/to/projectThe Viewer binds numeric 127.0.0.1 on an operating-system-selected port and shows the compiled
graph, node states as they change, the newest 50 runs for that exact workflow identity and working
directory, lineage, approval metadata, failures, bounded captured output, and Decision Packets.
When a run stops at an approval, the Viewer shows guarded Approve and Reject buttons alongside the
equivalent CLI commands. That decision is its only state mutation: it cannot edit workflows, start
provider runs, or schedule work. Pass --no-open to print the launch URL instead of opening a
browser, and treat that URL as a credential.
Without a browser, the same history is available as text:
kilin runs list
kilin runs show <run-id>As an agent
The bundled run skill validates the visible package, starts
kilin ui <id> --cwd <directory> --no-open --json as a managed attached process when the
requester's browser can reach the same loopback, and returns the viewer.started URL directly.
The Viewer remains alive after run success or failure until it is stopped or the outer-agent
session ends. If the agent runs on another machine or cannot retain the process, it returns the
manual command with the requester's local project path instead of claiming the remote
127.0.0.1 URL is accessible. That local Viewer sees the same history only when it can access the
same Kilin data.
kilin run --json streams one JSON object per line. Every event carries outputVersion: 1 and a type:
run.started · node.started · node.finished · approval.requested
approval.resolved · run.finished · errorRather than polling, block until the run next needs attention or reaches a terminal state:
kilin runs wait <run-id> --jsonA controller records its decision from a second local process while the run stays attached in the first, so nothing has to scrape a terminal:
kilin runs approve <run-id> <approval-node-id> --actor agent
kilin runs cancel <run-id>Failures carry stable error codes — NODE_TIMEOUT, LOOP_LIMIT_REACHED, APPROVAL_REJECTED, and
the rest — so a supervising agent can branch on the code rather than parse prose. runs list,
runs show, and workflow validate also accept --json.
What monitoring never exposes
Declared run parameters are deliberately excluded from lifecycle events, runs list, runs show,
and the Viewer. Loop iterations are grouped without exposing parameter, feedback, decision-choice,
or result values.
Captured stdout, stderr, and results remain private local files under the data directory rather than event payloads. See trust boundaries for what that history can contain, and the command reference for the full flag surface.