Headless Core + Multiple Clients

Headless Core + Multiple Clients

An architectural pattern where the core capability lives in a backend (server, daemon, library) that exposes a stable wire protocol; multiple clients (CLI, TUI, web app, agent skill, plugins, language bindings) consume the same protocol and have equal access. No client is privileged. No client gets backdoor access to internal state. Adding a new client is a small project, not a fork.

This sits one layer above The Local Daemon Pattern — the local daemon is one specific embodiment, but the headless-core idea applies just as well to cloud services, libraries, and embedded engines.

The shape

   Client A (CLI)        Client B (TUI)        Client C (web UI)        Client D (agent skill)
        │                     │                       │                          │
        └─────────────────────┴───────────────────────┴──────────────────────────┘
                                          │
                              Stable wire protocol
                              (JSON over socket, gRPC, REST, etc.)
                                          │
                                          ▼
                                    [ Core / brain ]
                                  Owns the data, the logic,
                                  the connections to backends.
                                          │
                                          ▼
                              Storage, networks, devices

The contract is the protocol. Everything above it is interchangeable.

Why this pattern works

The M × N → M + N collapse. Without the pattern, M clients × N backends = M·N integrations. With it: M clients + N backends = M + N. Each client speaks the protocol; each backend implements it. Adding a client doesn't touch the backends. Adding a backend doesn't touch the clients.

This is the same insight that made LSP work for editors-and-language-servers, DAP for editors-and-debuggers, MCP for agents-and-tools.

Historical lineage

The pattern is older than software. The newer history (rough order):

The pattern keeps being rediscovered because the M × N problem keeps being rediscovered.

Properties of a good headless core

  1. Stable protocol. Once a client depends on a schema, breaking it breaks the client. Versioning + additive changes only.
  2. No privileged client. The TUI doesn't get methods the CLI doesn't. The agent skill doesn't either. If a feature is in one, it's in all.
  3. Clear bucketing of operations. Each request fits in one well-defined category; new buckets require deliberate design. (mxr's four buckets: CoreMail / MxrPlatform / AdminMaintenance / ClientSpecific. lazydap's four: Session / Project / Diagnostics / ClientSpecific.)
  4. Boundary enforcement. Cargo dependency graph in mxr/lazydap. Module boundaries in larger systems. Network boundaries in cloud systems. The constraint is structural, not aspirational.
  5. Discoverable. Clients can introspect: "what can I do?" mxr exposes commands via clap's --help; LSP has initialize returning capabilities; MCP has tools/list.

What this enables

What this costs

The trade pays off as soon as you have two clients. Below two clients, it's overengineering.

When NOT to use this pattern

How mxr and lazydap embody this

Mxr: daemon owns SQLite, Tantivy, providers. Clients (CLI, TUI, agent skill, web bridge) consume IPC. CLI gets no special access. TUI implements features by talking to the same socket. Per-feature non-negotiable: every TUI action has a CLI equivalent.

Lazydap: daemon owns DAP adapter, session, breakpoints. Same client setup — CLI, TUI, agent skill, all peers. Even the AI integrations (future Tier 1+ capabilities) are external clients, not core features.

The pattern is the architecture. The daemon, the protocol, the bucketing, the dependency graph — all in service of "headless core, multiple clients."

Naming this in conversation

The pattern doesn't have one canonical name. Useful labels:

I lean on "headless core + multiple clients" in writing because it spells out both halves. See Client-Agnostic Cores for the synthesis.

See also