Website · Download .dmg · All releases · Shortcuts
You can run one Claude Code session in a terminal. GraphCode lets you run ten — connected, unattended, and still yours to attach to and correct mid-run. Each node in the graph is a unit of work running inside a real CLI coding-agent session; each edge is a hand-off, message, or spawn between them. They are real terminals you can attach to and steer, not headless jobs that report back when they're done.
Graph Engineering, simplified → — the full article: the mental model, then the machinery underneath it.
Every loop type is "an agent runs repeatedly" — they differ in what you stop doing:
| Loop type | You hand off | Runs until | For example |
|---|---|---|---|
| Turn-based | the check | you end it — each turn pauses for your review inside the session | a refactor you want to eyeball step by step |
| Goal-based | the stop condition | a goal is met (optionally a shell predicate exits 0) | "fix the build" — done when make test passes |
| Time-based | the trigger | you stop it — cadence lives in the prompt (/loop 1h …) |
hourly issue triage |
| Composite | the prompt | a sub-graph of loops runs it end to end | a pipeline that plans its own steps |
Two design choices explain most of the rest:
- GraphCode schedules nothing. A time-based loop's recurrence lives inside its
session, written into the prompt with the agent's own
/loopor/scheduleskill; the daemon only keeps the session alive. That's what makes a running loop something you can attach to and correct, rather than a job that already finished somewhere. - Sessions outlive everything. Each loop's terminal is a
zmxsession, so it survives closing the window, quitting the app, restarting the daemon, and a reboot — the backend's session ID is persisted, so relaunching resumes the conversation with--resumerather than starting a duplicate.
So a working graph might be an hourly triage loop, a hand-off edge into a goal-based fixer (done when the test suite passes), and a second edge into a turn-based reviewer where you approve each change yourself. All three stay live terminals — click any node and you're in that session, scrollback and all.
Each project carries its own graph, laid out as a lane. Cards are painted by the state they're in rather than their kind, so the canvas reads as which loops are running, which are done, and which are waiting on you — and the Graph view hangs every project's lane off one START node.
Requires macOS 15+ on Apple Silicon (arm64), with Claude Code on your PATH —
GraphCode launches it, it doesn't bundle it.
brew install --cask scgopi/graphcode/graphcodeOr grab
graphcode-macos-arm64.dmg
from the latest release and drag
GraphCode to Applications. Releases are Developer ID signed and notarized.
- Add a project — the sidebar's ⊕ menu: open a local folder, clone a repository from a URL, or add a remote repository over SSH (key auth and zmx on the server required — loops then run on the server while this Mac steers them). Whatever was open is restored next launch.
- Create a loop — ⊕ on the canvas or the Graph view. Write the prompt and hit Create: the type chooser explains what each kind hands off, and the title is optional — leave it blank and GraphCode asks the loop's own backend for a name. A goal-based loop's done check has a Test button that runs it exactly as the daemon will.
- Open it — click the node for its terminal workspace: tabs, splits, ⌘K to jump to any loop by name, ⌘⇧R to walk the loops asking for you (all shortcuts). Every loop type opens the same way, including ones the daemon started on its own — you're attaching to the live session, not a copy of its output.
- Connect loops — drag between nodes. An edge is a hand-off by default (fires when the source resolves); it can also be a message or a spawn, with a condition and a cycle guard.
| Piece | What it is |
|---|---|
graphcode.app |
The UI — project sidebar, graph canvas, and a per-loop terminal workspace with tabs and splits |
graphcoded |
Background daemon (launchd agent). Owns every project's graph, fires hand-off edges, polls goal predicates, and keeps unattended sessions alive whether or not the app is open |
graphcode |
CLI for the same daemon — graphcode status <project>, graphcode node create …, graphcode node send … (type a message into another loop's live session), graphcode node memo … (leave a note a relaunched loop reads on its next pass) |
zmx |
Third-party session daemon that keeps each loop's PTY alive (zmx.sh) |
| GhosttyKit | Third-party terminal engine rendering each surface (ghostty.org) |
State lives in ~/.graphcode/ — per-project graphs, recents, terminal layouts, the daemon
socket and logs, and the installed binaries. Nothing is ever written inside a project
folder you open.
Needs mise (Xcode, tuist, swiftlint, zig come through it) and the submodules:
git submodule update --init --recursive
make doctor # checks every prerequisite and prints the fix for anything missing
make third-party # builds zmx and GhosttyKit (zig)
make install-zmx install-cli daemon-install
make run-app
make test # unit tests
make check # swiftlint + swift-format, both strictStart with make doctor when something is missing — it covers the toolchain, the
submodules, the macOS 15 SDK zig needs, and the Metal toolchain GhosttyKit compiles shaders
with. Design docs live in docs/ and are kept local (gitignored) for now.
- Apple Silicon only. GhosttyKit is built for the native architecture; there is no x86_64 slice, so a universal build won't link.
- Claude Code is the most complete backend. Copilot CLI and Codex loops launch, run, fan out, resume after a reboot, and receive message edges like Claude ones; usage reporting stays Claude Code-only. The picker refuses pairings a backend can't host.
- A new folder stops at Claude's trust prompt. An unattended loop started by the daemon
in a folder Claude hasn't seen waits at "Do you trust this folder?" and shows as
runningwhile doing nothing. Attach once and answer it. - First session start is slow if your shell profile is slow (conda's hook, for instance) — the queued command runs only after the profile finishes.
- Sessions aren't reaped. Long-lived
graphcode-*zmx sessions accumulate; list them withzmx listand remove dead ones withzmx kill. - Remote repositories ride one multiplexed SSH connection per host. A dropped link
redials itself and degrades readings to "unknown" rather than resolving a loop it merely
lost sight of. Worktrees aren't available there, goal predicates run locally (write an
explicit
ssh host …if the check is remote), and a sleeping Mac fires no edges — the daemon stays local by design.
Inspired by Supacode — same spine of daemon-kept terminal sessions;
its unit is the worktree, GraphCode's is the graph of loops. Built on
Ghostty and zmx, vendored under ThirdParty/.
The app and the daemon are under the Functional Source License v1.1
with an MIT future license (FSL-1.1-MIT): use it, change it, self-host it,
redistribute it — the one thing it does not permit is shipping a competing commercial
product built from it, and every release converts to plain MIT two years after it goes out.
GraphcodeKit/ and graphcode-cli/ stay MIT, so scripting against
graphcode never raises a licensing question.
Contributions are accepted under the Developer Certificate of
Origin — add a Signed-off-by line with git commit -s.
