← Reference

Control-plane channels

System ↔ agent communication via <cp:*> XML tags.

Full notes from the app

Rate-limited per Decision 16. Visible live in the control drawer.

29 entries · kcode 0.4.0

29 shown
ChannelDirectionAttributesLimitWhat it carries
system→agent
<cp:permission-context>system→agent(none)60/min/sourceSnapshot of the active permission rules, injected once per turn.
<cp:event-trigger>system→agentsource="…"60/min/sourceExternal event fired (file watcher, timer, app-bus). Used to wake the agent on schedule.
<cp:hook-fired>system→agentname="…" (+ target="…" session="…" on project hook fires)30/min/hookA trigger hook executed and produced output worth surfacing to the agent. Project [[hooks]] fires emit it too — on the target session, recording the hook name, its declared target, and the resolved session, with a preview of the injected line — so /control shows why a turn started.
<cp:fs-change>system→agent(none)30/min globalExternal file-system change detected. Filters out self-tool writes — only third-party changes are emitted.
<cp:mcp-tools-changed>system→agentserver="…" added="N" removed="N"A connected MCP server pushed notifications/tools/list_changed and the live re-list changed the session's tool registry — the body names the added/removed qualified tool names so the agent plans against the real set (a no-op re-list emits nothing).
<cp:shell-notice>system→agentkind="command-terminated|host-restarted|prompt"Async shell notice: a command was terminated by a host crash (status indeterminate, never auto-reissued), the shell host restarted, or a command is blocked on an interactive prompt (answer via shell_write_stdin).
<cp:shell-exit>system→agentexec-id, exit-code, signalA watched background command exited — the watch is armed by default for any bash command that backgrounds past its timeout (2026-08-11), and stays opt-in via notify_on_exit: true on shell_spawn or a prompt-parked command (#77). The body carries the exit outcome plus the command's output tail (ANSI-stripped, bounded), so the agent can act without a shell_output round-trip. Mid-turn it drains into the next round like any channel, and one that lands after the round's drain continues the turn (cascade rule 5, 2026-09-07 — a failing build's exit used to sit unread until the next user prompt); when the session is idle the daemon drives a wake turn on it, so a finished command always gets acted on — no polling. A watched command can also be LOST without an exit (2026-07-22): a shell-host restart emits the same channel with terminated="<reason>" (result indeterminate, never reissued), and a session crash-respawn drains the dead incarnation's watch and drives a wake turn naming the lost exec ids — the agent reconciles instead of waiting on an exit that can never come.
<cp:plugin-inject>system→agentplugin="<name>"A plugin's kcode.inject(text) wake (the "inject" permission) — the plugin-facing face of the eventsource wake path. The body is the plugin's injection text. Mid-turn it drains into the next round like any channel; when the session is idle the daemon drives a wake turn on it, so a plugin can wake its session (a tail watcher, a long-poll monitor) instead of waiting for the user. Empty injections are dropped.
<cp:context-usage>system→agentused="…" window="…" pct="…"The live token budget (tokens used / model window / percent), so an autonomous agent can see how full its context is. Emitted only when the fill crosses a band boundary keyed to the compaction thresholds (comfortable < snip, filling < auto-compact, nearly-full above) — not every round, since each emission is injected into the transcript. Near-full carries a nudge to wrap up or call compact.
<cp:permission-denied>system→agenttool="…" reason-code="…" path="…"?A tool call was blocked by the permission layer. Carries the tool, the spec §15 reason-code enum (from permissions::DenialKind), and the offending path when there is one, so the agent can adjust rather than retry blindly.
<cp:plan-mode>system→agentconstraint="read-only" round="…"Per-round reminder while the planner agent kind runs: tool calls are limited to read-only operations (no edits/exec) — the user executes the assembled plan.
<cp:tool-empty-output>system→agenttool="…"Nudge fired when a tool returned an Ok outcome whose payload was null or empty — prompts the agent to verify the input or change approach rather than assume success.
<cp:turn-summary-missing>system→agentonce per turnReminder queued when a streamed round completes with no <turn-summary> signal — the working strip is built from it, so a silent round reads as a dead 'Working…'. Injected at the next round boundary (as a synthetic user message when no control plane is wired — headless/tests); a reminder, not an error.
<cp:memory>system→agentop="…" scope="…" hit-count="…"?A memory save / delete / recall occurred. Carries the operation, the scope, and (on a recall) the hit-count, so the agent sees memory activity in-context.
<cp:memory-recall>system→agentcount="…" names="…"Per-turn auto-recall (P11, [memory] auto_recall): the turn's input queried the memory store's ranking and the floor-passing top-k memories ride this block — name, scope, description, body, and a staleness warning when old. Injected beside the user's message in round 1; auto-recalls don't stamp recency or raise <cp:memory> events. The names attribute (comma-separated) feeds the chat marker: the daemon fans a persistent one-line 'Recalled N memories into context: a, b, c' transcript bubble (CommandReplyKind::Compaction, 2026-08-11 — a recall silently changes what the model reads, so it surfaces like a compaction; the long bodies stay in /control).
<cp:compaction-start>system→agent(none)A compaction pass just started — emitted the moment the threshold check passes and the summarization LLM round-trip begins (2026-08-11). The daemon fans it to subscribers as a persistent 'Compacting context…' transcript bubble (CommandReplyKind::Compaction, not a toast) and raises the tile to Working, so an idle session running a manual /compact shows both that it started and that it's still working. Paired with <cp:compaction> on completion.
<cp:compaction>system→agentstrategy="…" tokens-before="…" tokens-after="…"A compaction pass completed, carrying the strategy and the before/after token counts. The daemon fans a 'Context compacted (strategy): before → after tokens' transcript bubble (CommandReplyKind::Compaction) and pushes a corrected usage report so the chat footer's token/context count drops to the post-compaction figure immediately (2026-08-11 — it used to hold the pre-compaction number until the next turn's usage event). Also prefixes the summary on following provider calls.
<cp:subagent>system→agentstate="started|finished|failed" id="…" kind="…" rounds="…"? error="…"?Delegation lifecycle — a subagent the parent spawned via spawn_subagent started, finished (with its round count + final text), or failed (with an error summary). rounds counts the child's provider rounds, taken from the child turn's usage — not the number of tokens it streamed. Surfaces work-in-flight to the parent.
<cp:time>system→agentutc, local, (duration_ms on tool results), (origin on user-role messages)The moment the message it trails was written, in UTC and in your local zone. Rides on the end of every message kcode authors (agent_loop.time_metadata, on by default) so the agent can read elapsed time off its own history. Two optional per-message attributes refine it: a tool result carries duration_ms (that call's own wall time, which the gap between two stamps can't isolate), and a user-role message carries origintyped / queued / channel / nudge — so the agent can tell fresh typed intent from a queued message that may be stale or already answered. Read-only — the agent never emits it.
<cp:mailbox>system→agentfrom, tounboundedA message from a named agent in this session arrived in the main agent's mailbox (R#48).
<cp:worktree-merged>system→agentslug, branch, commit, kindnoneA worktree session's branch was merged into this session's tree (W4 — the user ran /worktree merge). Emitted by the daemon into the receiving session: the body carries the diffstat and the worker's final report (its last assistant message), kind says squash or true merge. Queued for the agent's next round and shown live as a transcript bubble.
<cp:lsp-diagnostics>system→agentpath, countunboundedFresh LSP errors on a file the agent just edited or wrote (R#37 post-edit digest; only from already-spawned servers).
<cp:external-trigger>system→agentname, target, sessionunboundedAn external trigger fired into this session via kcode trigger (R#39) — CI/cron/sidecar provenance for the injected turn.
agent→system
<cp:agent-status>agent→systemstate="done|continue"Round-end signal. Stripped from history. First occurrence is parsed for round control; malformed = hard stop.
<cp:goal-status>agent→systemstate="done|blocked"Goal exit declaration (#59): the agent declares the session goal verifiably complete (done) or unprocessable without the user (blocked), with its summary as the body. The daemon disarms the /goal driver and posts the summary as a notification (done → completed, blocked → needs-input). Stripped from history. Goal-scoped — it never affects turn continuation (pair with <cp:agent-status> to end the turn); malformed instances flag on /control but never hard-stop.
<cp:compact>agent→systemtype="fact|learning|decision|request|response|tool"Structured turn summary preserved in history. Used by the compaction engine to build session digests.
<cp:plan-revision>agent→systemfrom="…" to="…" reason="…"Plan-modification tracker. Preserved in history for an auditable trail.
<cp:agent-thinking>agent→system(none)Internal reasoning (view-only). Stripped from history per Decision 15; visible in /cot display.
<cp:judge-directive>agent→system(none)Verdict emission from the judge agent kind. Drives continuation rule 9.