A CLI for tracking the arc of AI-assisted projects end-to-end. Each project lives as an Obsidian note with YAML frontmatter; arc drives the full lifecycle from GitHub issue to merged PR using your coding agent of choice (Claude, Cursor, Codex) for planning, implementation, code review, and informal chatting.
When you're working on multiple projects in parallel, context gets scattered — across GitHub issues, Obsidian notes, web clippings, and your codebase. You lose track of what's running where, which branch is which, and the current stage of ongoing projects.
arc is opinionated. It bakes in the development patterns and preferences I've landed on after months of working with agents. I built it to solve some very specific problems in my workflow, some of which may or may not be relevant to you. That said, the problems it solves are general. If you're feeling the friction of context switching, parallel development, tracking project status, and documenting agent sessions across long-running AI-assisted projects, then arc might be useful to you as-is. Or at least as a starting point for building your own version. The customization guide is written specifically to help your coding agent of choice adapt arc to your repo, your tools, and your workflow.
The specific problems arc solves:
- Context management: Pulls together GitHub issues, Obsidian notes, and repo state into a single project view. Plans, clippings, and related notes are automatically linked and fed to agents as progressively disclosed context. Notes and plans get updated after every conversation.
- Parallel development: Each project gets its own isolated git clone (not a worktree — a lightweight clone), its own feature branch, and optionally its own dev server, all sharing a common local database (my personal preference, ymmv).
- At-a-glance status: The dashboard shows all active projects — development and non-development — with their current stage, branch, PR status, and running tmux sessions.
- Automate the predictable parts: Code review, CI monitoring, branch management, and PR creation are tedious but mechanical. arc handles them so you can focus on more interesting things without dropping the ball.
1. arc sync / arc new → Pull GitHub issues or create a project from scratch
2. arc plan → Collect context from Obsidian + GitHub, break into stages
3. arc sandbox / arc dev → Create isolated clone, optionally launch dev server
4. arc implement → Coding agent implements (interactive or background)
5. arc review → AI code review
6. arc diff-review → Manual (human) diff review in VS Code (Local PR Review extension)
7. arc address-review → AI addresses your review comments
8. arc approve → Push, open PR, continuous CI monitor with auto-fix
9. arc done / arc archive → Mark complete, clean up sessions/sandbox
At any point during a project's lifecycle, you can drop in for human-in-the-loop work:
arc chat <slug>— start a conversation with full project context loaded. Good for brainstorming, asking questions about the codebase, or thinking through a tricky decision without launching a full implementation session.arc note <slug>— jump straight to the project's Obsidian note. Review plans, check session history, or update the objective.arc editor <slug>— open the project sandbox in VS Code (or Cursor with--cursor) with the changed files pre-loaded, so you can review a diff or make a quick manual edit.
These aren't part of the linear workflow — they're escape hatches for when you want to check in, steer, or just read what's happened.
- Not everything needs an agent — arc makes it easy to jump between Obsidian, VS Code/Cursor, and the terminal.
arc note,arc editor, and the dashboard are quick-nav commands, not AI wrappers. - Separate implementation and review — use one model to implement, then another to review. You can configure the model/provider on every command. Or skip AI review and review the diff yourself. The steps are decoupled.
- Obsidian as the knowledge layer — project context, plans, clippings, and related notes all live in your vault. The vault organizer automatically tags and cross-links new notes to active projects.
- Project-aware sessions — the
ARC_PROJECT_SLUGenv var is set before every Claude launch, so your Claude Code status line and hooks can show which project you're working on. - Lightweight clones, not worktrees — each sandbox is a complete git clone via
--reference, so you get full isolation with minimal disk cost. Dev servers can run in parallel on different ports sharing a common local database. You can easily pull from the main branch, and don't have to worry about worktrees. - CI monitor with auto-fix — after opening a PR, arc polls CI status and can automatically invoke Claude to fix failures and push.
- Python 3.11+
uv(script runner —arcuses uv inline scripts, no virtualenv needed)claudeCLI (Claude Code)codexCLI —npm install -g @openai/codex(for code review; optional if using--tool claude)ghCLI (authenticated)tmux,git- Obsidian — all project state lives in your vault as Markdown notes
- VS Code or Cursor —
arc editoropens sandboxes in your editor (use--cursorfor Cursor) - macOS (uses
osascriptfor notifications; Linux users can swap fornotify-send)
git clone https://github.com/ehutt/arc.git
cd arc
arc init # interactive config setup — or copy config.example.toml to config.tomlMake arc.py your CLI entry point:
# Option A: alias
echo 'alias arc="uv run --script ~/path/to/arc/arc.py"' >> ~/.zshrc
# Option B: symlink
ln -s ~/path/to/arc/arc.py ~/.local/bin/arcProject slug autocompletion is built in via Typer — tab-complete works for all commands that take a <slug> argument.
| Command | Description |
|---|---|
arc |
Dashboard: status, stage progress, branches, tmux sessions |
| Project Management | |
arc sync |
Pull GitHub issues and sync PR status from the configured repo (reconciles sandbox branches first) |
arc reconcile |
Reconcile vault state against sandbox git reality: branch, last_activity (latest commit), planned→active promotion, orphan-sandbox report. --dry-run to preview. Scheduled nightly via launchd. |
arc note <slug> |
Open a project's Obsidian note |
arc new <title> |
Create a new project note without a GitHub issue |
arc done <slug> [stage] |
Mark a stage (or whole project) as done — auto-promotes next stages to ready; closing the whole project stops sessions and removes its sandbox. Use --skip to skip instead. |
arc archive <slug> |
Shelve a project without completing it — kills sessions and always preserves the sandbox for later. Use when pausing or abandoning work. |
| Planning | |
arc plan <slug> |
Interactive planning session (Claude by default; --codex for Codex) |
arc stage <slug> |
List stages; --add "name" to add, --depends-on 1,2 for deps, --plan <id> to plan a stage (--codex for Codex) |
| Development | |
arc sandbox <slug> |
Create an isolated git clone with a feature branch |
arc implement <slug> |
Implementation session; --bg for autonomous tmux mode, --codex to use Codex instead of Claude |
arc editor <slug> |
Open sandbox in VS Code (or Cursor with --cursor) with changed files |
arc dev <slug> |
Launch dev server in a background tmux session |
| Review & Ship | |
arc review <slug> |
AI code review (--tool codex or --tool claude, --model to override). Add --thorough for a multi-lens review, or --debate for an adversarial Codex-reviews / Claude-fixes loop. |
arc pr-review <number> |
Review someone else's PR by number: checks the PR out into a pr-<n> sandbox (created on demand), creates a lightweight pr-review project, and runs an approval-biased read-only review (--thorough / --debate supported). Writes a local report ending in RECOMMENDATION: APPROVE or REQUEST-CHANGES; never posts to GitHub unless --comment. |
arc diff-review <slug> |
Open VS Code with a Local PR Review session pre-seeded against the sandbox (base→branch diff with inline-comment gutter). Installs the extension on first run. |
arc address-review <slug> |
Hand the unresolved comments from the diff-review session to Claude/Codex to fix or reply, then mark addressed threads resolved. |
arc approve <slug> |
Push branch, create PR, and launch CI monitor |
| Knowledge | |
arc search <query> |
Natural-language vault search. Lifecycle/folder filters parsed from the query itself (e.g. "evergreen notes on RAG" or "skip old blog drafts"). Clickable Obsidian links in output. |
arc lint |
Read-only vault health report: notes missing lifecycle frontmatter, project status contradictions, folders without index.md, dead wikilinks. |
arc migrate-lifecycle |
One-shot: tag every vault note with lifecycle: + source_type: frontmatter. Idempotent. --dry-run to preview. |
| Utilities | |
arc init |
Interactive setup — create config.toml from prompts |
arc chat <slug> |
Informal chat with project context (Claude by default; --codex for Codex) |
arc organize |
Run the vault organizer (tag & link notes) |
arc cleanup |
Remove clean, commit-free sandboxes for done projects, then move done/archived project folders to the vault archive (--dry-run to preview). Archived-project sandboxes are preserved. |
Every note in the vault carries a lifecycle and source_type in its frontmatter. These drive how organize.py treats the note (what it can edit vs. leave alone) and power arc search.
Lifecycle classes:
live— active project indexes, current plans. arc auto-refresheslast_activity,last_command,open_prs, andactive_stageon everychat / plan / implement / review / approve / sandbox / dev / sync.log— session-log files (notes.mdunder Projects). Append-only; never touched by the organizer.frozen— archived project indexes, finished blog drafts. No edits.evergreen— authored notes worth re-verifying occasionally (Research, Agents).reference— clippings and web-sourced material. Tagged and linked, but bodies are never modified.
Source types: project-meta, session-log, web-clipping, authored. The source_type is permanent — a note clipped from the web keeps source_type: web-clipping even if it later moves out of Clippings/.
Classification is deterministic by folder + frontmatter; any note with an explicit lifecycle: you've set yourself is always preserved.
Project statuses (derived from stages): needs-plan → planned → active → done → archived
Stage statuses: pending → ready → implemented → reviewed → pr-open → done
Project status is derived from stages automatically, with one exception: a project is only marked done via an explicit arc done <slug> call (not by completing all stages). All stages being done means the current plan is finished — the project stays active until you close it. When the last stage completes, arc prints a hint to run arc done when you're ready.
Stages auto-promote from pending to ready when their dependencies are met. Arc owns all status transitions — agents don't update frontmatter.
Projects/my-feature/
index.md # frontmatter + objective + tasks (lean)
notes.md # project-level session log
stages/
1-api-endpoints/
plan.md # stage plan
notes.md # stage session log
2-ui-components/
plan.md
notes.md
Session notes, plans, and CI events all go to the appropriate notes.md — never into index.md. Each stage gets its own folder with isolated context.
Existing projects are auto-migrated on load: ## Notes sections are extracted from index.md into notes.md, old statuses are mapped to the new system, and stage folders are created.
Run arc init for interactive setup, or copy config.example.toml to config.toml and edit it. The file is gitignored — your personal config stays local.
[core]
obsidian_vault = "~/path/to/your/obsidian-vault"
projects_folder = "Projects"
sandbox_root = "~/Projects/my-repo-clones"
branch_prefix = "your-username"
[github]
user = "your-github-username"
repo = "org/repo-name"
[agent]
test_cmd = "pytest tests/"
lint_cmd = "make lint"
[organize]
skip_folders = ["Templates", ".obsidian", "Assets"]
max_notes_per_run = 20
model = "claude-sonnet-4-20250514"| Key | Purpose | Example |
|---|---|---|
core.obsidian_vault |
Path to your Obsidian vault (~ expanded) | "~/Documents/Notes" |
core.projects_folder |
Folder inside the vault for project notes | "Projects" |
core.sandbox_root |
Where isolated git clones are created | "~/Projects/my-repo-clones" |
core.branch_prefix |
Prefix for feature branches (prefix/slug) |
"jdoe" |
github.user |
Your GitHub username (for filtering assigned issues) | "jdoe" |
github.repo |
Target repo in org/name format |
"my-org/my-app" |
agent.test_cmd |
Test command run in sandboxes by agents | "pytest tests/ -x" |
agent.lint_cmd |
Lint command run in sandboxes by agents | "ruff check ." |
organize.skip_folders |
Vault folders the organizer ignores | ["Templates", "Assets"] |
organize.max_notes_per_run |
Caps API calls per organizer run | 20 |
organize.model |
Claude model for the vault organizer | "claude-sonnet-4-20250514" |
config.toml: Setgithub.repoto the target repo (e.g."my-org/my-app") andgithub.userto the user's GitHub username.config.toml: Setsandbox_rootto wherever clones should live (e.g."~/Projects/my-app-clones").arc.pyConfig.bare_repoproperty: Returnsself.sandbox_root / ".phoenix-bare". Rename.phoenix-bareto something appropriate (e.g.".my-app-bare"). This is a local bare git reference used for fastgit clone --reference.arc.py_load_env_keys()function: Loads API keys from a.envfile atcfg.sandbox_root.parent / "phoenix" / ".env". Change"phoenix"to the directory name of your main repo checkout, or remove this function if you manage env vars differently.
The arc dev command launches a dev server in tmux. By default it runs make dev in the sandbox. To customize:
Set dev.env_file in config.toml to source a canonical environment file
before every launch. When configured, arc dev refuses to start if the file
does not exist. Keep this file limited to non-secret application configuration.
At runtime, arc dev retrieves its API keys directly from macOS Keychain so
their values are not written into the launch script.
[dev]
env_file = "~/Projects/phoenix/.env"- Change the launch command: In
arc.py, find thedev_scriptconstruction (search forexec make). Replace the last line with your app's dev server command (e.g.exec npm run dev,exec cargo run, etc.). - Change the default port: The default port is
6006. Change to whatever your dev server uses. - Phoenix-specific env vars: The
PHOENIX_CLOUD_VARSlist andPHOENIX_WORKING_DIRare specific to the Phoenix app. Remove or replace these with env vars relevant to your app.
arc injects env vars into agent subprocesses in two ways:
-
MODEL_API_KEYSandDEV_API_KEYSlists: API keys carried into agent subprocesses and Phoenix dev-server processes.arc devresolvesDEV_API_KEYSfrom Keychain at launch time without serializing their values into its script. Add or remove keys as needed for your setup. -
_load_env_keys()function: Loads each key from the macOS Keychain first (security find-generic-password -a $USER -s <KEY> -w), falling back to a.envfile atcfg.sandbox_root.parent / "phoenix" / ".env"for any key not in the Keychain. Store keys withsecurity add-generic-password -a "$USER" -s <KEY> -w. Agent sessions use this loader;arc devsources its configureddev.env_fileand independently resolvesDEV_API_KEYSfrom Keychain inside the server launch process.
Subscription billing guard:
ANTHROPIC_API_KEYis always stripped from Claude Code launches (interactive and background) via_clean_env("claude")— its presence would silently switch Claude Code from subscription (OAuth) billing to pay-per-token API billing. Codex sessions and non-Claude subprocesses still receive it for code under test. Agents inside a Claude session that need the key can fetch it on demand from the Keychain.
_clean_env()function: Strips conda/virtualenv paths fromPATHbefore launching agents. This prevents Claude and Codex from seeing the wrong Python environment. If you don't use conda, this is harmless. If you use a different environment manager, you may need to adjust the path filters.
The interactive agent commands default to Claude but can use Codex with a --codex flag:
arc plan <slug> --codex
arc stage <slug> --plan <id> --codex
arc chat <slug> --codex
arc implement <slug> --codex # interactive
arc implement <slug> --bg --codex # autonomous (writes AGENTS.md, runs `codex exec`)Codex has no --system-prompt flag for interactive sessions, so arc concatenates the system prompt and initial message into one combined prompt. For --bg, autonomous implementation instructions are written to AGENTS.md (Codex convention) instead of CLAUDE.md.
arc review and arc address-review use a separate --tool {claude,codex} flag (Codex is the default for those — see below).
arc review defaults to Codex but supports both tools:
arc review <slug> # codex (default)
arc review <slug> --tool claude # claude instead
arc review <slug> --model gpt-5.3-codex # codex with specific model
arc review <slug> --tool claude -m claude-sonnet-4-20250514To change the default, edit DEFAULT_REVIEW_TOOL and DEFAULT_REVIEW_MODEL near the top of _run_review() in arc.py.
arc review <slug> --thorough # or -TInstead of one pass, --thorough splits the review into independent lens agents that each look at the diff from a different angle. Lens agents run in parallel (headless, approvals bypassed since the sandbox is already an isolated clone), then an interactive synthesis agent merges the findings and walks you through them one-by-one, asking before applying each fix.
Lenses:
behavior— correctness + regression risk (logic paths, boundary conditions, error handling, broken invariants). Runs tests and lint.tests— test quality and coverage (meaningful assertions, missing edge cases, flaky patterns)interface— public-surface ergonomics (naming, signatures, defaults, docs, discoverability)security— auto-added when the diff contains signals likeauth,token,crypto,pickle,shell=True, etc.
Output:
<vault>/Projects/<slug>/review/<lens>.md— each lens's findings<vault>/Projects/<slug>/review/summary.md— merged summary written by the synthesis agent. Compound findings (same location flagged by ≥2 lenses) are surfaced first.<vault>/Projects/<slug>/review/logs/<lens>.log— raw codex output per lens, for debugging.
Customizing lens prompts: each lens is a markdown file in lenses/ next to arc.py. Edit those to adjust methodology, severity bars, or output format — arc loads them at runtime.
Flow:
arc review <slug> --thorough
→ spawn N lens agents in parallel (codex exec, bypassed approvals)
→ show progress: [✓] behavior (42s) | [·] tests (running) | ...
→ when all done, spawn synthesis agent (interactive codex)
→ synthesis writes summary.md, then:
For each finding: "Apply this fix? [y/n/e/q]"
→ y applies + commits one-line per fix
→ n skips
→ e expands reasoning
→ q quits the walkthrough
arc pr-review 14054 # basic read-only review (codex by default)
arc pr-review 14054 --tool claude # claude instead
arc pr-review 14054 --thorough # multi-lens
arc pr-review 14054 --debate # adversarial: Codex attacks, Claude defends
arc pr-review 14054 --comment # explicitly opt in to posting the report as a PR commentUnlike arc review (your own work, fixes get committed), pr-review is built for reviewing PRs you don't own:
- Approval-biased posture: the agent is instructed to default to approval and gate only on serious issues — correctness bugs, data loss, security, breaking API changes, test regressions. Style observations are phrased as optional suggestions.
- Strictly read-only: never modifies the PR's code, never pushes, and never posts comments/reviews/approvals to GitHub. The only exception is an explicit
--comment, which posts the finished report as a single PR comment. - Self-managing sandbox: fetches PR metadata via
gh, clones apr-<n>sandbox from the bare reference repo on first use (reused on re-runs), andgh pr checkouts the branch. The diff is taken against the PR's base branch (git diff origin/<base>...HEAD). --debateflips the roles: Codex reviews adversarially, but Claude acts as the author's defender — it CONFIRMs or REBUTs each finding with evidence instead of fixing code. What survives both agents is what you gate on.- Reports live under
Projects/pr-<n>/review/in the vault, and each PR gets a lightweightpr-review-type project so the dashboard shows what you have in flight. - Auto-retirement: the nightly
arc reconcilechecks each openpr-reviewproject against GitHub; once the PR merges, the project is markeddone, its tmux sessions are killed, and thepr-<n>sandbox is deleted (only clean clones namedpr-*undersandbox_root— a dirty clone is left in place with a warning). The weekly cleanup then archives the project folder.
arc review <slug> --debate # up to 5 rounds (default)
arc review <slug> --debate --rounds 3An implement/review loop with the two agents in adversarial roles, using file-based handoff (no MCP session plumbing — each agent reads the other's artifact):
round N:
Codex (exec, read-write) reviews `git diff main` with an explicit
"assume it's broken" stance → writes findings + VERDICT to
<vault>/Projects/<slug>/review/debate/round-N.md
→ VERDICT: APPROVED → done
→ VERDICT: REVISE → Claude (headless) fixes each finding and commits,
or appends a REBUTTAL with evidence under the finding
next round: Codex re-checks fixes and rebuttals, re-raises what's unresolved
The loop terminates on APPROVED, a missing findings file, or --rounds. The outcome is appended to the project's session notes. Round files are kept for audit.
Ad-hoc cross-agent consultation: Codex is also registered as an MCP server in Claude Code (claude mcp add --scope user codex -- codex mcp-server), so any Claude session can invoke the codex tool directly — useful for second opinions mid-session without a full debate loop.
Status drift was the biggest real-world failure mode: statuses only moved when arc commands ran, so work done directly in a sandbox (or via a plain claude session) never reached the vault. arc reconcile treats git as ground truth: it updates branch from the sandbox's actual HEAD (fixing PR sync matching), advances last_activity to the latest commit when it beats the stored wall-clock timestamp, promotes planned projects with feature-branch commits to active, and lists orphan sandboxes no project tracks. arc sync also runs it before PR matching.
A launchd plist runs it nightly at 07:30:
launchctl load ~/Library/LaunchAgents/com.elizabethhutton.arc-reconcile.plistLogs: logs/launchd-reconcile.log.
Session-end hooks: both Claude Code (~/.claude/settings.json → SessionEnd) and Codex (~/.codex/hooks.json → SessionEnd) run a shared hook script (~/.claude/hooks/arc-session-end.sh) when an interactive session ends. The script resolves the project from ARC_PROJECT_SLUG (arc-launched sessions) or from the session's cwd being inside sandbox_root (sessions launched with plain claude/codex), then fires arc reconcile <slug> in the background. Sessions outside a sandbox are a silent no-op, and teardown never blocks — the reconcile is fire-and-forget with output to logs/hook-reconcile.log. The design keeps status git-derived: hooks trigger arc; agents still never write frontmatter.
arc injects system prompts into Claude and Codex at several points. You can customize these to match your team's conventions, coding standards, or review criteria. Each prompt includes project context (title, paths to notes/plans) and task-specific instructions. Agents are told to write session notes to the appropriate notes.md and are explicitly told not to update status in frontmatter.
| Command | Where in arc.py |
What the prompt does |
|---|---|---|
arc plan |
plan() function |
Instructs Claude to write a plan; points to project note and vault |
arc implement (interactive) |
_implement_interactive_simple() and _implement_interactive_staged() |
Gives Claude the project context, sandbox path, and git commit instructions. For staged projects, auto-includes plan.md and notes.md from all dependent stages under a "Prior Stages" section. |
arc implement --bg |
_implement_bg() — writes a CLAUDE.md (or AGENTS.md with --codex) to the sandbox |
Autonomous implementation instructions with paths to project note and notes file |
arc implement --bg |
_implement_bg() — inline prompt |
One-line prompt passed to claude (or codex exec with --codex) in the orchestrator script |
arc review |
_run_review() |
Code quality review prompt: diff against main, check correctness, run tests/lint, fix issues |
arc review --thorough |
_run_thorough_review() + lenses/*.md |
Multi-lens pipeline: parallel lens agents (behavior, tests, interface, optional security) write to <project>/review/<lens>.md, then an interactive synthesis agent merges findings to summary.md and walks you through fixes. Prompts live in lenses/ as markdown. |
arc chat |
chat() function |
Lightweight context prompt with paths to project note and notes file |
arc approve (CI fix) |
CI monitor script in approve() |
Instructs Claude to read CI failures, fix them, and push |
Global project index: arc writes a compact index of all non-archived projects (slug, status, active stage, branch, sandbox, last activity) to ~/.claude/projects-index.md on every dashboard run and pipeline command. Reference it from your global agent context file (@~/.claude/projects-index.md in ~/.claude/CLAUDE.md, or symlink that file to ~/.codex/AGENTS.md) so any agent launched outside arc knows what projects exist and where their notes live.
arc sets the ARC_PROJECT_SLUG environment variable before launching Claude sessions. This lets you customize Claude Code's behavior per-project using hooks and the status line.
Status line: If you want your Claude Code status bar to show the active project, create ~/.claude/statusline.sh:
#!/bin/bash
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name')
cwd=$(echo "$input" | jq -r '.cwd')
dir="${cwd##*/}"
pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
# Use arc project slug if available, otherwise directory name
project="${ARC_PROJECT_SLUG:-$dir}"
echo "[$model] $project | ${pct}% context"Then in ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}Tab title hook: To set your terminal tab/window title to the project name, create a hook script (e.g. ~/.claude/hooks/set-tab-title.sh):
#!/bin/bash
label="${ARC_PROJECT_SLUG:-$(basename "${CLAUDE_PROJECT_DIR:-unknown}")}"
printf '\033]1;CC: %s\033\\' "$label"
printf '\033]2;Claude Code — %s\033\\' "$label"Then in ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/hooks/set-tab-title.sh"
}
]
}
]
}
}These are optional — arc works without them. They just make it easier to track which project you're in when running multiple Claude sessions.
organize.py runs independently as a uv inline script. It uses Claude to tag notes and link them to projects. Authored notes get inline wikilinks; reference notes (clippings) keep pristine bodies but receive suggested links in an appended ## Related footer, so they still join the Obsidian graph.
- Scheduling: Set up a launchd plist (macOS) or cron job (Linux) to run
uv run --script organize.pyperiodically. - API key: The organizer looks for
ANTHROPIC_API_KEYin the environment, then falls back to macOS Keychain (security find-generic-password -a vault-organize -s ANTHROPIC_API_KEY). Set whichever is convenient. - Model: Configured via
organize.modelinconfig.toml. - System prompt: The
SYSTEM_PROMPTinorganize.pydescribes the vault owner as "an AI engineer focused on LLM evaluation." Change this to match the user's domain for better tagging.
cleanup.py runs independently as a uv inline script. It scans your Projects folder, finds any project with a done or archived status, and moves the entire project folder into Projects/Archived/. Before archiving a done project, it removes the project's sandbox only when the worktree is clean and its branch has no commits ahead of origin/main (or local main). Sandboxes for archived projects are always preserved so they can be resumed later.
Manual run:
arc cleanup --dry-run # preview what would move
arc cleanup # executeScheduling (macOS): A launchd plist fires every Saturday at 09:00.
# Install (one-time):
launchctl load ~/Library/LaunchAgents/com.elizabethhutton.arc-cleanup.plist
# To change the day or time, edit the plist (Weekday: 0=Sun … 6=Sat), then reload:
launchctl unload ~/Library/LaunchAgents/com.elizabethhutton.arc-cleanup.plist
launchctl load ~/Library/LaunchAgents/com.elizabethhutton.arc-cleanup.plistConfiguration (config.toml):
[cleanup]
statuses = ["done", "archived"] # which statuses trigger archival
archived_folder = "Archived" # subfolder within projects_folderLogs are written to logs/cleanup-YYYY-MM-DD.log and logs/launchd-cleanup.log.
arc.py (~2400 lines) — main CLI built with Typer. All project state lives in Obsidian YAML frontmatter — no database.
organize.py — standalone vault organizer. Scans for new/changed notes, classifies them with Claude, adds tags and wikilinks.
config.toml — user configuration (gitignored, see config.example.toml).
Config— parsed fromconfig.toml: vault path, sandbox root, GitHub repo, branch prefix, test/lint commandsProject— parsed from{vault}/Projects/{slug}/index.mdfrontmatter: slug, title, status, branch, sandbox path, stages, linked issues/PRs. Project status is derived from stage statuses (exceptdone, which requires explicitarc done).Stage— subtask with dependency graph: id, name, status, depends_on, github_issues, github_prs. Each stage gets a folder understages/withplan.mdandnotes.md.
| Session | Created by |
|---|---|
arc-{slug} |
arc implement --bg (autonomous implementation) |
arc-{slug}-ci |
arc approve (CI monitor loop) |
arc-{slug}-dev |
arc dev (dev server) |
arc implement → Claude writes code → you review the diff
arc review → AI code review (codex or claude)
arc diff-review / arc address-review → manual diff review + AI fixup
arc approve → PR + CI monitor → auto-fix CI failures → merge
In --bg mode, implementation runs in a tmux session with macOS notifications on completion. Review is a separate step you run when ready.
MIT