packages/. Each package has a single responsibility, exports a public API via dist/index.js, and follows strict dependency rules — always importing inward toward @comis/core, never across sibling packages’ internals.
All packages use ES modules ("type": "module"), strict TypeScript with composite: true project references, and ES2023 as the compilation target.
Package Overview
| Package | npm Name | Role | Key Exports |
|---|---|---|---|
| shared | @comis/shared | Result type, utilities (zero runtime deps) | Result, ok, err, tryCatch, fromPromise |
| core | @comis/core | Domain types, ports, event bus, security, config, plugins | Ports, domain types, EventMap, config schemas, security utils |
| infra | @comis/infra | Pino structured logging | Logger factory, log level manager |
| memory | @comis/memory | SQLite + FTS5 + sqlite-vec vector search | SqliteMemoryAdapter (implements MemoryPort) |
| gateway | @comis/gateway | Hono HTTP, JSON-RPC, WebSocket, mTLS, OpenAI-compatible API | HTTP server, RPC dispatch, WebSocket handler |
| skills | @comis/skills | Skill manifest, prompt skills, MCP, built-in tools, media processing | SkillRegistry, media preprocessor, STT/TTS/vision adapters |
| scheduler | @comis/scheduler | Cron jobs, heartbeat checks, task extraction | Cron engine, heartbeat monitor, task extractor |
| agent | @comis/agent | Executor, budget, circuit breaker, RAG, sessions, context engine | PiExecutor, session manager, budget tracker |
| channels | @comis/channels | 10 platform adapters (Discord, Telegram, Slack, WhatsApp, Signal, iMessage, LINE, IRC, Echo, Email) | Channel adapters, message mappers, media resolvers |
| cli | @comis/cli | Commander.js CLI, JSON-RPC client | CLI commands, RPC client |
| daemon | @comis/daemon | Orchestrator, observability, graph coordinator | DaemonInstance, wiring, graph coordinator |
| observability | @comis/observability | Diagnostics substrate: queued writer, payload bounding, sanitization, cache-trace runtime, EventBus bridge, cache-stats aggregation and RPC | Diagnostics runtime, cache-trace recorder, stats aggregator |
| orchestrator | @comis/orchestrator | Inbound pipeline, execution coordination, channel-manager, command queue, routing, and cross-session messaging | Pipeline coordinator, channel manager, command router |
| comis | comisai | Umbrella package (namespace re-exports) and comis CLI bin | Namespace re-exports of all sub-packages |
| web | @comis/web | Lit + Vite + Tailwind standalone SPA | Web dashboard views and components |
Package Roles Explained
@comis/shared is the foundation. It defines the Result<T, E> discriminated union and its utility functions. Every other package depends on shared, but shared depends on nothing. This makes it safe to import anywhere without creating circular dependencies.
@comis/core is the heart of the hexagonal architecture. It defines all 19 port interfaces in src/ports/, all domain types as Zod schemas in src/domain/, the TypedEventBus for inter-module communication, security primitives (SafePath, SecretManager, ActionClassifier), 22+ config schemas, and the plugin infrastructure (PluginRegistry, HookRunner). The composition root bootstrap() function lives here and returns an AppContainer.
@comis/agent is the execution engine. It contains the PiExecutor that orchestrates LLM calls, tool execution, and response generation. It also manages sessions (conversation state), budgets (token/cost limits), circuit breakers (automatic failure recovery), and RAG (retrieval-augmented generation from memory). It also contains the context engine — a 10-layer pipeline that manages token budgets and conversation length before each AI call.
@comis/channels contains the 10 platform adapters. Each adapter lives in its own directory (e.g., src/telegram/, src/discord/) with a standard file set: adapter, message mapper, media handler, credential validator, media resolver, voice sender, and plugin wrapper.
@comis/daemon is the top-level orchestrator. It wires all packages together using the composition root, manages the process lifecycle (startup, shutdown, signal handling), runs the graph coordinator for multi-agent pipelines, and provides observability metrics. This is the only package that depends on all other packages.
@comis/web is a standalone single-page application built with Lit web components, Vite for bundling, and Tailwind CSS for styling. It communicates with the daemon exclusively through the gateway’s HTTP and WebSocket APIs.
The published umbrella package is named
comisai on npm (the directory is packages/comis/). It bundles all @comis/* workspace packages and exposes a comis CLI binary. Subpath imports such as comisai/core or comisai/agent are exposed via the umbrella’s exports map.Dependency Graph
The dependency graph flows inward — adapters depend on ports (in core), never on each other. Thedaemon package sits at the top as the composition root that wires all packages together.
Layer Summary
sharedis the leaf — zero runtime dependencies, imported by everything. Defines theResult<T, E>type and utility functions (ok,err,tryCatch,fromPromise).coredepends only onshared— defines all 19 port interfaces, domain types, typed events, security primitives, and config schemas.- Mid-tier packages (
infra,memory,gateway,skills,scheduler) each depend oncoreand implement specific port interfaces or provide infrastructure services. agentdepends oncore,infra,memory, andscheduler— orchestrates execution, sessions, RAG, budgets, and circuit breakers.channelsdepends oncore,agent, andinfra— platform adapters that receive messages and route them to agents.clidepends oncore,memory, andagent— the command-line interface for managing the daemon via JSON-RPC. (Note:@comis/agentis a runtime dependency via package.json but not a tsconfig reference.)daemondepends on all packages — it is the composition root that wires everything together at startup and manages the process lifecycle.comisis the umbrella package that re-exports all other packages under a single namespace.webis a standalone SPA (Lit + Vite + Tailwind) that communicates with the daemon via the gateway HTTP API.
Package Boundary Rules
These rules are mandatory across the codebase and enforced through code review and architectural convention (see AGENTS.md section 6.2).No Cross-Package Internal Imports
Import from the package’s public API, never from internal source paths. Each package exports its public surface throughdist/index.js. This ensures that internal refactoring within a package never breaks consumers.
Dependency Direction Is Always Inward
Adapters depend on ports (in core), never on each other.channels never imports from gateway. skills never imports from agent. If two sibling packages need to communicate, they do so through the TypedEventBus or through shared domain types defined in core.
Inject Logger via Deps Interface
Never import@comis/infra directly in non-infra packages. Pass a logger through the dependency injection pattern so that packages remain decoupled from the logging implementation. This also makes unit testing easier since you can inject a mock logger that captures log calls for assertions.
ES Modules Only
All packages use"type": "module" with .js extensions in import paths. There are no CommonJS modules in the codebase. Import statements use the .js extension even though the source files are .ts:
Build System
TypeScript project references (composite: true) enable incremental builds across the monorepo. Each package has its own tsconfig.json that references its dependencies, so pnpm build compiles all packages in the correct order respecting the reference graph.
| Setting | Value | Notes |
|---|---|---|
| Target | ES2023 | Modern JavaScript output |
| Module resolution | NodeNext | Native ESM with .js extensions |
| Strict mode | Enabled | All strict TypeScript checks active |
| Build output | packages/*/dist/ | Gitignored, built on CI |
| Isolated modules | true | Compatible with esbuild and other bundlers |
| Package exports | "main": "./dist/index.js" | Plus "types": "./dist/index.d.ts" |
Integration tests in
test/integration/ require pnpm build first because they import from dist/, not from source. Run them with pnpm test:integration.Scale
The Comis monorepo contains approximately:- ~1185 source files across 15 packages
- ~944 test files co-located with source code
- 19 port interfaces defining the hexagonal architecture boundaries
- 183 typed events across 5 domain subsystems (Messaging, Agent, Channel, Infra, Terminal) — see Event Bus for the full per-subsystem breakdown
- 13 lifecycle hooks for plugin integration (5 modifying, 8 void)
- 10 channel adapters connecting to real-world chat platforms
Related
Architecture
How packages connect through ports and adapters
Event Bus
Cross-package communication via typed events
Contributing
Setup and build instructions
Developer Guide
Back to developer guide overview
