Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

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.

  • 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.

harn demo review-captain

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.

review-captain/scenario.harn
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.

Write your first pipeline

Install the CLI, write a few lines of Harn, and run a real agent in minutes.