# openclaw/openclaw

> Local Gateway that connects ~28 chat channels and companion apps to an embedded tool-calling agent with SQLite state and plugins.

- Category: [Open-source personal assistants](https://llms-technical-reviews.com/personal-assistants/)
- Repository: https://github.com/openclaw/openclaw (reviewed at commit `10334ec913d7b18f32e6e1d16e9ac10bdc760534`, 2026-10-06)
- Stars: 391500 · Language: TypeScript · License: MIT
- Canonical page: https://llms-technical-reviews.com/p/openclaw/

## Overview

OpenClaw is a self-hosted assistant built around one long-running process, the Gateway. The Gateway owns sessions, tools, events and channel connections. Clients connect to it: chat platforms (WhatsApp, Telegram, Slack, Discord, Signal, iMessage, Teams, Matrix and many more), the browser Control UI, the CLI and TUI, and companion apps for macOS, iOS, Android and Linux that add voice, camera, screen and "Canvas" actions. A message from any of them becomes a turn in a per-conversation session, which runs an embedded agent loop with tools, memory and skills.

Measured by code, it is the largest project in this category. `src/agents/` alone has more than 900 non-test files, `src/gateway/` about as many, and `extensions/` holds 175 bundled plugins: model providers, channels, memory backends, speech, search and more. The engineering rules in `AGENTS.md` explain the shape: "one owner per responsibility", "small core, capable plugins", SQLite for all state, and database access in worker threads instead of on the Gateway's main thread. The result is very modular and heavily guarded, but hard to read end to end.

OpenClaw is for people who want an assistant that lives in their existing chat apps and on their own machines, with no hosted tier. It is equally usable as one person's assistant on a laptop or as a team deployment. It ships with permissive defaults: host shell execution is on without prompts unless you configure exec policy or a sandbox.

## Architecture

```mermaid
flowchart LR
  CH["Channel plugins (Telegram, Slack...)"] --> IN["Inbound access + pairing"]
  UI["Control UI / CLI / TUI / apps"] --> GW["Gateway (HTTP + WebSocket)"]
  IN --> DSP["auto-reply dispatch"]
  GW --> DSP
  DSP --> RUN["Embedded agent runner"]
  RUN --> ATT["Attempt: prompt, tools, compaction, failover"]
  ATT --> LOOP["agent-core runLoop"]
  LOOP --> PRV["Provider plugins via packages/ai"]
  LOOP --> TOOLS["Tools: exec, files, browser, sessions, cron..."]
  TOOLS --> POL["Exec policy + approvals"]
  TOOLS --> SBX["Optional sandbox (Docker/Podman/SSH)"]
  ATT --> MEM["Memory plugin (memory-core)"]
  RUN --> DB["SQLite state + transcripts"]
  HB["Heartbeat + cron"] --> DSP
```

| Component | Path | Role |
|---|---|---|
| CLI entry | `openclaw.mjs`, `src/entry.ts`, `src/cli/` | `openclaw` command: onboarding, gateway, pairing, doctor, update |
| Gateway | `src/gateway/` | HTTP/WebSocket server, server methods, approvals, Control UI, OpenAI-compatible API |
| Channels | `src/channels/`, `extensions/<channel>/` | `ChannelPlugin` contract and about 28 bundled channel plugins |
| Inbound dispatch | `src/auto-reply/` | Context finalization, command detection, debouncing, reply dispatch, heartbeat |
| Embedded runner | `src/agents/embedded-agent-runner/` | Run orchestration, attempts, model resolution, compaction, failover |
| Agent core | `packages/agent-core/` | `Agent` class and the provider/tool loop with steering and tool batches |
| Provider layer | `packages/ai/`, `src/llm/`, `extensions/<provider>/` | Transports, stream wrappers, provider plugins |
| Tools | `src/agents/tools/`, `src/agents/bash-tools.*` | Core tools (sessions, cron, nodes, image, browser, terminal) and exec |
| Security | `src/infra/exec-approvals*.ts`, `src/security/`, `src/agents/sandbox/` | Exec policy, DM/group access, audit, sandbox backends |
| Memory | `packages/memory-host-sdk/`, `extensions/memory-core/` | Memory host SDK, default memory plugin with search and "dreaming" |
| Apps | `apps/{macos,ios,android,linux}` | Companion apps and device nodes |

## How a request flows

Take a Telegram DM, "remind me tomorrow to renew the passport":

1. **Admit the sender.** The Telegram plugin implements `ChannelPlugin`, a bundle of adapters for config, pairing, security, groups, mentions, outbound, status, auth, approvals, commands and secrets ([types.plugin.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/channels/plugins/types.plugin.ts#L44-L92)). The default DM policy is `pairing`: an unknown sender gets a pairing code, and the owner approves it with `openclaw pairing approve`. Groups default to an allowlist ([dm-policy-shared.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/security/dm-policy-shared.ts#L108-L130)).
2. **Dispatch.** `dispatchInboundMessage` finalizes the message context, installs outbound hooks, and calls `dispatchReplyFromConfig`, or the group-thread dispatcher for threaded groups ([dispatch.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/auto-reply/dispatch.ts#L183-L260)). Slash commands and directives are handled here before any model call.
3. **Run.** The reply runner picks a candidate (embedded or an external CLI harness) and calls `runEmbeddedAgent`. The orchestrator wraps the run in plugin-generation scopes, can refresh plugins and continue the same task, and settles usage and terminal receipts ([run-orchestrator.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/agents/embedded-agent-runner/run-orchestrator.ts#L630-L700)).
4. **Attempt.** Inside an attempt the runner builds the prompt from workspace bootstrap files (`AGENTS.md`, `SOUL.md`, `IDENTITY.md` and others), skills, memory and history. It then calls `activeSession.prompt` under a session transcript lock ([attempt-execution-phase.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/agents/embedded-agent-runner/run/attempt-execution-phase.ts#L115-L132)). That is the agent-core `Agent`, which calls `runAgentLoop` ([agent.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/packages/agent-core/src/agent.ts#L547-L558)).
5. **Loop.** `runLoop` streams the assistant response and starts tool calls while the stream is still arriving, then runs any remaining calls as a terminal batch. It continues while there are tool results or queued "steering" messages, which are user messages that arrived mid-run and get injected at the next checkpoint. It marks the turn tainted when tool output is untrusted, and records a loop-intervention flag when the tool-loop detector fires ([agent-loop.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/packages/agent-core/src/agent-loop.ts#L131-L330)).
6. **Act.** Here the model would call the `cron` tool to schedule a job in the Gateway's scheduler. A shell command would instead go through `exec`, whose host and approval policy are described below.
7. **Reply.** Streaming text and the final reply go back through the channel's outbound adapter. The transcript and session state are written to SQLite.

## Key components

### Gateway

`startGatewayServerCore` defaults to port 18789 and boots a kernel that loads plugins, channels, cron, hooks and the WebSocket control protocol ([server-start.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/server-start.ts#L17-L40)). The same process serves the Control UI, an OpenAI-compatible endpoint, plugin HTTP routes and the methods the CLI, TUI and apps use. Approvals for exec and other gated actions are delivered to whichever surface is watching, including Web Push.

### Exec policy

Exec has a host (`sandbox`, `gateway` or `node`), a security level (`deny`, `allowlist`, `full`) and an ask mode (`off`, `on-miss`, `always`). Five named modes map onto those: `deny`, `allowlist`, `ask`, `auto` (allowlist plus automatic review) and `full` ([exec-approvals-core.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/infra/exec-approvals-core.ts#L115-L134)). With nothing configured, the requested policy is `security: "full"`, `ask: "off"` ([exec-approvals-effective.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/infra/exec-approvals-effective.ts#L25-L26)), and the approvals file defaults match ([exec-approvals-config.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/infra/exec-approvals-config.ts#L95-L98)). Set `tools.exec.mode: ask` or `allowlist` if you want prompts or a command allowlist.

### Sandbox

Sandboxing is per agent, with `mode` set to `off`, `non-main` or `all`. The default is `off`, with a `docker` backend and `workspaceAccess: "none"` when it is enabled ([sandbox/config.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/agents/sandbox/config.ts#L232-L238)). `non-main` sandboxes every session except your main DM, which is the sensible setting for group chats and shared bots. Podman and SSH backends, sandboxed browsers and per-sandbox tool policy are also supported.

### Memory

The workspace's `MEMORY.md` is the canonical root memory file ([root-memory-files.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/memory/root-memory-files.ts#L5-L8)). Indexing and search are a plugin "slot". The bundled `memory-core` plugin provides `memory_search` and `memory_get` over SQLite full-text search plus embeddings, with OpenAI as the default embedding provider. It also schedules a "dreaming" consolidation pass over the workspace's memory. `memory-lancedb` and `memory-wiki` are alternative plugins. Memory entries carry provenance, and only owner- or agent-originated entries are eligible for automatic prompt injection ([types.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/packages/memory-host-sdk/src/host/types.ts#L39-L50)).

### Heartbeat, cron and sessions

The heartbeat wakes an agent on a schedule (default every 30 minutes, [heartbeat.ts](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/auto-reply/heartbeat.ts#L26-L26)) so it can act without being messaged. Cron jobs run isolated agent turns. Session tools (`sessions_spawn`, `sessions_send`, `sessions_history` and others) let one agent start, message or inspect other sessions and subagents.

## Extending it

- **Plugins.** Each extension has an `openclaw.plugin.json` manifest and uses only `openclaw/plugin-sdk/*` contracts. Channels, providers, memory backends, speech, search and tools are all plugins, and the Docker build can select a subset with `OPENCLAW_EXTENSIONS`.
- **Skills.** About 50 bundled skills live in `skills/`, from Apple Notes to 1Password, and workspaces can add their own. A skill workshop tool lets the agent draft skills.
- **Channels.** Implement the `ChannelPlugin` adapters you need. Core owns message tools and dispatch, and the channel owns accounts, security and transport.
- **MCP and harnesses.** MCP servers are bundled into agent tool sets. External agent harnesses such as Codex or ACP agents can be selected as run candidates in place of the embedded runner.

## Running it

- **Install.** Use `curl -fsSL https://openclaw.ai/install.sh | bash` or `npm install -g openclaw`. Node 24.16+ or 26.1+ is required, because state uses `node:sqlite`. Then run `openclaw onboard --install-daemon`, which checks model access, creates the workspace and installs the Gateway service, and `openclaw dashboard` to open the Control UI.
- **Docker.** `docker-compose.yml` runs `openclaw-gateway` on 18789 (plus a bridge port and a Teams port) with `NET_RAW`/`NET_ADMIN` dropped, `no-new-privileges`, a health check, and `host.docker.internal` mapped for local model servers ([docker-compose.yml](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/docker-compose.yml#L60-L95)). A second `openclaw-cli` service runs commands against it.
- **Needs.** At least one model provider (hosted, or a local server such as Ollama, LM Studio, vLLM or llama.cpp), plus credentials for each channel you enable.

## Strengths and caveats

- **Strength: channel coverage.** No other project here reaches as many chat surfaces with as uniform a contract, including pairing, group policy and per-channel approvals.
- **Strength: mid-run steering.** Messages sent while the agent works are injected at checkpoints instead of queuing behind the run, which suits chat use.
- **Strength: local and plugin-first.** All state is in SQLite on your machine, and models, memory, channels and harnesses are swappable plugins.
- **Caveat: permissive exec defaults.** Out of the box, exec runs on the Gateway host with `full` security and no prompts, and the sandbox is off. Pairing protects DMs, but anyone you approve, and any prompt injection that reaches the model, inherits shell access until you tighten policy.
- **Caveat: scale.** Thousands of source files, many layers between a message and the loop, and fast churn make it hard to audit or patch without the project's own tooling and docs.
- **Caveat: heavy runtime.** It needs a recent Node with `node:sqlite`, worker threads for database access, and many plugins. It is a service to operate, not a script.

*Sources: code at 10334ec, verified Q&A.*

## How openclaw/openclaw answers the Open-source personal assistants questions

### How is the assistant architected? (answered)

**Agent loop and runtime.** The Gateway (`src/gateway/`) is the central control plane — an HTTP/WebSocket server that manages all sessions, tool execution, events, and channel connections. Session lifecycle is governed by `src/sessions/session-lifecycle-admission.ts` which serializes mutations and work admission via SQLite-backed store writers. When a user message arrives, the `agentRunHandler` in `src/gateway/server-methods/agent-run-handler.ts` performs preflight validation, creates an agent turn service via `createAgentTurnService`, and dispatches the run. The agent turn service coordinates with `src/agents/` — the agent run loop — which manages MCP tool bundles, memory search, and LLM invocation through the provider runtime.

**Frontend/backend split.** The backend is the Gateway (HTTP server in `src/gateway/server-http.ts`). Frontends include a Control UI (Web), a CLI (`src/cli/`), a TUI (`src/tui/`), and native companion apps. The Gateway serves the Control UI, an OpenAI-compatible API, plugin HTTP surfaces, and WebSocket upgrades. It also exposes server-method modules (`src/gateway/server-methods/`) for agent runs, session history, model listing, tool invocation, user profiles, and more.

**Main packages.** Organized as a pnpm workspace monorepo. Key source directories: `src/gateway/` (routing, approvals, chat projection), `src/agents/` (agent harness, MCP tool manager, memory prompt prepare), `src/sessions/` (lifecycle, state events, transcripts), `src/channels/` (channel plugin system), `src/llm/` and `packages/ai/` (provider transports), `packages/memory-host-sdk/` (memory engine), `src/state/` (SQLite DB schemas for agent state, config, user profiles), `src/secrets/` (credential management), `src/security/` (audit, policy). 

**Request flow.** A message arrives via a channel plugin (e.g., Discord webhook) — each channel implements `ChannelPlugin` (`src/channels/plugins/types.plugin.ts:48`). The plugin routes it into the Gateway chat runtime (`src/gateway/server-chat.ts`), which creates a session via lifecycle admission. The session runs by calling the agent turn service, which invokes an LLM through the provider transport layer (`packages/ai/src/host.ts`), executes any tool calls (MCP, filesystem, exec), and streams responses back through the channel.


Citations: [src/entry.ts:1-12](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/entry.ts#L1-L12) · [src/gateway/server-http.ts:1-70](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/server-http.ts#L1-L70) · [src/gateway/server-methods/agent-run-handler.ts:1-80](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/server-methods/agent-run-handler.ts#L1-L80) · [src/channels/plugins/types.plugin.ts:48-85](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/channels/plugins/types.plugin.ts#L48-L85) · [src/sessions/session-lifecycle-admission.ts:1-60](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/sessions/session-lifecycle-admission.ts#L1-L60) · [src/gateway/server-http-modules.ts:1-41](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/server-http-modules.ts#L1-L41)

### How are integrations (email, calendar, chat, docs) implemented? (answered)

**Supported services.** OpenClaw connects to 20+ messaging platforms through a channel plugin system. Each platform implements the `ChannelPlugin` type (`src/channels/plugins/types.plugin.ts:48`) which exposes adapters for config, auth, outbound messaging, threading, approvals, status, security, pairing, directory resolution, and more. Bundled channel IDs are generated in `src/channels/bundled-channel-ids.generated.ts`. The plugin registry (`src/channels/plugins/registry.ts`) manages discovery and loading.

**API clients vs MCP.** Channels are native plugins with full lifecycle — config setup wizards (`src/channels/plugins/setup-wizard.ts`), OAuth flows, webhook receivers, outbound message formatting, and streaming. This is separate from MCP, which is managed through the MCP tool bundle system in `src/agents/agent-bundle-mcp-*.ts`

**OAuth flow.** Provider OAuth callbacks are handled by `src/gateway/provider-browser-auth.ts` via the `PROVIDER_OAUTH_CALLBACK_PATH` route. Channel plugins have their own auth adapters (`ChannelAuthAdapter`). The Gateway supports browser-based OAuth for model providers and channel-specific auth flows.

**Token storage.** Secrets and credentials are managed by `src/secrets/` — including `resolve-store.ts`, `configure-plan.ts`, `trusted-plan-path.ts`, and per-channel persisted auth state in `src/channels/plugins/persisted-auth-state.ts`. The Gateway's `credential-planner.ts` plans credential provisioning. Token material is stored in SQLite via the secrets subsystem with encryption support (`src/storage/encryption.ts`).

**Sync vs on-demand.** Channels are event-driven: incoming messages (webhooks, socket events) trigger session creation and agent runs. The `auto-reply/` module handles responses and memory flushes. There is also a cron subsystem (`src/cron/`) for scheduled/sync operations.


Citations: [src/channels/plugins/types.plugin.ts:48-85](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/channels/plugins/types.plugin.ts#L48-L85) · [src/channels/plugins/persisted-auth-state.ts:1-1](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/channels/plugins/persisted-auth-state.ts#L1-L1) · [src/gateway/provider-browser-auth.ts:65-72](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/provider-browser-auth.ts#L65-L72) · [src/gateway/credential-planner.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/credential-planner.ts#L1-L5) · [src/secrets/resolve-store.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/secrets/resolve-store.ts#L1-L5) · [src/storage/encryption.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/storage/encryption.ts#L1-L5)

### How is memory and user context stored and retrieved? (answered)

**Storage.** Memory lives in two layers. First, markdown files in the workspace (`MEMORY.md` as the canonical root memory file — see `src/memory/root-memory-files.ts:6`). Second, a SQLite database with full-text search (FTS) and optional vector embeddings via sqlite-vec or remote embedding APIs. The core engine is in `packages/memory-host-sdk/` with separate module files for storage (`engine-storage.ts`), embeddings (`engine-embeddings.ts`), session recall (`engine-sessions.ts`), and foundation (`engine-foundation.ts`). Embedding vectors are stored in SQLite with `sqlite-vec`. The default embedding provider is OpenAI (`DEFAULT_MEMORY_EMBEDDING_PROVIDER = "openai"` in `src/agents/memory-search.ts:70`).

**What is remembered.** Session transcripts, user-authored memory files, and agent-written memory entries. Each entry carries provenance metadata (`MemoryEntryProvenance` with `originClass`, `sessionKind`, `observedAt` in `packages/memory-host-sdk/src/host/types.ts:13`). Provenance classes (`owner`, `agent`, `untrusted`, `system`) determine eligibility for automatic prompt injection — only `owner` and `agent` origins qualify (`types.ts:41`).

**Injected into prompts.** `src/agents/memory-prompt-prepare.ts:8` calls `prepareMemoryPromptSection` from `src/plugins/memory-state.ts` which builds a `PreparedMemoryPromptSection` containing ranked search results with scores, snippets, and scores for relevance. This prompt section is injected into the LLM context.

**Summarization.** The memory host SDK includes consolidation/dreaming — `packages/memory-host-sdk/src/host/curated-annotations.ts` handles curated annotations. The `memory-host-sdk/dreaming.ts` module hints at consolidation processes that summarize or compact memory over time. Memory sync (`MemorySyncParams` in `types.ts:79`) supports forced refresh of session transcripts and archive files with progress tracking.


Citations: [packages/memory-host-sdk/src/host/types.ts:1-100](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/packages/memory-host-sdk/src/host/types.ts#L1-L100) · [src/agents/memory-prompt-prepare.ts:1-32](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/agents/memory-prompt-prepare.ts#L1-L32) · [src/agents/memory-search.ts:60-80](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/agents/memory-search.ts#L60-L80) · [src/plugins/memory-state.ts:1-100](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/plugins/memory-state.ts#L1-L100) · [packages/memory-host-sdk/src/engine-storage.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/packages/memory-host-sdk/src/engine-storage.ts#L1-L5)

### How are actions on the user's behalf gated? (answered)

**Approval / human-in-the-loop.** The Gateway manages exec approvals through `src/gateway/exec-approval-manager.ts` with Web Push notifications delivered to browsers via `src/gateway/approval-web-push.ts:1`. The `agent-runtime-approval-authority.ts:12` module validates delegated authority for each agent action, checking worker turn claims and message action turn capabilities. Operator approval flows live in `src/gateway/operator-approval-*.ts` with structured scopes `src/gateway/method-scopes.ts` and `src/gateway/operator-scopes.ts`.

**Permission scopes.** The security audit subsystem (`src/security/audit.ts:1`) runs comprehensive checks on startup: it inspects dangerous config flags (`dangerous-config-flags.ts`), filesystem exec policy drift (`exec-filesystem-policy.ts`), code safety (`audit-deep-code-safety.ts`), agent roster config (`audit-agent-roster.ts`), gateway config (`audit-gateway-config.ts`), and installed plugin trust. The `dangerous-tools.ts` module flags risky tool configurations. Channel-specific security is handled by `ChannelSecurityAdapter` in `src/channels/plugins/types.plugin.ts:75`.

**Dry-run / draft modes.** The `src/channels/draft-stream-controls.ts` and `src/channels/draft-stream-loop.ts` modules handle draft streaming for channels — responses can be streamed as drafts before final delivery. The approval system in `src/gateway/approval-session-audience.ts` manages which sessions see which approvals.

**Audit trail.** The `src/audit/` directory (separate from `src/security/`) contains the structured audit logging system. Gateway security events are emitted through `src/infra/diagnostic-events.ts`. The `session-lifecycle-events.ts` and `session-state-events.ts` in sessions provide an event-sourced audit trail. The SQLite state DB includes operator approval tables managed in `src/state/openclaw-state-db-operator-approval-migration.ts`.

**Filesystem sandbox.** The sandbox system (`src/agents/sandbox/`) provides optional Docker-based isolation for agent exec operations, with configurable workspace access modes (`none`, `ro`, `rw`).

> **Editor's note.** Correction: approvals exist but are not on by default; with no exec config the effective policy is security "full" with ask "off" (exec-approvals-effective.ts, exec-approvals-config.ts), and agent sandboxing defaults to mode "off". The draft-stream modules stream reply previews and are not a dry-run mode.

Citations: [src/gateway/agent-runtime-approval-authority.ts:1-43](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/agent-runtime-approval-authority.ts#L1-L43) · [src/security/audit.ts:1-58](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/security/audit.ts#L1-L58) · [src/security/exec-filesystem-policy.ts:1-60](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/security/exec-filesystem-policy.ts#L1-L60) · [src/gateway/approval-web-push.ts:1-80](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/gateway/approval-web-push.ts#L1-L80) · [src/channels/plugins/types.plugin.ts:70-85](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/channels/plugins/types.plugin.ts#L70-L85) · [src/channels/draft-stream-controls.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/channels/draft-stream-controls.ts#L1-L5)

### How are LLM providers selected and configured? (answered)

**Supported providers.** The provider abstraction lives in `packages/ai/src/` — the `providers.ts:2` registers built-in API providers. Stream-wrappers for individual providers are in `src/llm/providers/stream-wrappers/` with adapters for Anthropic, OpenAI, Google, MiniMax, Moonshot, and ZAI. Each wrapper handles provider-specific streaming nuances: Anthropic prompt caching semantics (`anthropic-family-cache-semantics.ts`), Google thinking payloads (`google-thinking-payload.ts`), OpenAI service tier observation (`openai-service-tier-observation.ts`), reasoning effort utils (`reasoning-effort-utils.ts`). Model contracts (including Anthropic-specific ones) are defined in `packages/llm-core/src/model-contracts/`.

**Config surface.** The `ModelRegistry` interface in `src/llm/model-registry.ts:4` provides `getAll()`, `getAvailable()`, `find()`, and `hasConfiguredAuth()`. Model pickers resolve from the model catalog (`src/model-catalog/`, `packages/model-catalog-core/`). Per-agent model overrides are handled by `src/sessions/model-overrides.ts`. Provider-level config (endpoint class, provider family, API type) is described by `AiProviderRequestCapabilities` in `packages/ai/src/host.ts:11`.

**Tool-calling / structured-output usage.** Tool-calling support is inferred from the provider transport system — `packages/ai/src/host.ts` provides `AiTransportPluginHost` with `resolveProviderStream()` and stream wrapping. The agent harness in `src/agents/` manages MCP tool bundles (agent-bundle-mcp-*.ts), tool policies (`src/agents/tool-policy-match.ts`, `src/agents/agent-tools.policy.ts`), and tool error handling (`tool-error-summary.ts`). The `packages/ai/src/transports.ts` module provides low-level HTTP/stream transport.

**Local-model support.** The Docker setup includes `extra_hosts: host.docker.internal` to reach host-side LM Studio/Ollama (`docker-compose.yml:66`). The `OPENCLAW_EXTENSIONS` build arg in the `Dockerfile:11` allows including bundled local-model provider plugins. The `env-api-keys.ts` in `packages/ai/` supports API key configuration from environment variables. The provider runtime (`src/provider-runtime/operation-retry.ts`) handles retry logic.

**Provider auth.** OAuth flows for Anthropic and OpenAI are in `src/llm/utils/oauth/` with `anthropic.ts` and `openai-chatgpt.ts`. Secret credential management is handled through the secrets subsystem (`src/secrets/`).


Citations: [packages/ai/src/host.ts:1-100](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/packages/ai/src/host.ts#L1-L100) · [src/llm/providers/stream-wrappers/anthropic-family-cache-semantics.ts:1-10](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/llm/providers/stream-wrappers/anthropic-family-cache-semantics.ts#L1-L10) · [src/llm/providers/stream-wrappers/google-thinking-payload.ts:1-10](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/llm/providers/stream-wrappers/google-thinking-payload.ts#L1-L10) · [src/llm/utils/oauth/anthropic.ts:1-10](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/llm/utils/oauth/anthropic.ts#L1-L10)

### How is it deployed and self-hosted? (answered)

**Runtime dependencies.** OpenClaw requires Node.js ≥24.16.0 or ≥26.1.0 with `node:sqlite` support (`src/openclaw.mjs:35`). Bun is supported for installs and scripts but not as the primary runtime. SQLite is the core database engine — multiple databases per agent (agent-specific DB, state DB, preferences, secrets, memory with sqlite-vec for vector storage). No external database server (PostgreSQL, etc.) is required — everything runs on local SQLite files. Message queues are built into the gateway process (no Redis dependency). Docker CLI is optional for sandbox isolation.

**Docker / one-click paths.** The `Dockerfile:16` is a multi-stage build from `node:24-bookworm-slim` with pinned SHA256 digests for reproducibility. The build supports extension selection via `OPENCLAW_EXTENSIONS` build arg (`Dockerfile:11`). `docker-compose.yml` provides two services: `openclaw-gateway` (main service, port 18789) and `openclaw-cli` (command runner). Host directories for config, workspace, and auth profiles are bind-mounted. Docker supports healthcheck, restart policies, optional Docker socket mounting for sandbox, and `host.docker.internal` for local model providers. One-line install is available via curl-sh or npm install -g (`README.md:28-41`).

**Required external accounts.** LLM provider API keys (Claude/Anthropic, OpenAI/ChatGPT) are required for model access. Channel-specific accounts (Discord bot token, Slack app, Telegram bot token, WhatsApp Business API, etc.) are needed per integrated channel. Environment variables accepted include `CLAUDE_AI_SESSION_KEY`, `CLAUDE_WEB_SESSION_KEY`, `CLAUDE_WEB_COOKIE` for Claude web access, and `OPENCLAW_GATEWAY_TOKEN` for gateway auth (`docker-compose.yml:42-44`).

**Telemetry and updates.** By default the only phone-home is a daily version check. Anonymous feature statistics are opt-in. `update.checkOnStart: false` disables both (`README.md:20`). The `node-runtime-update.mjs` and `src/state/local-onboarding-state.ts` manage runtime updates. OpenTelemetry export is supported via environment variables but is entirely optional.

**Platform support.** Native installers for macOS, iOS, Android, Linux, Windows. Companion apps add voice, Canvas, camera, screen, and device-local actions.


Citations: [Dockerfile:1-60](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/Dockerfile#L1-L60) · [docker-compose.yml:1-135](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/docker-compose.yml#L1-L135) · [README.md:18-80](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/README.md#L18-L80) · [src/state/openclaw-state-db.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/state/openclaw-state-db.ts#L1-L5) · [src/state/openclaw-agent-db.ts:1-5](https://github.com/openclaw/openclaw/blob/10334ec913d7b18f32e6e1d16e9ac10bdc760534/src/state/openclaw-agent-db.ts#L1-L5)
