Soft Composition - alexherrero/agentm GitHub Wiki
Why plugins keep enhances: and requires: in two separate fields, and what the capability resolver actually does when a plugin asks whether another is around.
The two fields stay separate because the resolver behind them is a simple checker, not a dependency solver. All it does is answer one question: is this other capability installed? That single limit is what splits the two kinds of dependency. Something a plugin genuinely can't run without has to be a hard requires:, because only the host that installs the plugins can guarantee it's there. Everything the resolver handles is optional by nature — which is exactly what enhances: means: nice to have, and when it's absent the plugin just falls back to working on its own. It's tempting to let the resolver chase the must-haves too and fold the two fields into one, but then it would have to fail the install when something required is missing, and that's the host's job, not the resolver's. So the resolver stays a plain yes-or-no check, and the two fields stay apart. The rest of this page fills in each half.
A plugin that requires another to function correctly lists it in requires:. On Claude Code this serializes to the dependencies: array in the marketplace entry; on Antigravity it is listed in the marketplace entry's requires: field. The host installer enforces it: if the dependency is absent, the host refuses to install the plugin or marks it as broken.
Hard deps are the host's job. agentm reads the requires: field to document it in the marketplace entry, but does not enforce it — that is the host's contract with the user.
A plugin that optionally uses another plugin's capabilities lists them in enhances:. Unlike requires:, an unmet enhances: is not an error — the dependent plugin falls back to its standalone behavior. An enhances: entry may carry a version range (>= 1.2) to express "I need at least this version for the enhancement to be safe."
enhances ∩ requires = ∅. A capability that is required must be in requires: (hard dep, host-enforced). A capability in enhances: is by definition optional — if it is not optional, it is in the wrong field. This invariant is enforced by design: agentm's resolver is a single-range check (LC-3), not a solver, so it is structurally incapable of resolving transitive or mandatory deps.
When a plugin's phase script checks whether an enhancement is available, it calls agentm capability <name> (or imports capability_available directly). The resolver:
- Builds a registry from installed plugins' declared
capabilities:— one provider per capability, first installed wins. - Returns exit 0 (available) or exit 1 (unavailable), with optional version-range matching.
- Falls through to unavailable on any error — the safe default (LC-4).
The caller never names the providing plugin — it names the capability. "git-review" is a capability; a plugin that declares capabilities: [git-review] is its provider. The caller is insulated from which plugin provides it.
enhances: borrows vocabulary from the MCP / capability-negotiation world (V5-9) but is not a wire protocol. It is a manifest-level declaration, resolved statically at runtime from on-disk JSON files. There is no negotiation, no handshake, no socket — just a registry lookup and a boolean answer.
V5-9 (MCP negotiation) will sit on top of this vocabulary, not replace it. The resolver is the read-only, substrate-level half; MCP will add the wire half. The two are designed to be composable.
Note
Status: implemented (V5-12) — The kind: persona primitive reuses enhances: for its optional composition. A persona lists capabilities it can exploit in enhances:, subject to the same soft-dep semantics described above: unmet entries are not errors, the persona falls back to standalone behavior. The check-personas gate does not validate enhances: entries — soft deps may name any capability (confirmed in the check-personas.py gate, which only asserts requires ⊆ substrate-native and no-always-load). See persona-tier-schema reference.
- Capability resolver reference — the API.
-
Persona tier schema — the
kind: personamanifest fields andcheck-personasgate (V5-12). - AgentM HLD — Capability discovery — the design decisions.
-
Persona tier design — design decisions for the persona primitive; DC-3 covers
enhances:reuse. - Foundations HLD — crickets split — the C3 principle (substrate beneath, not plugin host).