Design Philosophy
The runtime worldview behind “everything is a plugin”
Conclusion: replaceability is achieved by making interactions stricter
“Everything is a plugin” does not mean that any component may behave arbitrarily. DeepSeek Harness makes implementations replaceable by concentrating obligations into a small set of protocols: named services, typed event modes, effect ownership, scope routing, append-only facts, explicit commit points, and package-owned runtime invariants.
The architecture moves the fixed center away from concrete classes and toward interaction rules. That is the central design choice behind boot composition, Agent lifecycle, the Turn / Step Loop, tools, prompt contributors, providers, persistence, and UI projections.
1. “No privileged core” does not mean “no architectural spine”
The model adapter, tool registry, session log, and Agent Loop are all mounted as Cordis plugins. A neighboring plugin may contribute or replace behavior without patching a privileged application object, and its registrations unwind when that plugin unloads. ARCH-PLUGIN-CORE
There is nevertheless a spine. It consists of public service keys, interfaces, event names and modes, session-event vocabulary, scope rules, and configuration entry identities. Replacing a provider leaves those obligations in place.
| Replaceable implementation | Protocol that remains | Why the distinction matters |
|---|---|---|
| LLM provider | Adapter registration, request/stream vocabulary, normalized errors and usage | The Loop must consume every provider through one stable seam |
| Tool | Definition, schema, guarded execution, durable call/result events | Policy and replay cannot depend on a tool's private body |
| Agent driver | Agent interface, registry lifecycle, inbox and session facts | Surfaces can drive an Agent without importing the default Loop |
| Persistence backend | Session header and event-log semantics | Reloaded history must mean the same thing as live history |
The phrase “unprivileged core” describes implementation authority, not the absence of a constitution. The protocols are the real core. A plugin can be swapped only if the replacement preserves the obligations its consumers rely on.
2. Five composition primitives replace a central application class
Cordis supplies five recurring mechanisms: plugins implement a Service lifecycle; contexts expose services by stable key; inject declares availability dependencies; typed events choose observation or interception semantics; and effect/on bind contributions to teardown. DESIGN-CORDIS-SEMANTICS
| Primitive | Architectural job | Failure if misused |
|---|---|---|
| Service key | Separates a capability definition from its provider | A consumer imports a concrete provider and makes configuration replacement cosmetic |
inject | Expresses required topology without depending on YAML row order | A plugin observes a missing service or invents a silent fallback |
| Typed event | Lets policy, adapters, and observers attach without importing the orchestrator | The event mode and the caller's expectation diverge |
| Waterfall | Forms around-middleware with deliberate delegation through next() | An observer accidentally short-circuits a decision chain |
| Effect | Makes registration and retraction one owned lifecycle | HMR or session disposal leaks stale providers, tools, or listeners |
emit, parallel, serial, and waterfall are not stylistic variants. Awaiting, ordering, return-value, and short-circuit semantics differ; choosing a mode defines who may influence the operation.
3. Registration is an owned resource, not a global mutation
Prompt sections, tool definitions, adapters, providers, and event listeners register as reversible effects. Registry register() methods return exact disposers, and HMR-safety tests must prove removal after the owning fiber is disposed. ROOT-EFFECTSPKG-INVARIANTS
ScopedLayers makes the registration context carry two meanings at once: which scope can see a contribution and which effect owns its lifetime. Global entries are overlaid by ancestor scopes and finally by the nearest scope; undo removes only the exact registration and reclaims an empty layer. DESIGN-SCOPED-LAYERS
Scope tests verify synchronous usability, shared quiescence across repeated disposal, reverse cleanup order, key-routed event visibility, and one-way inheritance: a descendant dispatch reaches ancestor-scoped listeners, while an ancestor dispatch does not leak down to descendants. DESIGN-SCOPE-TEST
This is dependency injection plus a resource ledger. The context through which a plugin contributes something records both reachability and responsibility for removing it. That coupling is what makes live configuration and per-Agent composition feasible without a separate global cleanup registry.
4. Durable facts and live decisions occupy different planes
| Plane | Examples | Lifetime | Purpose |
|---|---|---|---|
| Durable session events | turn/start, messages, request headers, chunks, tool calls/results, turn/end | Survives reload and persistence | Conversation truth, reconstruction, replay, projections |
| Live Agent events | agent/pre-step, agent/request, request-error recovery, stopping | One active process and scoped runtime | Interception, policy, routing, control |
| Capability events | Tool, filesystem, telemetry, and provider hooks | Provider/plugin lifecycle | Attach policy without coupling to the Loop |
The session log is the source of model history. Anything entering a model request must be reconstructable from that log; model-visible input therefore requires a session event instead of an ephemeral callback-only mutation. ARCH-LOGROOT-MODEL-LOGGED
The default Loop marks its requests and installs an invariant that independently derives messages and folds the request header from the session log, then compares both with the request about to be dispatched. LOOP-REQUEST-INVARIANT
Event sourcing is used selectively. The durable stream records semantic conversation facts; not every live callback, registry mutation, or process detail becomes an event. This avoids treating the log as a dump of the whole runtime while preserving the one projection that must be reproducible: what the model saw.
5. Commit points separate preparation from publication
Repository rules require one owner for one asynchronous operation, forbid publishing derived state before success, require limits to apply where a complete value is known, and assign every runtime invariant to the package that owns the relationship. DESIGN-PACKAGE-RULES
The verified runtime chapters show the same idea at different scales:
Boot
Compose and prepare a candidate tree; return it only after Loader settlement and activation audit.
Agent creation
Build Session, Agent, and scoped world while unpublished; synchronously commit setup; then enter and announce registries in a fixed order.
Inbox mutation
Append the durable splice before mutating the live queue projection.
Turn execution
Append boundaries and request inputs before dispatch; commit assistant and tool outcomes before the next derived request.
The recurring state machine is prepare → validate → commit → publish → dispose. The exact commit artifact changes—a Loader tree, a registry entry, a session event—but downstream consumers are intentionally prevented from seeing a candidate state that can still fail.
6. A capability is a three-role seam
A complete capability seam consists of a Service Definition, at least one Service Provider, and a Consumer. A provider alone is not a product capability; a tool or UI consumer alone is not a replaceable abstraction. ARCH-LOG
| Role | Should know | Should not own |
|---|---|---|
| Definition | The shared operations and obligations required by all current consumers | One provider's deployment details or one UI's vocabulary |
| Provider | External API/process/storage details and provider-local configuration | Model-facing product policy that must survive provider replacement |
| Consumer | How the capability appears to a model, user, API, or orchestrator | Hidden assumptions about a single provider implementation |
This separation prevents the most common false modularity: defining an interface whose fields merely mirror the first backend. The cost is more packages and explicit wiring, but provider replacement becomes a real configuration operation rather than a rewrite of every caller.
7. Behavior belongs beside the Loop, not inside it
The default Loop owns the minimum orchestration skeleton: open a Turn, claim input, assemble a step, derive a request, stream the model, execute tools, and decide whether another step is owed. Prompt contributors, request rewriting, retry decisions, tool policy, context injection, and stopping behavior attach through services and events. ARCH-TURNLOOP-TURN-STATE
A small Loop is not pursued for line count. It is kept stable so independently owned behaviors can change without creating a second orchestration path. The price is semantic distribution: understanding one request requires following registrations across several plugins, not reading a single large function.
8. Explicit boundaries determine where trust stops
Same-process values already guaranteed by static TypeScript interfaces are trusted. Runtime validation is required at parsing/configuration, model/tool JSON, durable storage, worker, process, and wire boundaries. Deployment-varying values belong in validated configuration; missing referents fail at the earliest resolvable point; cross-boundary identities use branded types. ROOT-BOUNDARIES
| Boundary | Preferred treatment | Rejected pattern |
|---|---|---|
| Typed call within one process | Trust the interface and keep the path direct | Duplicate defensive parsing and silent fallbacks |
| Config/parser/wire | Validate the complete incoming value and fail with ownership context | Partially accept malformed values |
| Model/tool JSON | Parse, normalize, snapshot, and preserve a machine-routable failure | Treat probabilistic output as statically trustworthy |
| Persistence/replay | Validate format, identity, continuity, and JSON losslessness | Load a history that live code could never have produced |
| Policy decision | Enforce where execution occurs | Assume schema omission or UI filtering is authorization |
9. Invariants turn local ownership into runtime evidence
The invariant registry reserves one registration per package, applies allow/block selection, installs enabled checks in a service-owned child fiber, and wraps violations in an INVARIANT-coded error attributed to that package. Failed setup and disposal both release the reservation. DESIGN-INVARIANT-REGISTRY
An invariant is expected to check a relationship the package owns—such as request reconstruction, scope routing, or event pairing—not merely prove that a method exists. This matters in a plugin system because type correctness cannot establish that the assembled runtime still respects cross-plugin order and identity.
The invariant system acknowledges a hard truth of configuration-driven architecture: many failures appear only after a valid set of packages has been composed in an invalid relationship. Package attribution improves diagnosis, while selectable checks keep the mechanism operational rather than test-only.
10. Developer Preview changes the compatibility bargain
At the pinned baseline the project explicitly prioritizes foundational corrections over compatibility shims before its first tag. SQLite schema versions move monotonically, while the session format remains version 0 with no compatibility promise; old on-disk formats may be rejected. ROOT-PREVIEW
Current elegance must not be mistaken for a stable public contract. The architecture clearly invests in explicit protocols, yet names, package boundaries, configuration rows, and persisted formats can still change rapidly. This study therefore pins every claim to one commit and treats later upstream changes as a new baseline, not as corrections silently folded into history.
11. What this philosophy buys—and what it makes harder
| Choice | Benefit | Structural cost |
|---|---|---|
| Everything mounts as a plugin | Product surfaces and providers are configuration-composable | The effective runtime cannot be understood from imports alone |
| Registrations are effects | HMR and scoped teardown retract contributions predictably | Every contribution needs correct ownership and quiescence |
| Events are extension points | Policy attaches without Loop imports | Mode, order, short-circuit, and scope become public semantics |
| Model-visible means logged | Requests, replay, and projections can agree | Even transient context needs a durable representation and retention semantics |
| Explicit commit points | Observers see committed state rather than candidates | Preparation and rollback paths become more elaborate |
| Definition/provider/consumer seams | Provider replacement is genuine | Package count and composition surface grow |
| Package-owned invariants | Cross-plugin mistakes fail near their semantic owner | Invariant coverage must evolve with every protocol extension |
The architecture does not remove a core; it relocates the core into protocols and lifecycle rules. That is a strong fit for an Agent harness whose providers, tools, policies, and product surfaces must vary independently. Its success depends on disciplined ownership, generated maps, runtime invariants, and reconstructable logs. Without those safeguards, the same indirection would become a distributed, configuration-sensitive control flow that is harder—not easier—to reason about.
Chapter verification checklist
- Separated replaceable implementations from the protocols that remain mandatory.
- Verified Cordis service, injection, event-mode, waterfall, and effect semantics.
- Traced scope visibility and effect ownership into production storage and behavioral tests.
- Connected the model-visible/logged policy to the Loop's executable reconstruction invariant.
- Checked commit-point and ownership rules against Boot, Agent, Inbox, and Turn mechanisms.
- Verified package-attributed invariant installation and teardown.
- Preserved the Developer Preview compatibility caveat in every design assessment.
My Learning Notes
Autosaved only in this browser. Nothing is uploaded or committed. Export Markdown whenever you want to keep a copy.