# Agent plane ownership

> Harn has one public agent-loop entrypoint: agent_loop . HarnessAgent owns session mutations, checkpoints, event emission, transcript projection, and terminal classification....

Website: https://harnlang.com/dev/agent-loops.html

This page documents Harn, which is pre-1.0. Language, standard library, and CLI APIs may change. If the intended version is unclear, clarify before using this page.

---

Harn has one public agent-loop entrypoint: `agent_loop`. `HarnessAgent` owns
session mutations, checkpoints, event emission, transcript projection, and
terminal classification. `HarnessLlm` owns one model request, and
`HarnessTools` owns dispatch. Keeping those responsibilities separate prevents
a convenience wrapper from creating another lifecycle or result vocabulary.

## Typed stages

The loop crosses `agent_stage(agent, session_id, stage, input?)` at each safe
injection boundary. `AgentStage` is a closed vocabulary covering iteration,
compaction, tool dispatch, command hold, daemon idle, and loop exit. The seam
accepts only `HarnessAgent`; model and tool handles stay in the stages that use
them. Every checkpoint event, queued injection drain, and session hook therefore
observes the same stage name.

## Specification and result contracts

`AgentSpec` is the intersection of six named records: model, execution,
capability, lifecycle, context, and observability. These records are a static
projection over one flat runtime value, not nested configuration and not a
second normalizer.

`AgentResult` describes the value returned by `agent_loop` and
`HarnessAgent.session_finalize`. Its `terminal` member is projected from the
Rust `AgentTerminalKind` owner and checked against it in the VM test suite. ACP
metadata, CLI protocol artifacts, A2A task status/metadata, replay run records,
and Harn callers consume that projection instead of classifying `final_status`
or `stop_reason` themselves. A completion judge that cannot accept before its
deadline or policy limit produces `completion_unverified`; A2A projects that to
`failed`. Text-only nudge exhaustion produces `policy_no_progress`, while a
stall-governor hard stop after repeated equivalent actions or observations
produces `policy_thrash`. A2A suspension remains wire-compatible as `working` plus
`metadata.harn.pause` until the proposed paused state is standardized.

## Tool registries

`AgentModelSpec.tools` references `ToolRegistry` from `std/tools`. It no longer
contains a local structural copy. The typechecker and conformance suite verify
that registries cross package boundaries and remain assignable to `AgentSpec`.

## Package boundary

The agent contracts, LLM dialects, and provider catalog remain in `harn-vm`.
They share normalization, dispatch, replay, and terminal semantics with the
runtime, and every current Rust consumer needs that complete behavior. Harn
Cloud links `harn-vm` and `harn-serve`; Burin and 20eq consume the versioned
Harn toolchain rather than a dialect-only library.

Extracting a catalog or dialect crate would create another versioned projection
without an independent consumer or release cadence. The deeper boundary is the
small typed interface inside `harn-vm`: capability data selects one dialect,
`AgentSpec` configures one loop, `ToolRegistry` supplies its tools, and
`AgentResult` reports its terminal state. Generated catalog artifacts and drift
checks keep external projections aligned with the same release.

## Completion checkpoints

Built-in completion judges are terminal checkpoints, not worker turns. Harn
projects the immutable worker transcript into bounded effect and verification
evidence. Judge requests exclude callable tool schemas and raw transcript
replay. The judge request and response are not appended to
`harness.agent.messages(session_id)`.

The task, rubric, and output schema occupy the stable start of the request. The
changing user message carries the latest mutation, verification, problem, and
transcript-integrity evidence. This placement lets a provider reuse the stable
prompt prefix, but cache behavior is only a performance detail.

The `harn.completion_judge_cache.v1` checkpoint records cache eligibility, a
hash of the static prefix, and provider-reported cache reads and writes. These
fields are telemetry. They do not prove equivalent evidence and never reuse a
prior verdict.

Deadline admission uses monotonic remaining time, the configured operation
budget, and the terminal reserve. `prompt_token_estimate` is a rough
character-count estimate, not a provider tokenizer result, and does not decide
admission. The VM bounds the complete checkpoint operation, including local
setup and response parsing.

`harn.completion_judge_evidence_projection.v1` records what evidence entered
the request, including how many read-only calls carried a record in the
packet's `research_summary` and how many did not. `harn.completion_directive_receipt.v1` records the final action,
reason, admission result, and whether repair feedback reached the next turn.
`evidence_id` and transcript digests correlate these records and reveal changed
input; they never substitute for a new judgment.

A `continue` result injects repair feedback because it is meant to steer the
worker. An `accept` or `stop_unverified` result changes only events and terminal
state. Tests should assert the worker transcript around accepted judge calls
instead of inferring isolation from event counts.

---

## Read next

- [LLM dialect ownership](https://harnlang.com/dev/llm-dialect-contract.md)
- [Agent harness ownership](https://harnlang.com/dev/agent-harness-ownership.md)
