Skip to content
Open source · Apache-2.0 · TypeScript

The coding agent you can hold accountable.

Arcturn is an open-source terminal coding agent and the TypeScript harness underneath it.

npm install -g arcturn

Node 20 or newer. See Getting started.

Allowed. The edit landed, and a checkpoint was written first.

An arcturn session. The header names the model and the working directory; a prompt asks for input validation on the /signup handler; Arcturn reads the route and greps for existing validation, then stops and asks permission before editing src/routes/signup.ts, offering allow, deny, or always-allow for src/**.ts. The edit is allowed: it lands as 24 lines added and 3 removed, a checkpoint is recorded for /rewind, LSP reports no errors, and the session's spend so far is shown against its budget.

The problem

Capability raced ahead of accountability.

The models write the code — that question is settled. The one I actually have is whether I can let an agent run, and, twenty minutes later, what exactly it did.

git diff is the whole forensic story.

Forty tool calls leave the residue of maybe twelve, in a flat pile, with no indication of which turn produced which hunk.

The shell commands leave no trace at all.

Fetches, background tasks, and the sub-agent that ran for ninety seconds and cost more than the rest of the session.

“Undo” means git checkout plus remembering.

The conversation that produced the change isn’t in version control, so going back means losing it.

Control

Decide once, at the choke point.

The runtime’s tool dispatcher checks the permission engine and returns a denial before a tool’s execute is ever reached — there is no second path. Rules are allow, deny or ask; scopes resolve session over project over user. Read-only tools pass. Anything that reaches the ask step with no permission requester configured resolves to deny, not “assume it’s fine.”

  • Four modes — default, acceptEdits, plan, yolo
  • --dry-run sends file mutations to a shadow tree for /diff before /apply
  • Lifecycle hooks can veto a preToolUse call
  • An opt-in OS sandbox confines bash writes to the workspace

A permission prompt in an arcturn session: editing src/routes/signup.ts requires approval, with allow, deny, and always-allow for src/**.ts offered.

Accountability

The session is the artifact.

Every session is a .jsonl file — a header line, then one JSON line per entry, appended in order. The structure is a tree: each entry carries a parentId, so resuming from three turns ago and trying a different approach starts a branch instead of overwriting what came after. Both branches stay walkable.

Underneath, every write and edit snapshots the file’s prior content first, so /rewind can restore it.

Replay, bisect and blame
arcturn replay <session>
Re-runs the original prompts against the same model or another one, emitting NDJSON per turn, so you can diff two runs mechanically.
arcturn bisect <session>
Binary-searches those prompts for the turn where behaviour diverged, replaying a recorded cassette hermetically: no provider, no network.
arcturn blame <file>
Per line, which turn wrote it and what evidence that turn had: files read, pages fetched, commands run, with anything from a fetch or an MCP server marked untrusted.

Models

Bring your own provider.

One interface across Anthropic, OpenAI and every OpenAI-compatible endpoint, Google Gemini, Bedrock, Vertex and Azure — streaming, tool calls, thinking, prompt caching and cost tracking included. Point --model at <provider>/<model>, route different roles to different models, or set a failover chain.

arcturn --model anthropic/claude-sonnet-4-5
arcturn --model openai/gpt-5.1
arcturn --model google/gemini-3-pro-preview

Receipts

What has actually run, and what hasn’t.

6 of the 9 provider paths have completed real multi-turn tool-calling sessions against a live endpoint. Another 3 have never reached their endpoints at all. Which is which is in the table, not in a footnote.

  • openai-compatible

    Any OpenAI-shaped endpoint, credentials per endpoint. Has completed real multi-turn tool-calling sessions.

    Proven
  • anthropic

    Claude, direct — ANTHROPIC_API_KEY, or an OAuth subscription sign-in. Verified live on Claude Haiku 4.5.

    Proven
  • openai

    GPT via Chat Completions — OPENAI_API_KEY. Verified live on GPT-5 nano.

    Proven
  • openai-responses

    GPT via the Responses API — OPENAI_API_KEY. Verified live on GPT-5 nano.

    Proven
  • google

    Gemini, direct — GOOGLE_API_KEY (GEMINI_API_KEY also works). Verified live on Gemini 3.5 Flash Lite.

    Proven
  • anthropic-compatible

    Any Anthropic-Messages endpoint, credentials per endpoint. Verified live against a canonical Messages API; no third-party implementation exercised yet.

    Proven
  • bedrock

    Claude, Nova, Llama, Mistral and Titan on AWS — the standard AWS provider chain.

    Not reached
  • vertex

    Gemini and Claude on Google Cloud — application-default credentials.

    Not reached
  • azure

    GPT on Azure OpenAI, addressed by deployment — AZURE_OPENAI_API_KEY or Entra ID.

    Not reached

Four waves of adversarial review went at the seams. They found /apply writing outside the workspace through an in-workspace symlink, served sessions and sub-agents escaping the audit trail entirely, a WebSocket upgrade with no Origin check, and two features that were present but unreachable. All four are written up on the security page rather than quietly patched out.

Every fix landed with a regression test verified to fail against the previous behaviour first.

Embed it

The same runtime, without a terminal in front of it.

@arcturn/core is what the CLI is built on. One Agent per session, one AgentEvent stream out — the same events the CLI emits with --output-format json.

agent.ts
import { createAgent } from "@arcturn/core";
import { createClient, requireModel } from "@arcturn/ai";
import { createDefaultTools } from "@arcturn/tools";

const llm = createClient(); // resolves API keys from the environment
const { tools } = createDefaultTools({ cwd: process.cwd() });

const agent = createAgent({
  llm,
  model: requireModel("anthropic/claude-sonnet-4-5"),
  systemPrompt: "You are a focused, careful coding agent.",
  tools,
  cwd: process.cwd(),
  sessionDir: ".arcturn/sessions", // omit for an unpersisted, in-memory agent
  permissions: { mode: "default" },
});

agent.subscribe((event) => {
  if (event.type === "toolStart") console.log("→", event.toolName);
});

await agent.prompt("Add input validation to the signup handler");
console.log(agent.finalText());
Embedding with the SDK

Open source

Apache-2.0, and checkable.

No commercial-use restriction, no source-available licence with a catch in clause four. One repository holds the CLI, the runtime, the harness and the regression tests behind the findings above — and the commands that check them are written down rather than described.

Every turn counts.

Start a session, watch every tool call ask first, then go back and read exactly what happened.

npm install -g arcturn