Package and app boundaries
Dependency direction
Arrows point at what a layer is allowed to depend on. Anything not drawn is not allowed.- Protocol and home packages sit below executable apps.
- Clients depend on protocol contracts, not daemon implementation.
- Daemon domains may depend on protocol and home contracts, but extension SDKs must not depend on daemon internals.
- UI packages consume client/cache layers; they do not import
apps/monad. - Runtime boundary types are schema-first at process, HTTP, WebSocket, file, MCP, atom, and skill boundaries.
Daemon module ownership
The daemon uses explicit lifecycle modules for long-lived resources. A module belongs beside the behavior it manages:store/lifecycle.tsowns persistence startup and shutdown.services/log-maintenance/lifecycle.tsowns persistent-log cleanup scheduling and shutdown.platform/sandbox/lifecycle.tsowns sandbox setup.agent/model/lifecycle.tsowns model services, provider discovery, and embedding indexer lifecycle.capabilities/lifecycle.tsowns stable first-party tool and command registries.atoms/lifecycle.tsowns atom discovery.capabilities/skills/lifecycle.tsowns skill discovery and watch integration.capabilities/mcp/lifecycle.tsowns MCP connection state.
runtime/create.ts assembles descriptors into RuntimeKernel; it is not a
business-logic dumping ground. application/lifecycle.ts orchestrates process
startup, application services, handlers, and transport launch.
Extension points
Prefer public extension surfaces over daemon imports:- Skills for procedural knowledge and tool-use recipes.
- Atom packs for skills, channels, MCP servers, providers, hooks, and other declared extension kinds.
- MCP for external tools.
- Command hooks or atom hooks for agent-loop policy and observability.
- Protocol/client packages for API integrations.
apps/monad internals. If an extension
needs a new stable contract, add or extend the appropriate protocol or SDK package
instead of leaking daemon implementation types.
Anti-patterns
- Reintroducing a central
bootstrap/hierarchy for daemon behavior that already has an owning domain. - Putting runtime service instances into Zustand. Zustand is for serializable
lifecycle state; service outputs live in
RuntimeContext. - Reading or writing settings files outside environment initialization/repair or the daemon ConfigManager source.
- Using RxJS, revision queues, or global event logs for local config hot reload.
Use
ConfigManagerand module reload hooks. - Adding feature-specific
process.platformbranches outside a thin platform adapter. - Redeclaring wire/domain types in consumers instead of deriving from the schema producer.
- Adding UI-only state to protocol packages or daemon-only state to UI packages.
Recorded decision: @monad/sdk-experience
The workplace-experience SDK is one package with two entry points, split on the React
boundary by subpath — so a third-party web-component experience author can type the host
API without pulling in React, while a host-component author gets the RTK hooks from the same
package.
@monad/sdk-experience(root) — the React-free contract: the published snapshot/actions/host-API types plus the framework-agnostic runtime helpers (WORKPLACE_EXPERIENCE_API_VERSION,defineWorkplaceExperience,isWorkplaceExperienceApiCompatible,bindWorkplaceExperience, the DOM event bridge). Dependencies:@monad/protocolonly, zero React.web-componentatoms (external custom elements, e.g. graph-view) can’t use React hooks and stay on this event-bridge contract.@monad/sdk-experience/react— a curated re-export subset of@monad/client-rtk’s RTK Query hooks, scoped to whathost-component(React) atoms in@monad/atomsneed. It must never grow a second implementation of an endpoint; every export re-exports a hook that already exists in@monad/client-rtk.react/react-reduxare optional peer deps — importing the root never pulls them in. This works because built-in host-component experiences render inside the host app’s Redux<Provider>(seeapps/web/src/lib/monad-store.ts/monad-runtime-provider.tsx).
@monad/sdk-atom
stays the pure atom-authoring adapter contract (protocol + zod only), unrelated to this package.
WorkplaceExperienceDefinition/Entry/HostApi remain wire types in @monad/protocol; the daemon
consumes those directly.