Get started free
Documentation

Extensions

intentic is a lean core plus an extension system. An extension is a git repo with a manifest, and unlike an editor plugin it can extend the agent as well as the UI.

What an extension is

A git repository with an intentic-extension.json file at its root. That's the whole definition. The manifest names a publisher, a name, and the things the extension contributes; if it contributes UI, the repo also holds a prebuilt bundle exporting an activate() function.

intentic-extension.json
{
    "publisher": "acme",
    "name": "incidents",
    "version": "1.0.0",
    "category": "work",
    "icon": "exclamation-triangle",
    "engines": { "intentic": "^0.4.0" },
    "permissions": { "sandbox": ["GET /logs", "GET /logs/tail"] },
    "contributes": {
        "views": [{ "id": "incidents", "label": "Incidents", "surface": "rail", "badge": true }]
    }
}

Identity is derived, never declared: this extension is acme.incidents everywhere in the product, because that's what publisher and name say. There is no id field to contradict the one the install dialog showed you.

It extends the agent, not just the editor

This is the part that has no equivalent in a normal editor's plugin model, and it's the reason to build one. A sandbox is a whole machine: an agent, its tools, its credentials, its image. An extension can reach all of it.

The UI half

ContributesWhat it adds
viewsA tile in the left rail, a per-repo panel in the Workspace tree, or a tab on the Sandbox hub.
viewersA renderer for a file type: the host fetches the bytes, your component draws them.
commandsAn entry in the command palette, optionally with a global keyboard shortcut.
settingsTyped settings the host renders and stores for you, including secrets and env vars for the agent.
filesWhich workspace files back your view, so the daemon pushes you a refresh instead of you polling.

The agent and daemon half

ContributesWhat it adds
agentA directory of skills, subagents, hooks and MCP servers, loaded into the agent every turn.
binExecutables prepended to the agent's PATH, which is how you ship it a command-line tool.
capabilitiesA whole third-party integration as data: a card, a config form, env vars, and a cheatsheet.
processesA long-lived background process the daemon supervises, optionally on a tunneled preview URL.
listenerA realtime event source that can wake the agent, the way Discord and IMAP do.
environmentDockerfile layers baked into the sandbox image, so your tools are actually installed.

Nothing says you have to use both halves. A connector is a manifest and two files with no code at all. A skill pack is a directory. An extension that ships a CLI for the agent and never draws a pixel is a perfectly ordinary extension.

The trust model

Extension code runs in your browser and your sandbox, so the install is built to be understood before it's approved, not audited after. Three mechanics do that work:

  • The code is pinned to a commit. Installing takes a full 40-character commit sha, not a branch. The code you approved is the code that runs, and an update is an explicit, visible act, never something that happens under you.
  • The manifest is the approval surface. The install dialog shows exactly the declared contributions. Afterwards the host enforces them: a view, command, viewer, setting or process the approved manifest never declared is refused at runtime. An extension cannot grow new powers after you said yes.
  • Backend reach is an allowlist. An extension has no ambient client to your daemon. It declares the routes it calls as "GET /logs"-style entries and the host refuses everything else, so "what can this thing actually touch" is a list you can read in the diff.

Credentials are never part of that surface. The transport injects auth host-side; an extension bundle never sees a token, and secret settings round-trip as "still set" rather than as their value.

Everything first-party is an extension too

Thirteen of the features you already use are extensions: Activity, Automations, Logs, Memory, Pipelines, Preview, Acceptance, the file viewers, the Discord and IMAP gateways, the connector catalog. They ship through the same @intentic/extension-api a third-party bundle compiles against, and a lint rule fails the build if one of them reaches into app internals instead.

That's a deliberate constraint rather than a boast: it means the public API is the API the product is built on, so it can't quietly rot into the second-class path.

How extensions reach a sandbox

  • Baked into the image: first-party ones are present in every sandbox and can be switched off, not removed.
  • Git-installed: everything else, as a sha-pinned clone into .intentic/extensions/, added from a repo URL or picked from a registry.

Both land in one list on Sandbox → Extensions, with one on/off switch each. Switching one off unwires it everywhere: no view, no command, no PATH entry, no connector card, no env var, no background process.

Where to go next