Juggler

The agent loop is the easy part.

Juggler is a GUI-first AI coding harness, built by Julian Storer (JUCE, Tracktion, Cmajor). It's a native Go server, conversations are CRDTs synced live to local and remote clients, and no Electron in sight.

Tool calls, item properties and nested sub-threads laid out in a Finder-style Miller column view

Under the hood

  • A native app and a matching server

    The backend is Go; the interface is type-checked JavaScript served directly, with no frontend compilation step. Conversations are Yjs documents, so every connected client converges on the same live state.

  • A state machine, not a while-loop

    The turn cycle — model, tools, approval, next call — advances by named state transitions in the conversation document, not by a loop holding it all in memory. An approval is a state rather than a blocked process, so a turn can be interrupted anywhere and carry on later as if nothing had happened.

Everything is an extension

Juggler is assembled from a small set of abstractions, and every one of them is a capability an extension can supply — even read, write and bash go through the public SDK. There is no privileged inner tier.

// A tool the model can call: a JSON schema in, an approval gate if
// it's destructive, a structured result out.
import ContextItem from 'juggler/context-item';

// The policy of the agentic loop: which tools exist this turn, what
// gets auto-approved, what guidance the model is given.
import Strategy from 'juggler/strategy-type';

// A slash command — no LLM, no approval, the simplest capability.
import Command from 'juggler/command-type';

// An environment for a conversation's tools to run in. The built-in
// git-worktree, scratch-copy and project-folder providers are three;
// an ssh host or a container could be a fourth.
import WorkspaceProvider from 'juggler/workspace-provider';

// Owns a file type end to end: how it renders for you, and what the
// model sees of it — two different jobs, in two different places.
import FileViewer from 'juggler/file-viewer';

// An ambient tile in the sidebar, alongside Tips and Git status.
import InfoCard from 'juggler/info-card-type';

// A view the user pins beside the conversation. Display only, by
// design: it has no way to feed the model.
import PinboardItem from 'juggler/pinboard-item-type';

Those imports are real. Writing an extension starts with a single scaffold command.

Your agent's conversation is a tree, not a log file.

Branch at any point: send a tangent, a delegated task or a competing approach into a sub-thread, and bring back only its result instead of pouring the whole excursion into your main context.

Branching threads. Sub-threads, all the way down.
Inspect anything. Properties, history and context.
  • A desktop interface for long sessions

    Using a coding agent means reading and editing substantial amounts of text. Juggler gives that work a proper interface: Miller-column navigation and focused views, built for long sessions.

  • Branching is recursive

    A sub-thread can have sub-threads. Explore a tangent or a competing approach as deep as it needs to go.

  • Everything important is inspectable

    Open tool arguments, approvals and results in their own views. Open any model transaction: system prompt, messages, tool definitions, output, token use, timing, stop reason.

Give each agent its own place to work

Run several conversations on one project without them treading on each other: each works in its own workspace — a git worktree on another branch, a throwaway scratch copy, or one folder of a monorepo.

Workspaces in the tab strip. Conversations sharing a workspace are boxed together.

How workspaces work →

Run it where the code lives

Launch the desktop app and everything runs locally. When the project lives on a dev box or server, run Juggler there instead: the session lives with the code, and every connected client — app, browser, phone — stays in sync.

Big screen or pocket-sized. One live session, in the desktop app or a browser.

The Context Surgeon

An agent's context should not be a sealed container. Open the assembled system prompt and tools, fold history into a new thread, move items between branches, expand a branch back into its parent — and undo any of it.

  • Sessions survive quits and reconnects

    A session lives on disk, not just in memory. Quit, relaunch or lose the connection and the conversation is still there, including an agent waiting for you to approve its next step.

  • Vendor-neutral, with no house model

    Claude Code, Anthropic, OpenAI, Codex, GitHub Copilot, Gemini, Mistral, Z.AI, Ollama, OpenRouter, DeepSeek and other OpenAI-compatible providers. Bring a subscription you already pay for, or your own API keys. Juggler sells no tokens, so it has no stake in which you pick — switch provider or model mid-conversation.

  • Nothing intercepts what you send

    Model traffic goes direct from your machine to the provider you chose: no server in the path, no cloud index of your repository. Conversations and API keys stay on your own disk, and the source is public, so none of that has to be taken on trust.

  • Context limits are handled before they become your problem

    Juggler sizes the complete request before each call, leaves room for the answer, and compacts older history when a conversation outgrows the model's window.

  • MCP tools, fully inspectable

    Connect a local or remote MCP server and follow the whole handoff: schema, generated arguments, approval, result. Check server status and logs, filter individual tools, and see what a past model turn actually received.

  • AGPLv3 application, permissive extension SDK

    The application is AGPLv3; the extension SDK and bundled extensions are Apache-2.0, so extensions can remain closed source. A build from source supports local and LAN access; the official binaries add WAN modes — see LICENSING.md for the boundary.

A session supports multiple clients. Desktop and browser views stay in sync.
Built on extensions. The LLM-facing tools use the same public SDK available to you.

Who's building this?

I'm Julian Storer. I've been building tools for developers and musicians since the 1990s, and these days most of my own work happens through a coding agent. Juggler exists because I wanted that tool to be worth living in. And somehow I seem to have ended up writing it myself...

Active development

Frequent releases, shaped by people using it on real projects — the changelog has the details.

Constructive feedback is welcome on the Discord.

No terminal required

The desktop app

Download and launch it. The app starts its matching local server and opens your project.

For long-lived & remote sessions

The terminal server

Run the headless juggler binary where your code lives, then attach from a browser or the desktop app.

Free to download. Open source. No Juggler account. No Electron.