Standalone IAddon contract — the addon/plugin abstraction as a leaf library.
A host loads addons that implement IAddon to gain capabilities (Dependency
Inversion): the host depends on this abstraction, never on the concrete addons,
and no addon compile-depends on the host. Any project — an MCP server or
something entirely unrelated — can host addons by consuming this lib.
io.github.hive-agi/hive-addon {:mvn/version "1.0.0"}
Deps: Clojure + hive-dsl + malli. .cljc.
hive-addon.protocol/IAddon:
| Method | Returns |
|---|---|
addon-id | stable string identifier (registry key) |
addon-type | :native | :mcp-bridge | :external |
capabilities | set of capability keywords |
initialize! / shutdown! | idempotent lifecycle |
health | {:status :ok\|:degraded\|:down} |
tools / schema-extensions / resources / hooks | host contributions |
excluded-tools | tool names this addon supersedes |
Plus predicates (addon?, valid-addon-type?, healthy?/degraded?/down?)
and constants (valid-addon-types, standard-capabilities, health-statuses).
(require '[hive-addon.protocol :as addon])
(defrecord MyAddon []
addon/IAddon
(addon-id [_] "my.addon")
(addon-type [_] :native)
(capabilities [_] #{:tools})
(initialize! [_ _config] {:success? true})
(shutdown! [_] nil)
(tools [_] [...])
(schema-extensions [_] [])
(health [_] {:status :ok})
(excluded-tools [_] #{})
(hooks [_] {}))
Mount manifests may request bounded initialization retries:
{:addon/id "my.addon"
:addon/type :native
:addon/init-ns "my.addon"
:addon/init-fn "addon-ctor"
:addon/init-retry {:max-attempts 4
:initial-delay-ms 250
:max-delay-ms 2000
:backoff-factor 2}}
hive-addon.mount/mount-classpath! and hive-addon.mount/compose-classpath! accept :on-event for structured lifecycle events and :sleep-fn for deterministic tests. Mount results report :init-attempts.
hive-addon.hot rebuilds a mounted addon from its manifest when its code
changes, and cascades to every addon that was handed its instance. hive-hot is
a SOFT dependency: with it on the classpath the namespace reload is delegated
to hive-hot.core/reload-scoped!, scoped to the seeds' own source roots: a
change another session left under some other watched root is declined and
reported under :hot/ns-skipped, never loaded on the caller's behalf.
(require '[hive-addon.hot :as hot])
(hot/reload-addon! host specs "my.addon" {:mount-opts {:resolve-config my-resolver}})
;; => RemountReport: :hot/affected, :hot/torn-down, :mounted,
;; :hot/ns-reloaded / :hot/ns-skipped / :hot/ns-dragged, :hot/stale-ctors ...
A reload whose namespace pass claims a load that did not happen (the
constructor var is provably the same object afterwards) is REFUSED
(:hot/stale-ctors) instead of remounting from old code and reporting success.
hive-addon.hot.inject/inject! mounts an addon that was not on the classpath
at boot: it puts the project's deps.edn :paths (or a source dir, or a jar) on
the live DynamicClassLoader, discovers the manifests under those paths only,
solves them against the mounted peers, remounts the mounted dependents that
now have a new sibling to receive, and registers the new addons with hive-hot.
(require '[hive-addon.hot.inject :as inject])
(inject/inject! host mounted-specs "/path/to/addon-project"
{:mount-opts {:resolve-config my-resolver}})
;; => InjectReport: :hot/injected, :hot/already-mounted, :hot/affected, :mounted ...
An addon that is more than tools implements one of these beside IAddon, on
the same reify, so a vessel or terminal never compile-depends on a host:
| Namespace | Protocol | For |
|---|---|---|
hive-addon.terminal | ITerminalAddon | an addon-contributed terminal backend (started in initialize!) |
hive-addon.vessel | IVessel | a headed environment (Emacs, tmux, a web UI) supplying terminals, editors, channels and REPLs |
hive-addon.capability | (data) | the machine-readable description of one tool's commands, their arguments and their stability |
hive-addon.opaque mounts a compiled, source-free addon: an ordinary mount
manifest with :addon/type :external and :addon/trust-class :proprietary,
governed by the same licence gate as any other, with nothing special-cased in
the mount path.
From 1.0.0 this library follows Semantic Versioning.
The public contract is IAddon and its companion protocols, the mount and plug
manifest schemas, and the registry APIs.
Bump VERSION, merge to main. CI tags v<VERSION> and cuts a GitHub release.
MIT. Copyright (C) 2026 Pedro Gomes Branquinho (BuddhiLW).
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |