# Architecture Decisions This file records decisions that are still relevant to the current implementation. ## ADR-000: Platform-First Runtime OpenHermit optimizes for hosted multi-agent operation instead of a single local assistant process. The gateway is the control plane, and agents are registered resources with durable state and lifecycle management. ## ADR-001: Internal State Is Outside The Workspace Conversation history, memories, instructions, users, schedules, skills, MCP assignments, and sandbox rows (per-agent execution environments) are internal state. They live in PostgreSQL, scoped by `agent_id` where applicable. The workspace is external task state: user files, generated artifacts, repositories, and mounted data. ## ADR-002: PostgreSQL With Drizzle Stores `packages/store` uses Drizzle and PostgreSQL. SQL migrations live in `packages/store/drizzle/`; schema definitions live in `packages/store/src/schema.ts`. PostgreSQL gives shared durable state for many agents, indexed event/session queries, and full-text memory search. Drizzle keeps query code close to TypeScript types without introducing a generated ORM client. ## ADR-003: Gateway-Managed In-Process Agents The current gateway starts `AgentRunner` instances in-process through `AgentInstanceManager`. This is simpler than a reverse proxy over per-agent processes while preserving explicit `/api/agents/{agentId}/...` routing and per-agent lifecycle. The `AgentInfo.port` field remains protocol-compatible metadata, but current managed agents do not require per-agent ports. ## ADR-004: Durable Sessions Do Not Close Permanently Sessions are durable threads. They can be idle, running, awaiting approval, or inactive. `/new` and channel session switching mark old sessions inactive rather than destroying history. ## ADR-005: User Identity Is Channel-Based And Role-Gated Users are resolved from `(channel, channelUserId)` identities. Roles are per-agent: `owner`, `user`, or `guest`. Owners get full management tools. Users get standard memory/web/session access. Guests are intentionally restricted. Channel adapters can auto-create unknown identities as guests. ## ADR-006: Introspection And Compaction Are Separate Compaction keeps model context within limits. Introspection maintains long-term memory, working memory, and session descriptions. They run on different triggers and use different tool surfaces. ## ADR-007: Program-Driven Scheduler Scheduling is a first-class subsystem with cron and one-shot schedules. Schedules are stored in PostgreSQL, run through `Scheduler`, and post prompts back into agent sessions through `AgentRunner` host callbacks. ## ADR-008: Skills Are Prompt Assets, MCP Servers Are Tool Providers Skills are directories containing `SKILL.md` and optional supporting files. They are indexed in the prompt and synced into each exec backend's sandbox at `/.openhermit/skills/system/` via `runner.syncSkills`. MCP servers are executable external tool providers. Their tools are discovered at runtime and exposed as namespaced `mcp__{serverId}__{toolName}` tools. ## ADR-009: Built-In Channels Run Beside Agents Telegram, Discord, and Slack adapters are built-in channel packages. The gateway starts them when the agent config enables them, registers per-channel bearer tokens, and records status for the UI/API. Adapters use the OpenHermit SDK over gateway agent routes instead of reaching into runner internals. ## ADR-010: Execution Backends Are Pluggable The `exec` tool runs through an `ExecBackendManager`, built from per-agent rows in the `sandboxes` table. Four backends are implemented: `docker`, `host`, `e2b`, and `daytona`. Gateway-created agents auto-provision a sandbox from the preset named by `autoProvisionSandbox` in `gateway.json` (default: `docker-ubuntu`); the `host` backend is reserved for the privileged "devops" agent (see [`sandbox-model.md`](./sandbox-model.md)).