Skip to content

Chat package boundaries

Chat (and chat-component) sit at a particular position in the dependency graph: above the framework (@open-matrix/core), below applications that embed it (Director). This page is the explicit list.

Chat app — allowed dependencies

chat/package.json dependencies:

json
"highlight.js": "^11.11.1",
"katex": "^0.16.40",
"marked": "^17.0.5",
"marked-katex-extension": "^5.1.7",
"mermaid": "^11.13.0"

devDependencies includes @open-matrix/core (workspace:*) for type checking and Vite.

What that means

  • Render libs are direct deps. Markdown/KaTeX/highlight.js/mermaid are bundled into the chat browser bundle; they are required for mx-markdown-viewer, mx-code-viewer, etc.
  • @open-matrix/core is a workspace dev-dep. Type-checking against the source. At build time, Vite resolves imports through the workspace.
  • No @open-matrix/agents, @open-matrix/inference, @open-matrix/observability, @open-matrix/factotum. Chat reaches those via RequestReply only; it never imports their source.
  • No @open-matrix/director, @open-matrix/smithers, @open-matrix/flowpad. Chat is below them; they may consume chat-component, never the other way.

chat-component — same set

chat-component/package.json declares the same dependencies. The two packages are intentionally aligned at the dependency level so they produce equivalent browser bundles for the shared element set, plus chat-component adds its own surface/.

Forbidden imports

Per CLAUDE.md Coding Standards:

  • No cross-package ../../ imports — only declared npm dependencies.
  • TypeScript strict mode — no any, no as any.
  • No console.log — use actorLog() for bus-native logging.

The vite.config.ts for both packages adds aliases that resolve @open-matrix/core/* to source in dev (for HMR) and to the built dist in production. Anything that escapes those aliases is suspect.

Runtime vs browser split

Chat is a hybrid package: same source builds two outputs.

OutputTsconfigPurpose
dist/browser/tsconfig.jsonBrowser custom elements, services, bootstrap.
dist/runtime/tsconfig.runtime.jsonRuntime-side actor declarations consumed by mx-cli / Host Service.

The runtime build excludes anything that requires the DOM. The browser build excludes Node-only modules. vite.config.ts and vite.runtime.config.ts are separate; build.mjs orchestrates both.

When you add code to chat/src/, decide which build it belongs to:

  • DOM/CustomElement classes → browser build only.
  • Headless actors that the runtime instantiates (ChatConversationProxy, ChatExportService) → runtime build, but their interface is also visible to the browser via services/impl/* for the standalone-local mode.

Manifest declarations enforce the boundary

chat/matrix.json:

json
{
  "class": "hybrid",
  "namespace": "chat",
  "root": { "type": "MatrixChatApp", "export": "MatrixChatApp", "mount": "chat", "surface": "browser" },
  "runtime": {
    "language": "typescript",
    "entry": "./dist/runtime/index.js",
    "browserEntry": "./dist/browser/register-elements.js",
    "bootstrapEntry": "./dist/browser/bootstrap.js",
    "environments": ["browser", "headless-dom", "runtime"],
    "executionClassCompatibility": [
      "shared_host_service", "dedicated_process",
      "container", "isolate", "remote_managed_service"
    ]
  },
  "components": [...9 headless services...],
  "consumes": [...6 service contracts...],
  "permissions": { "fsPolicy": "none", "network": true, "subprocess": false, "env": false }
}

Key facts:

  • class: "hybrid" — has both browser and runtime sides.
  • environments: ["browser", "headless-dom", "runtime"] — the runner picks the matching environment for the runtime side.
  • permissions.fsPolicy: "none" — Chat never reads or writes the filesystem at runtime.
  • permissions.subprocess: false, env: false — Chat does not spawn processes or read env vars.
  • permissions.network: true — necessary for the bus (NATS-WS) and the markdown libs that fetch fonts.

The consumes[] list declares which IChat*Service contracts the package needs. Required: IChatConversationService, IChatComponentLibraryService, IChatSessionStateService. Optional: identity, preferences, MCP.

Surface declaration (chat-component only)

chat-component/matrix.json adds:

json
"surfaces": {
  "conversation": {
    "tag": "conversation-surface",
    "module": "./dist/browser/surface/register-surface.js",
    "route": "/apps/chat-component/surface/register-surface.js",
    "description": "Embeddable conversation surface plugin loaded by host shells (Director, etc.) via dynamic import"
  }
}

This is metadata for future host-side import-map work (HARVEST-040). It is currently informational.

See also

Source: projects/matrix-3/packages/chat/package.json, chat/matrix.json, chat/vite.config.ts, chat-component/matrix.json.