Skip to content
sitharaj88Public

About

AI coding agent that edits files runs commands and coordinates development work in a local repository

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Arcturn β€” every turn counts

npm license node CI

arcturn.dev Β· Getting started Β· Docs Β· SDK Β· Security Β· Blog


An agent now edits files in your working tree, runs shell commands, and spawns sub-agents that do both again with their own budgets. The interesting question stopped being can it write the code? It is can I let it? β€” and twenty minutes later, what exactly did it do?

Arcturn is an open-source terminal coding agent and the TypeScript harness underneath it, built around those two questions:

  • Every tool call clears a permission engine before it runs β€” rules, scopes, modes.
  • Every file edit is snapshotted first β€” /rewind restores files and forks the conversation back to any earlier turn.
  • Every session is a file on disk you can replay, bisect, and blame back to the exact tool call that made a change.
  • Reviewers in multi-agent pipelines structurally cannot merge code β€” not a prompt asking nicely, an execution lane that discards their diffs by construction.
Arcturn stopping at a permission gate: the edit tool asks before touching src/routes/signup.ts, with Allow once / Allow always / Deny options
The permission gate, mid-session: the agent wants to edit a file, and the next keystroke is yours.

Install

npm install -g arcturn

Node 20 or newer. pnpm add -g arcturn and bun add -g arcturn work the same way; npx arcturn runs it without installing.

export ANTHROPIC_API_KEY=sk-ant-...   # or OPENAI_API_KEY, GOOGLE_API_KEY, ...
cd your-project
arcturn                                # interactive TUI
arcturn -p "explain this repo"         # one-shot: run, print, exit
arcturn -p "..." --output-format json  # NDJSON event stream, for programs

What's in the box

πŸ›‘ Permission engine

Rule-based allow/deny/ask decisions resolved across session, project, and user scopes, with four modes β€” default, plan, acceptEdits, yolo. Deny beats yolo, always β€” that ordering is what lets a workflow confine a role to its worktree, and why the rules and the sandbox compose instead of fighting. Path matching folds case on case-insensitive filesystems β€” probed at runtime, not assumed from the platform, because .ENV should not walk past a **/.env deny rule on macOS.

// .arcturn/config.json
{
  "permissions": [
    { "tool": "bash", "specifier": "npm *", "action": "allow", "scope": "project" },
    { "tool": "read", "specifier": "**/.env", "action": "deny", "scope": "project" }
  ]
}

πŸ”’ A cloned repo runs none of its own code until you say so

<repo>/.arcturn can declare lifecycle hooks, a verify command, extensions and stdio MCP servers β€” all of which run as you, and a sessionStart hook runs before you have typed anything. Arcturn asks once, in a prompt that names every command and file, and refuses by default. Off a terminal β€” --print, CI, serve, acp β€” there is nobody to ask, so the answer is no: the run still completes, and says on stderr exactly what it did not run and the three ways to approve it.

The approval covers the project's contents, not its path. Editing src/, a README or a skill never re-asks; adding a hook, changing any file under extensions/, or declaring an MCP server does. Your own ~/.arcturn hooks and extensions are never gated β€” that is the difference between a gate and a nuisance.

$ arcturn trust --list      # exactly what this project would run
$ arcturn trust --allow     # approve it for these contents
$ arcturn -p "..." --trust-project   # CI that already trusts the checkout

Known edges are documented rather than implied: a hook command is a pointer into your shell, so Arcturn cannot see what the files it invokes will contain later. See docs/integration-notes/INTEGRATION-project-trust.md.

βͺ Checkpoints & /rewind

Every edit is snapshotted before it lands. /rewind restores the files and forks the conversation back to that turn β€” the session is a tree, not a list, so the branch you rewound away from still exists. /rewind <query> jumps by intent.

🎞 Sessions you can replay, bisect, and blame

Sessions persist as JSONL trees. arcturn replay re-runs one hermetically, arcturn bisect finds the turn where behaviour changed against a recorded cassette, and arcturn blame traces any file change back to the session, turn, and tool call that made it. Cost and token usage ride the same stream β€” --max-cost 2.00 is a hard abort, not a suggestion.

πŸ€– Workflows & agent organizations

A numbered markdown file is a multi-stage pipeline. @role dispatches a step to a named markdown agent with its own model, tools, and turn ceiling:

---
name: ship-fix
budgetUsd: 15
---
1. @qa-functional Write a regression test that FAILS against the current code: {{input}}
2. @developer Make it pass. Repro: {{prev}}
3. - @qa-adversarial Try to break the fix from a fresh reading of the diff. {{prev}}
   - @security-reviewer Audit the change for anything a hostile caller could exploit. {{prev}}
4. @tech-lead Assemble the evidence packet. Do not merge anything yourself. {{prev}}

Three dispatch lanes decide what a role can touch, derived from its tools, never from its description: read (no worktree), exec (isolated worktree, diff always discarded), write (worktree, diff captured and applied). A reviewer cannot land code β€” bash is a write primitive wearing a read costume, and the lane knows it. Worktrees are seeded with the run's already-applied patches, so reviewers read what the pipeline actually produced, not untouched HEAD.

Runs are journalled and resumable: /workflow status shows what an interrupted run reached and its spend; /workflow resume re-enters it, replaying completed steps rather than paying for them twice, and probing every recorded patch with git apply --check --reverse so nothing lands twice. A role that hits real ambiguity emits ORG-ASK: and the whole run pauses for a human answer, then continues exactly where it stopped. Per-run budgetUsd: and per-step stepTimeoutMs: ceilings bound the two things that actually run away.

A step can promise a typed reply with [contract:…]; on a model that takes a JSON schema (Claude 4.5+, OpenAI, Gemini 2.5+) the contract is sent as a native response schema instead of a fenced block to be hunted for, and the same validator still judges it. [budget:<tokens>] gives a step a task budget on the Claude models that support one, so it paces itself rather than being cut off at the turn ceiling.

A runnable ten-role, six-pipeline enterprise kit ships in kits/enterprise-org/, documented alongside an honest account of what is enforced and what is still convention.

πŸ”Œ MCP, both directions

Connect stdio and HTTP Model Context Protocol servers (OAuth 2.1 included) and their tools, resources, and prompts just work. Or invert it: arcturn mcp-serve exposes Arcturn as an MCP server so another agent can drive it β€” read-only by default, behind a workspace boundary enforced by permission rule and a physical path check, with the peer assumed hostile. The boundary's audit trail is public: see the security page.

Servers can also ask back. An MCP elicitation opens a form in the TUI (and is declined, never auto-accepted, where nobody is at a terminal); every one is audited by field name, never by answer. Sampling, a server asking your model for a completion, is off unless that server's mcp.json entry says "sampling": true, runs as one isolated call, and is billed to the session and its --max-cost.

🌐 Multi-provider, honestly labelled

Provider Verified against a live endpoint
Anthropic (Messages API) βœ…
OpenAI β€” Chat Completions and Responses API βœ…
Google Gemini βœ…
Any OpenAI-compatible endpoint βœ…
Any Anthropic-compatible endpoint βœ…
AWS Bedrock · Vertex AI · Azure OpenAI ⚠️ implemented, not yet verified live

Streaming, tool calls, thinking, prompt caching, and cost tracking across all of them. "Verified" means a real request to the real endpoint: streaming, a tool call answered on a second turn, and cost accounting checked against published rates β€” the story of why that column exists is worth two minutes. A per-event idle timeout (not a duration cap) means a slow but progressing stream is never killed while a stalled one is. /model refresh queries each provider's own model list and merges newly released models without touching curated entries.

πŸ” Code search without an embedding service

A BM25 + structural index over the workspace powers a search_code tool that finds code by meaning. Nothing leaves your machine.

🧠 Context engineering

Automatic compaction, context editing, tool-output offloading, and deferred tool schemas loaded on demand via tool_search β€” a long session stays inside the window without silently dropping what mattered, and the history only ever grows at the end, so the prompt cache and the thinking Claude's newest models bind to it survive.

🧰 And the rest of a working day

Built-in tools (read, write, edit, bash with background execution, grep, glob, ls, fetch, websearch via Brave or DuckDuckGo, or Anthropic's own web search and fetch if you set websearch.provider: "anthropic") Β· LSP diagnostics appended to every edit (TypeScript, Python, Go, Rust) Β· markdown skills as slash commands with no build step (.arcturn/skills, frontmatter, $ARGUMENTS) Β· lifecycle hooks that can veto a preToolUse call Β· fuzzy @file mentions with image attachment Β· plan mode and structured todos living in the session tree Β· sub-agents, /team, /scout, and /bg for parallel work Β· an opt-in OS sandbox confining bash writes to the workspace Β· full light/dark theming down to the terminal canvas itself (OSC 11) Β· live cost and context meters in the status bar.

Embed it: the SDK

The CLI is a consumer of @arcturn/core β€” everything it does, your program can do:

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-5-5"),
  systemPrompt: "You are a focused, careful coding agent.",
  tools,
  cwd: process.cwd(),
  sessionDir: ".arcturn/sessions",
  permissions: { mode: "default" },
});

agent.subscribe((event) => {
  if (event.type === "toolEnd") console.log(event.result.isError ? "βœ—" : "βœ“", event.toolCallId);
});

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

One Agent per session, options in, events out β€” the same event stream the TUI renders and the CLI prints as NDJSON. Start at the SDK docs.

Packages

Package Description
arcturn The interactive coding agent, workflow engine, and agent-org runtime
@arcturn/core Agent runtime: event loop, steering, sessions, compaction, permissions, sub-agents
@arcturn/ai Unified multi-provider LLM streaming client with model catalog and retry
@arcturn/types Zero-dependency shared contracts (messages, events, tools, permissions, sessions)
@arcturn/tools Built-in tools: read, write, edit, bash (+background), grep, glob, ls, fetch
@arcturn/mcp Model Context Protocol client bridge β€” internal, API may change in any release
@arcturn/tui Terminal UI library with differential rendering β€” internal, API may change in any release
@arcturn/index Token-optimized code index and BM25 semantic search β€” internal, API may change in any release
@arcturn/protocol NDJSON wire protocol for server mode β€” internal, API may change in any release
@arcturn/server WebSocket server exposing agent sessions β€” internal, API may change in any release
@arcturn/evals Task-level eval harness (in-repo only, not published)

@arcturn/types, core, index, and protocol carry no external runtime dependencies at all β€” nothing in the layer that decides whether a tool call runs comes from outside this repository.

Documentation

arcturn.dev/docs β€” 44 pages: a CLI reference for every flag and slash command, permissions, workflows, agent organizations, the SDK, and the security limits page that states every control's known edges as content, not fine print.

From the blog, the three stories that explain the project's temperament: Why I built an agent harness you can audit Β· Three providers, three bugs, under two cents Β· Reviewers who cannot merge

Platform support

Arcturn runs on macOS, Linux, and Windows β€” CI builds and tests all three on Node 20 and 22 (.github/workflows/ci.yml). Windows differences worth knowing:

  • The bash tool and lifecycle hooks run commands through %ComSpec% (cmd.exe by default), not a POSIX shell, so agent-authored commands with POSIX idioms (&&-chained builtins, $(...), single-quoted strings) may not run as written.
  • The opt-in sandbox: "workspace-write" filesystem sandbox is macOS (sandbox-exec) and Linux (bwrap) only; on Windows it runs unconfined and says so explicitly rather than silently claiming confinement.
  • Windows support is newer than macOS/Linux. If you hit a rough edge, WSL2 is the smoothest path to the same POSIX shell and sandbox this project runs on day to day.

Development

git clone https://github.com/sitharaj88/arcturn.git
cd arcturn
pnpm install
pnpm build     # build all packages
pnpm check     # lint + typecheck
pnpm test      # run all tests

Node.js β‰₯ 20 and pnpm β‰₯ 10 required. See PLAN.md for architecture, the status ledger, and the roadmap β€” including the corrections, which stay in the record rather than getting laundered out of it.

Issues and pull requests are welcome. The engineering bar to know about up front: fixes land with a regression test that was verified to fail first, and claims of verification are reserved for things that have actually run.


πŸ‘€ Author

Sitharaj Seenivasan

β˜• Support

If this project helps you, consider buying me a coffee β€” it keeps the work going.

Buy Me A Coffee

πŸ“„ License

Licensed under the Apache License 2.0. Β© 2026 Sitharaj Seenivasan.

About

AI coding agent that edits files runs commands and coordinates development work in a local repository

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages