What is Arc
Arc is a version control system built for the age of AI agents. Instead of staging, committing, and pushing, Arc captures continuous snapshots of your working directory as you code. Every meaningful change is recorded automatically — no ceremony, no context switching.
Traditional VCS was designed around a human workflow: think about what changed, stage it, write a message, commit, push. That made sense when one person typed code into one file at a time. It breaks down when an AI agent is rewriting four files in parallel, a second agent is running tests, and you're reviewing the output — all in the same minute.
Arc replaces that ceremony with a continuous, observable substrate. Changes flow in. History accumulates. Agents and humans query it when they need context. Nobody stops to commit.
Quick Start
Starting a new project? Two steps — install, then point Arc at the project. The daemon starts capturing immediately.
# 1. Install
curl -fsSL https://arc.daystra.com/install.sh | sh
# 2. Initialize in any project
cd my-project
arc init
# That's it. arc init sets up everything:
# .arc/ — snapshot database + object store
# .arcignore — default ignore patterns
# .mcp.json — MCP server config (auto-discovered by Claude Code)
# .claude/settings.local.json — wildcard MCP permissions (zero friction)
# .claude/skills/ — arc-source-control skill for agent onboarding
# First moves
arc status # check capture is live
arc snapshots # see what changed
arc snapshot diff 20 25
arc intent declare "Add user authentication"
# Send feedback to the Arc team
arc feedback --bug "something broke"
arc feedback --feature "would love arc diff --stat"
Joining a project that already lives on a relay? One command. Which one depends on where the relay is:
- Filesystem relay (local volume, NAS, mounted server) — no credential needed; clone straight from the path:
arc clone /Volumes/backup/arc. It creates the project directory, wires up the relay, pulls the full history, and writes the files to disk. - R2 relay (off-machine, credentialed) — the owner mints a read-only invite bundle (a JSON file you treat like a password):
arc relay invite --relay my-arc --out invite.json. You clone it witharc clone --bundle invite.json.
# On the new machine — install once
curl -fsSL https://arc.daystra.com/install.sh | sh
# Filesystem relay — clone straight from the mounted path (no JSON, no credential)
arc clone /Volumes/backup/arc # creates the project dir, pulls history, writes files
# R2 relay — owner mints a JSON invite, you clone with it
# owner runs: arc relay invite --relay my-arc --out invite.json (share it like a password)
arc clone --bundle invite.json # creates the project dir, pulls history, writes files
cd && arc status # you're current — full history, files on disk
# Already ran `arc init` in a directory there? Wire the relay in instead of cloning:
arc remote add /Volumes/backup/arc --pull # filesystem
arc remote add --bundle invite.json --pull # R2
arc sync pull --materialize # writes the project files to disk
How It Works
- Snapshots, not commits. A daemon watches your filesystem and captures snapshots automatically when changes settle. Every snapshot is content-addressed and immutable, stored by BLAKE3 hash. No staging area, no commit messages.
- Intents, not branches. Declare what you're working on with
arc intent declare "goal". Arc tracks which snapshots relate to which intent. Complete, abandon, or merge when done. - Sync at the boundary. When you call
arc_intent_complete, Arc captures any pending edits synchronously before reading — so the change set you ship is the change set you actually made, even if the daemon's idle timer hasn't fired yet. - Layered config. Global in
~/.arc/config.toml, project in.arc/config.toml, env vars on top. Everything composes cleanly. - Content-addressed storage. Files deduplicated by content hash. Store the same file in a hundred snapshots — one copy on disk.
- Ed25519 identity. Every actor (human or agent) gets a cryptographic identity, and records are Ed25519-signed when synced — so you can verify who made what change.
- Secret-safe capture. Capture scans every change for secrets — per your policy it blocks the snapshot or masks the matched bytes (API keys, tokens) before they ever reach the substrate.
arc secrets policytunes it.
Relay Sync
A relay is the safe, off-machine copy of your substrate — every snapshot, intent, and signed record. More than a backup: one relay gives you durable redundancy, keeps a second machine current, and brings a fresh clone up to speed. Pushes are incremental and content-addressed; restoring — or standing up a new machine — is a single arc clone.
- The remote you already trust, without the ceremony. Push your work somewhere safe — no force-push tangles, no conflict markers on disk, no history to rewrite.
- Delta, not dumps. The first push seeds your history once; after that only changes move, deduped by hash across the whole relay.
- You hold the keys. Records stay Ed25519-signed end to end and the bucket is yours. Arc mints a least-privilege token scoped to that one bucket — nothing more.
- Invite there, clone here. Mint a read-only invite bundle on the owner machine; on the receiver, one command stands up the whole project — init, remote, pull, and files on disk.
# Set up a relay — an off-machine copy. Two ways:
arc remote add /Volumes/backup/arc # local volume, NAS, home server — just a path
arc relay provision --backend r2 --bucket my-arc --push # Cloudflare R2 — one command: bucket + scoped token + wired
# Receive it on any machine — ONE command: init + wire + pull + materialize
arc clone /Volumes/backup/arc # filesystem — no credential needed
arc clone --bundle invite.json # R2 — from a read-only invite
# Share an R2 relay: mint a read-only invite, hand it over like a password
arc relay invite --relay my-arc --out invite.json
Where it lives is your call:
- Local / NAS / server — any mounted path. Available now.
- Cloudflare R2 — turnkey one-command provisioning, zero egress fees.
- Amazon S3 & S3-compatible (MinIO, Backblaze B2, …) — same transport engine; turnkey provisioning on the roadmap.
Worktrees, Snapshots, and the Timeline
Arc's mental model is a base timeline with worktree spurs. Snapshots chain. Worktrees fork off the chain when you declare an intent and merge back when you finish.
- Snapshots are immutable nodes. Each snapshot has a parent. Reading a path at any snapshot reconstructs the tree that existed at that moment. Nothing is rewritten.
- Worktrees are physical APFS clones. When you
arc intent declare, Arc forks an isolated copy of the project. The daemon watches it. Captures live in their own chain, tagged withworktree_id, so they don't pollute base history until merge. - Merges write a new base snapshot.
arc_intent_mergepreviews the three-way diff (fork ancestor, current base, worktree head) and on execute writes a single merge snapshot to the base timeline. Conflicts surface as structured data, not file-on-disk markers. - Abandon means no merge. An abandoned worktree's snapshots stay in the timeline for inspection but don't reach base. The branch ends; the history doesn't.
- Inline intents are first-class. If your work doesn't need isolation, skip the worktree — declare an intent against the base directory directly. The same snapshot/intent linking applies. Worktrees earn their tax only on concurrency or destructive-muscle-memory containment.
The Agent Architecture
Arc ships with an MCP (Model Context Protocol) server that gives AI agents structured, native access to history and state. No shell parsing. The MCP entry point (arc mcp-server) and the daemon (arc serve) run as separate processes — see Multi-Terminal Sessions for how that unlocks running multiple agents on one project.
Architecture diagram — agents → MCP → core → storage
Multi-Terminal Sessions
Arc runs multiple Claude Code sessions against the same project simultaneously. Each session gets its own MCP server process; all coordinate through a single daemon (arc serve) that owns the file watcher, capture pipeline, and singleton lock. The daemon is a separate process, kernel-enforced singleton via flock(2) — multi-daemon races are impossible by structure, not by policing.
How it's wired — sessions, sockets, and the singleton lock
- One daemon per project, enforced by the kernel.
arc serveacquiresflock(LOCK_EX)on.arc/daemon.pidat startup. A secondarc servein the same project sees the lock, prints "daemon already running, PID N", and exits cleanly. Multi-daemon races are impossible by structure, not by policing. - One MCP server per session. Claude Code launches
arc mcp-servervia.mcp.jsonwhen you open the project. The MCP server connects to the daemon over.arc/daemon.sockand forwards tool calls. If no daemon is running, the MCP server auto-spawns one (detached subprocess; reparented tolaunchdso it survives session exit). - Each session can declare its own intent. Sessions don't share state at the application level — each agent can fork its own worktree via
arc_intent_declareand work in isolation. Conflicts only arise when intents merge back, and at that point both agents' rationale and the full diff are available to inform the resolution. - Optional: keep the daemon alive across logins. On macOS,
arc daemon installwrites a launchd plist that auto-starts the daemon at login and respawns it on crash.arc daemon uninstallremoves it.
Multi-session has been stable across several releases. Long-lived deployments and very-large concurrent fleets are still earning miles; file an arc feedback if behavior surprises you.
Zero-Friction Agent Setup
arc init wires everything agents need in one command:
.mcp.json— MCP server config. Claude Code (and other MCP-compatible editors) auto-discoverarc mcp-serveras an available server, which connects to the project's daemon (arc serve). No manual configuration..claude/settings.local.json— pre-authorized wildcard permission (mcp__arc__*). Agents never get blocked by permission prompts for Arc tools. Zero friction, zero popups..claude/skills/arc-source-control/SKILL.md— an onboarding skill that teaches new agent sessions how to use Arc. A fresh agent drops into your project, reads the skill, and knows how to take snapshots, declare intents, and query history — no human explanation needed.
How an agent session works: When Claude Code (or any MCP-compatible agent) connects to your project, it discovers Arc's tools automatically. The first thing it typically calls is arc_context — which returns the project's current state: active intents, recent snapshots, config, and hints about what tools to call next. From there, the agent can query history, declare intents, take snapshots, and navigate diffs — all without shelling out to a CLI.
Agent Compatibility
Arc is model-agnostic and provider-agnostic. It doesn't care which AI is driving — it just needs the agent to speak MCP.
- Claude Code (Anthropic) — full integration, primary development environment. MCP tools auto-discovered;
arc-source-controlskill teaches new sessions without human explanation. - Cursor, Windsurf, Cline — native MCP support. Add
arc mcp-serverin their settings and agents get all Arc tools. - Any MCP client — Arc speaks standard MCP over stdio. No vendor lock-in.
Where it stands with OpenAI, Gemini, Grok, Copilot
- OpenAI / ChatGPT — OpenAI has announced MCP support. As their tooling matures, Arc's MCP server will work out of the box.
- Google Gemini — Gemini CLI and Google's agent tooling are adding MCP support. Arc will work automatically once the MCP client is available.
- xAI Grok — if and when xAI's agent tooling supports MCP, Arc is ready.
- GitHub Copilot — does not currently support MCP. If it adds MCP support in the future, Arc will work with it automatically.
The Human Experience
Arc is agent-first but not agent-only. As a solo developer, here's what changes:
- You stop thinking about commits. Run
arc init, start coding. The daemon watches your filesystem and captures snapshots when changes settle. You never have to decide "is this worth a commit?" because everything is captured. - You get time travel for free.
arc snapshotsshows your history.arc snapshot diff 20 25shows what changed between any two points.arc reset 15takes you back. No staging, no stashing. - You declare intent, not branches.
arc intent declare "refactor auth"tells Arc what you're working on. When you're done,arc intent complete. No merge conflicts with yourself. - Your agent understands your project. When Claude Code connects to an Arc-tracked project, it immediately has context — what's changed recently, what intents are active, what the project looks like right now. No digging through history to figure out what's going on.
The Story Reads Itself
Arc is built for the agents — but what changed, and why is the question that belongs to the human. Every team answers it four times over: a wiki for how it fits together, a task board for what was planned, a story for why it mattered, and the source for what actually happened. Four tools, four copies of the truth, four chances to drift — and a standing human tax to keep them in sync. They rot because they're hand-curated: the moment the code moves, every other copy is stale.
Arc collapses the four. The source already holds the snapshots and the intents — so the story is generated from them, never re-typed; the task is the intent you declared; the wiki writes itself. Nothing to reconcile, because there is only one source — and the narrative is read from it on demand, so it cannot go stale.
That's arc recap — one question-shaped command for the human in the loop:
arc recap last-week # what shipped, grouped by intent
arc recap last-30d # a month at a glance
arc recap --path crates/arc-core # what changed in one corner, and which functions
It answers straight from the substrate — the intents that landed, the files that moved, the functions touched — deterministically, with no model in the loop and nothing to curate. The standup write-up, the "what did we do last week," the cold-start briefing for whoever (or whatever) joins next: one query, always current, because the substrate is the only thing it reads.
Narration
Arc can automatically narrate your snapshots using AI — human-readable descriptions of what changed and why, without you writing a single commit message. Pluggable: Anthropic, OpenAI, Gemini, Grok, or local Ollama. You pick the backend. It's off by default — nothing leaves your machine until you turn it on. When enabled, narration sends each snapshot's change context to the backend you choose: a cloud provider receives your diffs, while the local Ollama option keeps everything on-machine.
Provider list and config example
- Anthropic Claude API — set your API key and Arc calls Claude to narrate snapshots with full context
- OpenAI API — point
narration.base_urlat OpenAI's chat completions endpoint, set your model (e.g.,gpt-4o) - Google Gemini API — use Gemini's OpenAI-compatible endpoint
- xAI Grok API — xAI's API is OpenAI-compatible, works with the same config pattern
- Ollama (local) — run a local model, no API key needed, no data leaves your machine
- Any OpenAI-compatible endpoint — configure
narration.base_urlto point at any API that speaks the OpenAI chat completions format
Configure in ~/.arc/config.toml or per-project in .arc/config.toml:
[narration]
mode = "auto"
base_url = "http://localhost:11434/v1" # Ollama
model = "llama3.2"
The Hidden macOS Spotlight Tax Paid by Devs
If your Mac fan spins up when nothing seems to be running, it's probably mdworker_shared — Spotlight's sandboxed importer worker, spawned by mds to read every file the indexer wants to know about. Spotlight indexes everything by default — including the gigabytes of build output, dependency caches, and AI-agent-generated churn that nobody ever searches for by name. Every solo dev running AI agents on a Mac is paying this tax. Most don't know to look.
Arc thinks about this at the systems level, not just the source-control level. arc init drops a .metadata_never_index sentinel in .arc/ automatically — tells Spotlight to skip the substrate's high-churn content-addressed object store. arc doctor flags drift if the sentinel goes missing; arc doctor --restore-path-inert --commit re-drops it. The same instinct mitigates antivirus CPU on the same hot paths (AV exclusion is per-app in System Settings rather than per-path, but the FSEvents budget they compete for is the same one).
The asymmetry to know about (and how to fix it once)
The sentinel only prevents new Spotlight indexing. If Spotlight has already indexed your .arc/objects/ tree (likely if you've been running Arc for a while), you need to erase the existing index once:
mdutil -E /path/to/your/project/.arc
mdutil -s /path/to/your/project/.arc # verify status
Without that erase step you'll keep paying CPU on already-indexed content even with the sentinel in place.
The bigger offenders aren't always Arc-managed
Build-output and dependency directories chew far more Spotlight CPU than .arc/ ever will. Drop the same sentinel in the ones your project uses:
touch node_modules/.metadata_never_index # JS/TS
touch target/.metadata_never_index # Rust
touch .venv/.metadata_never_index # Python
touch vendor/.metadata_never_index # Go, Ruby, PHP/Composer
touch _build/.metadata_never_index # Elixir
touch build/.metadata_never_index # generic / Java / Swift
touch .gradle/.metadata_never_index # Gradle
touch DerivedData/.metadata_never_index # Xcode
# Erase any existing index for those dirs (one-time):
mdutil -E node_modules target .venv vendor _build build .gradle DerivedData 2>/dev/null
Want the recursive, repo-aware version? This bash script walks a project root and drops the sentinel for you. It uses always-safe names (node_modules, .venv, __pycache__, etc.) plus sibling-marker checks for generic names (e.g. target/ only when there's a Cargo.toml next door, vendor/ only with go.mod/Gemfile/composer.json). Supports --dry-run and refuses to scan / or $HOME without --force.
On other operating systems (this is not just a macOS problem)
Spotlight isn't unique. Every desktop OS ships a background indexer that walks high-churn build dirs by default:
- Windows — Windows Search indexes via
SearchIndexer.exe. Exclude paths in Settings → Privacy & Security → Searching Windows → Add an excluded folder. PowerToys Run and Everything (voidtools) are popular replacements that don't need a background indexer. - Linux — GNOME uses
tracker-miners(config at~/.config/tracker/); KDE uses Baloo (balooctl status, ignore dirs in~/.config/baloofilerc). On either, the cross-desktop launchers Ulauncher or Albert can replace the indexer entirely if you don't use content search.
The other CPU sink — on every platform — is your antivirus or EDR agent. If mdworker_shared (or its equivalent) is quiet but the fans are still loud, the AV is scanning every file your tools touch. On managed laptops the exclusion lives in your org's security console (CrowdStrike Falcon, SentinelOne, Sophos, Defender for Endpoint, Jamf Protect, Carbon Black, Trellix); on personal machines, the AV's own UI. The Spotlight sentinel only solves half the problem when an agent is also watching.
Feedback
Arc is built to be run by agents — so let the agent file the report. When Claude Code hits a rough edge (a confusing tool, a missing capability, something that broke), it can log it without leaving the session, from the CLI or the arc_feedback MCP tool:
- Report a bug —
arc feedback --bug "what broke" - Request a feature —
arc feedback --feature "what you want" - Leave a note —
arc feedback "anything else"
Every entry lands in ~/.arc/feedback.md and, once you opt in, syncs to the Arc team. We read all of it and work it — the friction your agent hits is what shapes the roadmap.
Update anytime with arc update. Pin a specific version with VERSION=0.9.30 curl -fsSL https://arc.daystra.com/install.sh | sh.
How agents discover Arc on session start
When Claude Code (or any MCP-compatible agent) opens a project, it looks for .mcp.json in the project root. Arc's entry points it at arc mcp-server, which connects to the project's daemon (auto-spawning one if needed). From there:
- The agent discovers 38 tools via the MCP handshake — snapshots, intents, queries, config, diffs, reset, retroactive purge, doctor probes, worktree management, and more
- It calls
arc_contextfor a cold-start briefing — active intents, recent decisions, stale warnings, and setup hints - If no intent is active,
arc_contexttells the agent to declare one before doing any work — with an example call and a pointer to the full lifecycle protocol - If an intent is active, hints guide the agent through progress logging, completion, and merge
- The
arc-source-controlskill (installed to.claude/skills/) teaches the agent Arc's workflow without human explanation - New tools added in updates are surfaced automatically via
arc_contexthints
Known setup notes — permissions, config locations, upgrades
- MCP permission prompts. Claude Code asks before calling MCP tools for the first time.
arc initpre-authorizes all Arc tools by writingmcp__arc__*to.claude/settings.local.json. If you see a permission prompt, runarc initin that project to fix it. - Project-level config (
.claude/). Arc creates three files in your project duringarc init:.mcp.json(MCP server config),.claude/settings.local.json(permission wildcards), and.claude/skills/arc-source-control/SKILL.md(agent onboarding). - Global config (
~/.arc/). Arc stores global config at~/.arc/config.toml(narration, sync relays, feedback preferences), binary at~/.arc/bin/arc, feedback at~/.arc/feedback.md. Per-project data lives in.arc/inside each repo. - Non-destructive version upgrades. When Arc detects a version change (after
arc update), it re-wires.mcp.json, permissions, and the onboarding skill in every project on next use. Existing config is merged, not overwritten. - MCP server restarts on update. After
arc updatereplaces the binary, the nextarc mcp-serverspawn runs the new version. The daemon picks up updates on its next restart (launchctlhandles this if installed viaarc daemon install). Active Claude Code sessions need to restart to pick up new tools.
macOS (Apple Silicon) · MIT License · Built by humans and agents, tracked by Arc