Juggler

Everything is an extension.

Every tool the model can call — including read, write and bash — is a JavaScript plugin. So are the agentic-loop strategies, the slash commands, the sidebar cards, and the viewers that decide how a file is displayed and what the model sees of it.

Juggler's own built-in extension is loaded through exactly the same path as yours, from the same public SDK. There is no privileged inner tier: anything the app can do, an extension you write can do.

Start in about a minute

You don't need Juggler's source. Everything you need ships in the binary.

juggler ext init my-extension       # a complete, working extension
juggler ext validate ./my-extension # the same check the app runs at load
juggler ext link ./my-extension     # symlink it into ~/.juggler/extensions

The scaffold loads unedited, so you start from something that works rather than something that compiles. After link, saving any file hot-reloads the extension in every connected viewer — no restart, for the whole of your dev loop.

What an extension can be

Juggler is assembled from a small set of abstractions, and every one of them is a capability an extension can supply.

  • Context item

    A tool the model can call. Declare a JSON schema, do the work in execute(), format the outcome in getSummary(). Add an approval gate for anything destructive.

  • Strategy

    A policy for the agentic loop: which tools exist this turn, what gets auto-approved, what guidance the model is given. Read-only and YOLO are just two of these.

  • Command

    A slash command. The simplest capability there is — no LLM, no approval, no schema. (For a reusable prompt, you don't need code at all: a custom command is a markdown file.)

  • Workspace provider

    Supplies an environment for a conversation's tools to run in. The built-in git-worktree, scratch-copy and project-folder kinds are providers like any other; yours could provision an ssh host or a container. How workspaces work.

  • File viewer

    Owns a file type end to end: how it's rendered for you, and what's extracted for the model. Those are two different jobs, and they run in two different places.

  • Info card

    An ambient tile in the sidebar's spare space, next to Tips, Usage and Git status.

  • Pinboard tab

    A view the user can pin and keep beside the conversation — git status, the current plan, a file held in view. Display only, by design: the SDK gives it no way to feed the model.

A whole tool, start to finish

Not an excerpt — this is a complete, loadable context item.

import ContextItem from 'juggler/context-item';

class WordCountContextItem extends ContextItem {
  static MANIFEST = { id: 'word-count', name: 'Word Count', version: '1.0.0',
    description: 'Count words in a text string' };

  static getToolDefinitions() {
    return [{
      name: 'word_count',
      category: 'read',
      description: 'Count words in a text string',
      input_schema: { type: 'object',
        properties: { text: { type: 'string', description: 'Text to count' } },
        required: ['text'] }
    }];
  }

  async execute(params) {
    return { count: params.text.split(/\s+/).filter(Boolean).length };
  }

  getSummary(outcome) {
    if (!outcome.success) return this.failureSummary(outcome.error);
    return this.successSummary(outcome.result.count + ' words');
  }
}

export default WordCountContextItem;

Extensions import only from the public juggler/* modules — filesystem, shell, search and web operations, UI helpers, and the base classes. That's the same surface the built-in extension uses, which is what makes third-party parity real rather than aspirational.

What you're trusting

Extensions are unsandboxed JavaScript running with the full privileges of the app, exactly like plugins in an editor. An extension declares the host access it uses, and Juggler shows you that declaration before you install — but it is disclosure, not containment. Install and enable only extensions you trust.

The SDK and the built-in extensions are Apache-2.0, so an extension built on them carries no copyleft obligation: license yours however you like, closed source included.

Read next

  • The tutorial builds one extension from an empty directory to a published one — a tool, an approval gate, a setting, a slash command and a sidebar card.
  • The guide is the reference: the manifest, every capability type, settings and secrets, the trust model, and how context actually reaches the model.
  • The examples are small extensions meant to be copied, covering every capability type.
  • The SDK source is the canonical API documentation. Each base class opens with a quickstart and a full method reference, and the app can show it to you offline with no checkout.