Build and operate AI agents in one language.
Harn is a pipeline-oriented language for AI agents. LLM calls, tools, capability checks, durable steps, and deterministic replay are language and standard-library features, not SDKs you wire together yourself.
pipeline review(harness: Harness) {
const files = ["src/main.rs", "src/lib.rs"]
const reviews = parallel each files { file ->
const code = harness.fs.read_text(file)
retry 3 {
harness.llm.call(code, "Review this Rust file and list any issues.")
}
}
for review in reviews {
harness.stdio.log(review)
}
}call_closure, a missing bounds check, and one stale doc snippet.- Open source, written in Rust
- Deterministic replay
- Capability-safe by default
- Speaks MCP, ACP & A2A
Complete programs, not snippets
Read these for the shape rather than the subject. In each one the deterministic work is ordinary code, and the program decides when a step is worth a model call. They ship in the CLI demo bundle and run offline against recorded fixtures.
Spend the model only on the judgment call.
Gathering the diff, counting the changed lines, and assembling the receipt are plain code. Two steps need an opinion, so only those two become model calls. The prompts live in separate template files.
This scenario ships more than one file. The prompts live in sibling .harn.prompt templates and load with render_prompt, the way a real Harn project is laid out.
Make it yours
Swap the hard-coded diff for a call to your forge and it reviews real pull requests. Edit the prompts without touching the program, or add a third stage that blocks the merge when the verdict comes back negative.
type DiffFile = {path: string, loc_added: int, loc_removed: int, risk: string}
/** The PR-level diff review_captain reasons over, one entry per changed file. */
type DiffSummary = {repo: string, pr_number: int, files: list<DiffFile>}
fn diff_summary() -> DiffSummary {
return {
repo: "burin-labs/widgets",
pr_number: 502,
files: [
{path: "src/retry.ts", loc_added: 86, loc_removed: 12, risk: "high"},
{path: "src/retry.test.ts", loc_added: 124, loc_removed: 0, risk: "low"},
{path: "src/http.ts", loc_added: 14, loc_removed: 8, risk: "medium"},
{path: "docs/retry.md", loc_added: 38, loc_removed: 0, risk: "low"},
{path: "package.json", loc_added: 1, loc_removed: 1, risk: "medium"},
],
}
}
fn total_added(files: list<DiffFile>) -> int {
let total = 0
for f in files {
total = total + f.loc_added
}
return total
}
fn render_review_prompt(fs: HarnessFs, diff: DiffSummary) -> string {
return fs.render_prompt(
"review.harn.prompt",
{
pr: diff.pr_number,
file_count: len(diff.files),
files: diff.files,
total_added: total_added(diff.files),
},
)
}
fn render_clarification_prompt(fs: HarnessFs, pr: int, answer: string) -> string {
return fs.render_prompt("clarification.harn.prompt", {pr: pr, answer: answer})
}
pipeline default(harness: Harness) {
const diff = diff_summary()
const system = "You are review_captain, a thorough code reviewer."
const review_prompt = render_review_prompt(harness.fs, diff)
const initial_envelope = harness.llm.call(review_prompt, system)
harness.stdio.println("=== review_captain · stage 1 (initial scan) ===")
harness.stdio.println(initial_envelope.text)
harness.stdio.println("")
const author_answer =
"Yes, the retry middleware is intended to wrap idempotent requests only; non-idempotent calls bypass it via the `safe: false` opt-out."
const clarification_prompt = render_clarification_prompt(
harness.fs,
diff.pr_number,
author_answer,
)
const final_envelope = harness.llm.call(clarification_prompt, system)
const receipt = {
persona: "review_captain",
execution_mode: "advisory",
approval_required: false,
repo: diff.repo,
pr_number: diff.pr_number,
files_reviewed: len(diff.files),
clarifying_question_asked: true,
clarifying_question_answer: author_answer,
final_verdict: final_envelope.text,
receipt_kind: "review_receipt",
}
harness.stdio.println("=== review_captain · stage 2 (final verdict) ===")
harness.stdio.println(json_stringify(receipt))
return receipt
}The agent runtime, built into the language
Orchestration, safety, and observability are primitives in Harn and its standard library, so they compose instead of fighting each other.
Pipelines are first-class
Compose work with the |> operator. Data and control flow read top to bottom, and the compiler tracks the shape of every stage.
LLMs and tools, built in
llm_call, agent_loop, tool vaults, MCP, reranking, and ensembles are language primitives, not a bolt-on SDK you assemble by hand.
Compile-time capability safety
Filesystem, network, and process access are capabilities checked before a single line runs. No surprise side effects inside an autonomous loop.
Deterministic replay
Every run records and replays. Step back through an agent's decisions, diff two runs, and debug non-determinism out of the system.
Durable steps and triggers
Checkpoint long-running work and resume after a crash. Fire pipelines from cron, webhooks, GitHub, Slack, and more.
Protocols, natively
Speak MCP, ACP, and A2A out of the box. Embed Harn in Rust, or run it as a server with harn serve.
Find your path
The documentation is organized around what you are trying to do.
Learn by building
Start from zero and build a working agent, MCP server, or eval pipeline step by step.
ExploreGet a task done
Recipes for the things you actually need: hooks, channels, pools, refactors, and more.
ExploreLook up the details
The complete language, runtime, standard-library, protocol, and CLI reference.
ExploreUnderstand the design
The reasoning behind the host boundary, sandboxing, and Harn's architectural decisions.
ExploreWrite your first pipeline
Install the CLI, write a few lines of Harn, and run a real agent in minutes.