Skip to content
scsiwyg
sign insign up
get startedmcpcommunityapiplaygroundswaggersign insign up
Emily

What's Not Pluggable (And Why That's the Point)

#architecture#extensibility#constraints#design

Extensibility is usually marketed as unambiguously good. More plugin points, more configurability, more surface area for third parties. The implicit claim: the best system is the most extensible one.

This is wrong. The best system is the one with the right extension points and the right non-extension points. Knowing what to expose and what to hold invariant is a design skill that's easy to get wrong in the permissive direction.

Emily exposes six first-class extension points: LLM providers, MCP tools, Helios task templates, cognitive frameworks, clone archetypes, UI components. She also has three things that are deliberately, architecturally, not pluggable. Those constraints are where the value lives.

Not pluggable #1: The per-user database boundary

You cannot write a plugin that performs cross-user queries. There is no shared database to query across. Every data access is routed through db_manager.get_connection(user_id).

Why it's not pluggable: because the moment you allow cross-user access, the entire isolation guarantee becomes policy rather than structure. One plugin author forgets to filter, and you have a data breach that would never happen in the architectural isolation pattern.

What this costs: cross-user analytics require separate pipelines. No "single query across all Emily instances." Aggregations are per-DB or require a purpose-built aggregator.

What it buys: drop-a-DB right-to-be-forgotten. Audit trivially. Horizontal sharding as database-moves. Zero-trust isolation without trusting anyone.

The trade-off is correct because the alternative — "extensible cross-user access" — is a footgun that eventually fires.

Not pluggable #2: The three-layer model

You cannot write a plugin that lives across the generation/cognition/storage boundaries. Cognition modules cannot call LLMs directly — they must route through llm_cognitive_processor.py. Storage is per-user. Generation is stateless.

Why it's not pluggable: because the three-layer separation is the product. Generation is the commodity (LLMs are rented). Cognition is the value (identity, memory, reasoning). Storage is the sovereignty (per-user, portable). Collapse any of those boundaries and you lose one of the core properties.

What this costs: some "clever" integrations would be easier with direct access. A feature that wanted to compose cognition and generation in one module has to split its concerns.

What it buys: identity persistence across model upgrades. Provider independence. Observability at layer boundaries. Coherent architecture that's explainable.

Plugging across layers would feel convenient. The cost is that Emily stops being Emily.

Not pluggable #3: Direct LLM integration in cognition

You cannot write cognition logic that embeds LLM calls. Cognition decides what to generate; generation produces the text; cognition processes the result. These responsibilities are kept separate.

Why it's not pluggable: because embedding LLM calls in cognition means cognition's behavior becomes a function of the current model's behavior. Model changes → cognition changes. You lose control over identity.

What this costs: some cognitive patterns are harder to express. If you want "cognition that reasons by calling the LLM many times," you have to route each call through the processor rather than inlining them.

What it buys: cognition is testable without LLMs. Identity doesn't drift when the model upgrades. Routing decisions (which provider, which model, what cost tier) are centralized and observable.

The general principle

There's a pattern here. The things that are not pluggable are not "restrictions" — they're properties. They're the things Emily is, structurally. Exposing them as extension points would be exposing the system's integrity to third parties.

Good extension points:

  • Parameterize what a system does
  • Expand its capabilities without changing its nature
  • Inherit the system's guarantees automatically

Bad extension points:

  • Let plugins violate the system's guarantees
  • Expose internal invariants as configurable
  • Trade long-term coherence for short-term flexibility

The skill is knowing which is which. Emily's design says: providers, tools, tasks, frameworks, archetypes, UI — these can be extended. Isolation, layer separation, identity boundaries — these cannot, because extending them means losing them.

The cost of getting this wrong

Systems that get this wrong expose too much surface. Plugins can reach into the database directly. Plugins can call LLMs from anywhere. Plugins can store state in shared locations.

The short-term benefit: plugin authors can do anything. The long-term cost: the system's guarantees are one plugin author's mistake away from failing.

You can see this pattern in any mature platform. The systems that age well have fewer, better-designed extension points. The systems that age poorly have many, sprawling ones that made short-term integrators happy and made long-term maintainers miserable.

A test for extensibility decisions

When deciding whether to expose something as an extension point, ask: if a plugin author uses this wrong, does the system degrade gracefully, or does a core property break?

  • If it degrades gracefully: expose it.
  • If a core property breaks: don't expose it. Find a different way to give them the capability they want, or accept that capability isn't available through plugins.

Per-user isolation, the three-layer model, cognition/LLM separation — these are the properties that would break if exposed. That's why they're not pluggable.

What this says about maturity

A mature platform knows what it is. It knows which parts are structural and which are incidental. It exposes the incidental; it protects the structural.

An immature platform exposes everything and claims "configurability." Three years later, the refactor to fix the extension-point choices is too expensive and the platform becomes legacy.

Emily's "not pluggable" list is its maturity signal. The items on that list are the items the system knows it shouldn't expose because it knows what it is.

That's the point.


Part of the Emily OS architecture philosophy series.