# The Core Engine **Status**: Stable **See also**: [[Creating-Addons]] | [[ADR-0007-hive-addons-architecture]] | [[Addon-Classpath-Discovery]] | [[Interfaces-and-Protocols]] ## What hive-mcp actually is hive-mcp is a **host**: a runtime that other things mount into. It is not a library you depend on, and it is not the thing you type into. Three words get used for systems in this space, and they are not synonyms: | Term | What it names | Is hive-mcp this? | |---|---|---| | **Harness** | The scaffolding that drives a model: prompt loop, tool dispatch, context management. Claude Code is a harness. | **Partly.** hive-mcp is a harness for the agents *it* spawns — lings get their loop, presets, budget and context from it. It is *not* the harness you talk to; that's your MCP client. | | **MCP server** | The wire protocol surface. | **Yes**, but that's the transport, not the architecture. | | **Host** | The runtime addons mount into and are amalgamated by. | **Yes — this is the load-bearing one.** | So: *your* harness (Claude Code, or any MCP client) talks to hive-mcp over MCP; hive-mcp hosts the addons that supply the actual capabilities; and hive-mcp is itself a harness for the sub-agents it runs. If you want one sentence: **hive-mcp is an addon host that doubles as an agent harness.** ``` ┌────────────────────────────────────────────────────────────┐ │ Your harness — Claude Code, or any MCP client │ └───────────────────────────┬────────────────────────────────┘ │ MCP protocol ┌───────────────────────────▼────────────────────────────────┐ │ hive-mcp — THE HOST (AGPL-3.0) │ │ │ │ protocols · registries · orchestrators · server │ │ memory CRUD · KG edges · swarm · session ritual │ │ │ │ ┌──── extension registry ────┐ ┌──── tool roots ────┐ │ │ │ generic ext-keys, noop │ │ addon tools become │ │ │ │ defaults, addon-owned │ │ new top-level │ │ │ │ registrations │ │ tools, no core edit│ │ │ └────────────────────────────┘ └─────────────────────┘ │ └───────────────────────────┬────────────────────────────────┘ │ IAddon ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ addon (tools) library (backend) addon (tools) ``` ## The rule that shapes everything: closed for modification > hive-mcp is **CLOSED for modification, OPEN for extension via IAddon.** When an addon needs a new capability — an extension key, a predicate, a handler, a schema, a compression strategy — **all** of that code goes in the addon. Zero changes to core. This is not style advice; it is the boundary that makes the open-core split possible. Core is AGPL and public. The intelligence layers are private addons. If core had to grow a line every time an addon gained a capability, the boundary would leak on every release. **What core owns** - Protocols and contracts - Registries and the loader - Orchestrators, the MCP server, transport - Memory CRUD, basic KG edges, swarm coordination, the session ritual - **Noop defaults** for every extension point **What core must never contain** - Behaviour belonging to a named addon - A `requiring-resolve` of a concrete addon namespace — *this is the smell*; dependencies and knowledge flow **addon → core**, never the reverse - Addon-specific parameters bolted onto a core tool's input schema - Proprietary hooks, or comments describing them ### How the seam actually works Core defines a **generic extension key** and applies whatever is registered under it: ```clojure ;; in core — addon-agnostic, this is the only legitimate core change (ext/get-extension :catchup/wrap) ;; in the addon's IAddon/hooks — registered at initialize!, removed at shutdown! {:catchup/wrap my-addon.catchup/wrap-fn} ``` Core never learns that `my-addon` exists. Ownership is tracked per-addon, so `shutdown!` deregisters cleanly. ### Tool roots: extension without registration ceremony The tool surface is assembled at advertisement time from three sources: 1. **Domain roots** shipped by core — `code`, `swarm`, `memory`, `project`, `fs`, `git`, `emacs`, `preset`, `web`, `events`, `multi`, `migrate-kanban` 2. **Channel tools** 3. **Addon-registered tools** — filtered for collisions with domain names and for anything explicitly absorbed via config Anything an addon registers that doesn't collide **becomes a new top-level tool root automatically**. No core edit, no allowlist entry, no release. A visibility gate (`config.edn` → `[:tool-roots :visible]`) can then shrink the advertised surface without breaking callers: hidden tools stay dispatchable by name, they just leave `tools/list`. ## The addon/library distinction Manifests (`META-INF/hive-addons/*.edn`) carry `:addon/kind`: | Kind | Meaning | Examples | |---|---|---| | `:addon` | Contributes user-facing tools | knowledge, lsp-mcp, clj-kondo-mcp, basic-tools-mcp, emacs, ingestor | | `:library` | Pure backend or infrastructure — vector search, memory store, terminal, instrumentation | qdrant, milvus, proximum, tmux, claude | The test is simple: **anything contributing user-facing `:tools` is an `:addon`; pure backends are `:library`.** This is deliberately *not* the same axis as `:addon/type` (`native | mcp-bridge | external`), which describes the integration mechanism instead. ## Depending on the host without depending on the host An addon **must not** `:require` any `hive-mcp.*` namespace. The host is a runtime, not a dependency. What the addon needs is expressed as a port: - **Contracts to implement** → `hive-addon` (for `IAddon` itself) and `hive-contracts` - **Host services consumed at runtime** → soft resolution (`requiring-resolve`) behind a var-map, so the addon loads and degrades gracefully when the host is absent A load-time require on the host is the violation. A soft runtime resolve is not. The same discipline runs one level down: hive's own libraries depend on **no concrete store** — not datahike, not datalevin, not datascript. They ask `hive-contracts` for a datalog surface, and whichever backend addon is mounted answers. "It's only in-memory" is not an exemption: the rule is about the dependency edge, not about durability. ### Why this is enforced so hard One hard `:require` on the host makes a published addon artifact unloadable from a plain Maven fetch. One addon in this ecosystem had ~35 soft resolves and exactly one hard require — that single line cost the entire drop-in-addon story. ## Open core, concretely | Layer | Licence | Home | |---|---|---| | hive-mcp (this repo) | AGPL-3.0 | GitHub | | FOSS addons and libraries | MIT | GitHub | | Intelligence / product addons | Proprietary | Private | Core ships the protocol *and* a working noop fallback for every extension point, so the FOSS stack alone is a complete, usable system — see [[FOSS-Quickstart]]. Private addons add ranking, learning, and domain intelligence by registering into the same seams any third-party addon uses. ## Extending it 1. Want addon behaviour at a core code path? Identify or add a **generic** ext-key that the core path consumes via `ext/get-extension`. That registry seam is the only legitimate core change. 2. Put the logic in the addon; expose it through the addon's `hooks` map. 3. Need new tools? Ship whole tool-defs from the addon — don't edit a core tool's schema. 4. Never `requiring-resolve` a concrete addon namespace from core. Full walkthrough with a scaffolded project: [[Creating-Addons]].