Extensions
Extensions are opt-in,
agent-agnostic
add-ons that
compose
Thurbox through the public
thurbox-cli
surface — they never extend the binary. The core knows a declarative
manifest format
, never any specific extension, so the same machinery installs and manages any of them.
Overview #
An extension is a directory with a single
extension.toml
manifest plus the files it ships (specs, scripts, config templates). One command
installs it:
thurbox-cli
fetches the manifest, lays the files down under a home directory, registers any agents
the extension needs in
agents.toml
, then creates — and keeps alive — the sessions and automations the
extension declares.
- Data, not binary. Nothing about an extension is compiled in; the core reads a manifest and acts on it.
-
Agent-neutral.
Extensions reach coding agents only through
agents.tomlaliases you remap to any CLI (claude, codex, antigravity, opencode, vibe, …). - Self-healing. While an extension is active, deleting its session or automation is a no-op — Thurbox recreates it. Deactivating is the real off-switch.
Two extensions ship with Thurbox, and both are built in. Everything else you install yourself, from a URL, a local directory, or a git repository. The worked example is fleet , a control-plane template you clone — see Available extensions . The commands and manifest fields below are generic; the examples use fleet.
Two extensions ship built in:
agent hooks
, which wires each agent's lifecycle hooks to
thurbox-cli session signal
so the session list shows working/blocked/done/idle, and
ui-skill
, which teaches whichever coding CLI you run
how to edit the interface
. Unlike the others both are
embedded in the binary and auto-activated
— they still install through the same manifest machinery shown here. Turn either
off with
thurbox-cli extension deactivate <name>
.
Install #
Install an extension from a directory, a URL, or a git repository:
thurbox-cli extension install ./my-extension
thurbox-cli extension install git+https://github.com/you/my-extension
That single command is the whole installer. It resolves the source, fetches the manifest
and payload, writes them under the extension home (
~/.config/thurbox/extensions/<name>
by default;
--home <dir>
to override), registers the extension's agents, writes the resolved manifest to
~/.config/thurbox/extensions/<name>.toml
, and activates it. It is idempotent — re-running refreshes shipped files while
keeping your own data (seeded files you've edited, agent tweaks).
Lifecycle commands #
All extension management lives under
thurbox-cli extension
(alias
ext
):
| Command | What it does |
|---|---|
install <url|dir|git+repo|name> |
Fetch + lay down files, register agents, write manifest, and activate. |
uninstall <name> |
Reverse an install: tear down the session/automation, remove the extension's
agents, and delete the manifest. Add
--purge
to also delete the home dir.
|
activate <name> |
(Re)create the declared sessions/automations and mark the extension active. |
deactivate <name> |
Tear down resources and stop self-heal (the off-switch). Add
--force
to kill tmux/worktrees,
--purge
to also drop the manifest.
|
list |
Show installed extensions with their active / healthy state. |
status [<name>] |
Per-resource presence for one extension (or all). |
Install vs. activate.
install
also lays down files and registers agents;
activate
only (re)creates the runtime resources from an already-installed manifest. Use
deactivate
to switch an extension off but keep it installed for a later
activate
.
Sources & versioning #
The install target can be four things:
-
A local directory
(
./my-extension) — installs from a checkout. -
An
http(s)://base URL — installs from your own source, fetching each manifest-named file. -
A git repository
(
git+https://…, a URL ending in.git, orgit@host:path) — cloned as a working copy, which is how an extension that lives in its own repo installs. Recognised explicitly, so a plainhttps://URL keeps meaning “a base to fetch files from”. -
A bare name
— fetched from the official source over
curl/wget, pinned to your binary's release tag (dev builds trackmain), so a fetched extension always matches the binary reading it. Nothing ships under a bare name today: the only extensions in the Thurbox repository are the two built-ins, which install themselves.
thurbox-cli extension install ./my-extension
thurbox-cli extension install https://example.com/ext/my-extension --home ~/work/ext
Safety:
payload paths are validated against traversal (no absolute paths or
..
), a config template you've edited isn't overwritten on reinstall (use
--force
), and payload files are fetched as text (specs, scripts, JSON) — not binaries.
Self-healing #
An installed extension is recorded in an
active set
. On TUI startup and on every automation tick, Thurbox re-ensures each active
extension's declared sessions and automations exist — so deleting them by hand
(TUI
Ctrl+D
, a
clean
, or
thurbox-cli session/automation delete
) is a no-op: they come back. This is what makes an extension hard to half-remove by
accident.
-
deactivate <name>removes the extension from the active set, so self-heal stops resurrecting it — the real off-switch. -
Headless self-heal (while the TUI is closed) rides the automation heartbeat, so it
needs
[features] automations = true; with automations off, healing happens at the next TUI startup only.
The manifest #
An extension is fully described by its
extension.toml
. It has two halves: an
install
spec (what to lay down) and a
runtime
spec (what to keep alive). The
{home}
token is substituted with the resolved home directory.
The example below is modelled on fleet. Its real manifest uses
[[agents]]
, one
[[files]]
, three
[[symlinks]]
and one
[[sessions]]
; the rest is illustrative, so every field the format supports appears once.
name = "fleet"
description = "Control-plane session: the repo map and thurbox orchestration"
config_version = 1
# home = "~/fleet" # OPTIONAL; default is under the config dir
# ({home} is substituted everywhere it appears)
# install spec ---------------------------------------------------------------
[[agents]] # registered in agents.toml (existing kept)
name = "fleet"
command = "claude"
args = ["--model", "claude-haiku-4-5"]
[[files]] # fetched from the source, written under home
path = "FLEET.md"
[[files]]
path = "scripts/sync-registry.sh"
executable = true # chmod +x
[[files]]
path = "repos.md"
if_absent = true # seed once; never clobbered on reinstall
[[files]]
path = ".claude/settings.json"
source = "claude-settings.json" # source path differs from dest
substitute = true # replace {home} in the content
[[symlinks]] # never clobbers a real file at `link`
link = "CLAUDE.md"
target = "FLEET.md"
# runtime spec (ensured on activate, self-healed if deleted) -----------------
[[sessions]]
name = "fleet"
agent = "fleet"
repo_path = "{home}" # resolved to the absolute home at install.
# {home} is the EXTENSION home, so an extension
# whose session must open your own checkout ships
# a placeholder its installer renders instead
# [[automations]] is an OPTIONAL runtime resource (fleet ships none on purpose —
# its only scheduled candidate pushes to `main`). An extension that wants a
# scheduled tick declares:
[[automations]]
name = "example-tick"
trigger = "cron:*/10 * * * *" # same grammar as `automation create --trigger`
session_ref = "fleet" # must match a [[sessions]] name above
prompt = "tick"| Section | Purpose |
|---|---|
home |
Default install directory; overridable with
--home
.
|
[[agents]] |
Agent definitions appended to
agents.toml
(existing names are kept).
|
[[files]] |
Payload files written under
home
. Flags:
executable
,
if_absent
(seed once),
substitute
(
{home}
in content), and
source
(when the source path differs from the destination).
|
[[symlinks]] |
Symlinks created under
home
(never clobber a real file).
|
[[sessions]] |
Sessions ensured on activate and self-healed if deleted. |
[[automations]] |
Automations ensured on activate;
session_ref
names a session above.
|
Authoring an extension #
-
Create a directory with an
extension.tomland the files it references ([[files]]paths are relative to both the source and the home dir). -
Build the behavior on the
thurbox-clisurface (session,task,automation) plus standard tools — no core changes, no vendor lock-in. -
Test locally with
thurbox-cli extension install ./your-ext, then publish it — a git repository is the usual home, andinstall git+https://…clones it.
For the exact config-file locations and the metadata key that tracks active extensions, see the configuration reference .
Available extensions #
Two ship with Thurbox and are on by default; anything else you install yourself.
Built in
Ships embedded in the binary and is active by default — no install step.
agent hooks built in
Wires each agent's lifecycle hooks to
thurbox-cli session signal
so every session reports working/blocked/done/idle. Embedded and on by default.
ui-skill built in
Installs a
thurbox-ui
skill into whichever coding CLIs you have, so an agent in any session knows how
to edit the interface. Embedded and on by default.
Install it yourself
Lives in its own repository, installs through the same manifest machinery.