Public Wiki186,313View on GitHub
Want openclaw/openclaw knowledge in your AI?

src

OpenClaw is a self-hosted AI agent platform that connects LLM-powered conversational agents to multiple messaging channels (Telegram, Discord, Slack, Signal, iMessage, LINE, Matrix, Teams, Twitch, IRC, Nostr, Google Chat, Zalo, and more) through a unified gateway architecture. It provides a CLI/TUI for managing agent configuration, model selection, memory, and browser automation, with a WebSocket-based gateway protocol enabling multi-device orchestration including iOS clients via a Swift companion package (Swabble).

Tech Stack

VitestExpress.jsZod

Key Features

  • Multi-Channel Messaging
  • AI Agent Lifecycle Management
  • Auto-Reply Engine
  • WebSocket Gateway
  • Memory & Semantic Search
  • Browser Automation Tools
  • Plugin SDK & Extensions
  • CLI & TUI
  • Canvas Host & A2UI
  • Voice Call Integration
  • iOS Companion (Swabble)
  • Agent Client Protocol (ACP)

Entry Points

Start here when working with this codebase

Runtime Bootstrap
openclaw.mjs

Bootstrap and initialize the openclaw runtime by loading compiled distribution files. This is the main process entry point.

Start here when understanding how the application boots, what modules get loaded at startup, or when debugging initialization issues.

Build Configuration
tsdown.config.ts

Configure the tsdown bundler with multiple entry points for building different modules. Defines which source files become distributable bundles.

Start here when adding a new module that needs its own build entry point, or when changing how modules are bundled.

Test Configuration (Unit)
vitest.unit.config.ts

Configure unit test discovery and execution patterns for the Vitest test runner.

Start here when adding new test file patterns or configuring test-specific behavior.

Test Configuration (E2E)
vitest.e2e.config.ts

Define E2E-specific Vitest configuration with intelligent worker pool sizing.

Start here when adding end-to-end tests or modifying E2E test infrastructure.

Test Environment Setup
test/setup.ts

Test infrastructure setup providing reusable stub plugins and test environment configuration for channel plugin testing.

Start here when writing tests for channel plugins or needing to understand how test stubs are structured.

Test Global Setup
test/global-setup.ts

Initialize test environment and provide cleanup mechanism for test suite teardown.

Start here when modifying global test lifecycle hooks or environment initialization.

Test Environment Variables
test/test-env.ts

Configure process environment for test execution with proper isolation and cleanup.

Start here when tests need specific environment variables or when debugging env-related test failures.

Canvas Host Server
src/canvas-host/server.ts

HTTP/WebSocket server for serving canvas static files with live-reload, security checks, and MIME type detection.

Start here when modifying the canvas hosting layer, adding new HTTP routes to the canvas server, or debugging live-reload.

A2UI Asset Server
src/canvas-host/a2ui.ts

Serve A2UI static assets with live reload injection for HTML files.

Start here when modifying how A2UI assets are served or adding new A2UI endpoints.

ACP Session Mapper
src/acp/session-mapper.ts

Maps session labels/keys to actual session keys via gateway RPC requests. Core session resolution logic.

Start here when modifying session resolution, adding new session-related gateway requests, or debugging session mapping.

Voice Call Extension
extensions/voice-call/index.ts

Full extension example with gateway RPC endpoints (voicecall.*) and an LLM tool (voice_call). Demonstrates the extension plugin pattern.

Start here when building a new extension that needs gateway endpoints AND LLM tools. This is the most complete extension reference.

Google Chat Extension
extensions/googlechat/index.ts

Extension that handles incoming webhooks from Google Chat. Demonstrates webhook-based extension pattern.

Start here when building an extension that receives webhooks from an external service.

Nostr Extension
extensions/nostr/index.ts

Extension with HTTP handler registration for profile management. Demonstrates REST-style extension endpoints.

Start here when building an extension that exposes HTTP endpoints for external API consumption.

Zalo Extension
extensions/zalo/index.ts

Extension that registers a webhook handler for Zalo messaging platform callbacks.

Start here when building a minimal webhook-receiving extension for a new messaging platform.

Swift Protocol Generator
scripts/protocol-gen-swift.ts

Code generation tool that transpiles protocol schemas to Swift source code for the iOS companion app.

Start here when modifying protocol schemas that need Swift counterparts, or when adding new protocol types.

Swift Package Manifest
Swabble/Package.swift

Package manifest for the Swabble Swift package, orchestrating iOS/macOS project structure and dependencies.

Start here when adding Swift dependencies or modifying the iOS companion app build configuration.

Gateway Smoke Test
scripts/dev/gateway-smoke.ts

Developer script that exercises gateway WebSocket endpoints (connect, health, chat.history). Useful as a reference for gateway client usage.

Start here when understanding how to interact with the gateway WebSocket API or when writing gateway integration tests.

iOS Node E2E Script
scripts/dev/ios-node-e2e.ts

End-to-end test script for iOS node communication via gateway RPC (connect, health, node.list, node.invoke).

Start here when debugging iOS-to-node communication or understanding the node invocation RPC pattern.

How to Make Changes

Common modification patterns for this codebase

Add a new messaging platform extension (e.g., WhatsApp, WeChat)

1
extensions/

Create a new directory under extensions/ named after your platform (e.g., extensions/whatsapp/)

Pattern: Follow the directory structure of extensions/zalo/ for a minimal webhook-based extension, or extensions/voice-call/index.ts for a full-featured extension with gateway endpoints and LLM tools.

2
extensions/<platform>/index.ts

Create the main extension entry point that exports a plugin registration function. Register webhook handlers, gateway RPC methods, and/or LLM tools.

Pattern: See extensions/googlechat/index.ts for webhook handler registration pattern. See extensions/voice-call/index.ts for registering gateway RPC endpoints (voicecall.initiate, voicecall.status, etc.) and LLM tools (voice_call).

3
extensions/<platform>/index.ts

Implement message handling: inbound message parsing from the platform's webhook format, and outbound message delivery to the platform's API.

Pattern: See how src/telegram/ handles Telegram-specific message formats, or src/discord/ for Discord message processing. Each channel module has dedicated message handling logic.

4
src/channels/

If this is a first-class channel (not just an extension), register it in the channel plugin system with config and allowlist support.

Pattern: See how src/telegram/, src/discord/, src/slack/, src/signal/, src/imessage/, src/line/, and src/web/ are structured as channel modules. Each has its own directory under src/ with dedicated message handling, monitoring, and delivery logic.

5
tsdown.config.ts

Add the new extension or channel module as a build entry point so it gets bundled.

Pattern: Look at existing entry points in tsdown.config.ts and add your new module path in the same format.

6
test/setup.ts

Add test stubs for the new channel plugin if it's a first-class channel.

Pattern: Follow the stub plugin patterns already defined in test/setup.ts for channel plugin testing.

Conventions to follow:

Extensions live under extensions/ directory; first-class channels live under src/<channel>/Each extension exports a plugin registration function from its index.tsWebhook handlers are registered via the plugin system, not by manually adding HTTP routesGateway RPC methods use dot-notation namespacing (e.g., voicecall.initiate, voicecall.status)LLM tools use snake_case naming (e.g., voice_call)Message delivery is handled through the outbound delivery infrastructure in src/infra/

Add a new gateway RPC endpoint

1
src/gateway/

Define the new RPC method in the gateway protocol layer. Add the method name, parameter types, and response types.

Pattern: See how voicecall.initiate, voicecall.continue, voicecall.status etc. are defined in extensions/voice-call/index.ts. Gateway methods use dot-notation namespacing.

2
src/gateway/

Implement the RPC handler that processes the request and returns a response. Include authentication and authorization checks.

Pattern: See how scripts/dev/gateway-smoke.ts calls connect (auth), health (status check), and chat.history (data retrieval) for the client-side pattern. See extensions/voice-call/index.ts for the server-side handler registration pattern.

3
src/acp/session-mapper.ts

If the endpoint involves session management, integrate with the session mapper. Use the REQUEST pattern for gateway requests.

Pattern: See how sessions.resolve and sessions.reset are defined as gateway requests in src/acp/session-mapper.ts.

4
scripts/protocol-gen-swift.ts

If the endpoint needs to be callable from iOS, update the Swift protocol generator to emit Swift types for the new RPC method.

Pattern: Follow the existing transpilation patterns in scripts/protocol-gen-swift.ts for converting TypeScript protocol schemas to Swift source code.

5
test/gateway.multi.e2e.test.ts

Add E2E tests for the new endpoint, especially if it involves multi-instance or node communication.

Pattern: Follow the test patterns in test/gateway.multi.e2e.test.ts for gateway deployment and inter-gateway communication tests.

Conventions to follow:

RPC method names use dot-notation namespacing (e.g., namespace.action)Authentication is handled at the gateway connection level (see connect in scripts/dev/gateway-smoke.ts)Gateway requests in application code use a REQUEST pattern (see src/acp/session-mapper.ts)All new protocol types that need iOS support must be added to the Swift protocol generatorE2E tests for gateway go in test/ directory with .e2e.test.ts suffix

Add a new LLM tool (agent skill)

1
src/agents/

Define the tool in the agents module. Create the tool schema with name, description, and parameter definitions.

Pattern: See how the voice_call tool is defined in extensions/voice-call/index.ts with action-based dispatch supporting multiple operations (initiate_call, continue_call, speak_to_user, end_call, get_status). Tools use snake_case naming.

2
src/agents/

Implement the tool handler function that executes when the LLM invokes the tool. Handle all action variants and error cases.

Pattern: See extensions/voice-call/index.ts for the action-based dispatch pattern where a single tool (voice_call) handles multiple operations via an 'action' parameter.

3
src/browser/

If the tool involves browser automation, integrate with the Chrome DevTools Protocol automation layer.

Pattern: See src/browser/ for existing browser automation tools and how they use CDP for browser control.

4
src/memory/

If the tool needs to store or retrieve information, integrate with the memory and embeddings system for semantic search.

Pattern: See src/memory/ for vector embeddings storage and semantic search patterns.

Conventions to follow:

Tool names use snake_case (e.g., voice_call, not voiceCall)Tools registered in extensions use the plugin SDK registration pattern from extensions/voice-call/index.tsComplex tools use action-based dispatch with a single tool handling multiple operationsTool descriptions must be clear enough for the LLM to understand when and how to use the toolTools should handle errors gracefully and return informative error messages to the LLM

Add a new CLI command

1
src/commands/

Create a new command implementation file in the commands module. Define the command's arguments, options, and handler function.

Pattern: See existing command implementations in src/commands/ (agent, doctor, configure, status, onboarding). Each command is a separate module with its own handler.

2
src/cli/

Register the new command in the CLI command registration system. Define the command name, description, aliases, and link it to the handler.

Pattern: See src/cli/ for how existing commands are registered with argument parsing and TUI integration.

3
src/cli/

If the command needs interactive prompts, add TUI components using the interactive prompt system.

Pattern: See src/cli/ for existing TUI and interactive prompt patterns.

Conventions to follow:

Each CLI command gets its own file in src/commands/Command registration happens in src/cli/ using the argument parsing systemInteractive commands use the TUI/prompt system from src/cli/Commands that modify configuration should use the config persistence system from src/config/

Add a new HTTP endpoint to the canvas host server

1
src/canvas-host/server.ts

Add a new route handler in the canvas host server. Define the HTTP method, path pattern, and handler function.

Pattern: Follow the existing GET /{basePath}/* and HEAD /{basePath}/* patterns in src/canvas-host/server.ts. Note how it handles security checks, MIME type detection, and live-reload injection for HTML files.

2
src/canvas-host/a2ui.ts

If the endpoint serves A2UI assets, add the route in the A2UI module instead.

Pattern: See how GET /__openclaw__/a2ui/* and HEAD /__openclaw__/a2ui/* are defined in src/canvas-host/a2ui.ts with live reload injection.

3
src/canvas-host/server.test.ts

Add tests for the new endpoint covering success cases, error cases, and edge cases.

Pattern: Follow the test patterns in src/canvas-host/server.test.ts which tests GET /canvas/, GET /__openclaw__/a2ui/, and WS /canvas/ws endpoints.

Conventions to follow:

Canvas host routes use a configurable basePath prefixHTML responses get live-reload script injection when live-reload is enabledHEAD requests mirror GET but return only headersWebSocket endpoints return 426 Upgrade Required when accessed via plain HTTPSecurity checks are applied to file-serving routes to prevent directory traversal

Add a new configuration option

1
src/config/

Add the new configuration type/field to the central configuration type definitions.

Pattern: See src/config/ for existing configuration types, paths, and session definitions. Configuration follows a typed schema approach.

2
src/config/

Add default values and validation for the new config option in the config persistence layer.

Pattern: Follow the existing config persistence patterns in src/config/ for how defaults are set and configs are loaded/saved.

3
src/commands/

If the config should be user-settable, add it to the configure command.

Pattern: See the configure command implementation in src/commands/ for how config options are exposed to users.

Conventions to follow:

All configuration types are centrally defined in src/config/Config persistence handles serialization/deserializationUser-facing config options should be accessible via the configure CLI commandEnvironment variable overrides are handled in src/infra/

Add a new agent auth profile or model provider

1
src/agents/

Add the new model provider or auth profile definition in the agents module. Define the provider's API interface, authentication requirements, and model selection logic.

Pattern: See src/agents/ for existing model selection, auth profiles, and provider configurations. The agents module handles AI agent lifecycle including model selection.

2
src/config/

Add configuration types for the new provider's API keys, endpoints, and settings.

Pattern: Follow existing config type patterns in src/config/ for provider-specific settings.

3
test/provider-timeout.e2e.test.ts

Add timeout and fallback tests for the new provider.

Pattern: Follow the test patterns in test/provider-timeout.e2e.test.ts which tests provider timeout fallback functionality.

4
scripts/bench-model.ts

Add the new provider to the benchmarking utility so it can be performance-tested.

Pattern: See scripts/bench-model.ts for how LLM API response times are benchmarked across providers.

Conventions to follow:

Model providers are managed in src/agents/ with auth profilesProvider timeout and fallback behavior must be testedAPI usage tracking should be supported (see scripts/debug-claude-usage.ts for the Anthropic pattern)Benchmarking support via scripts/bench-model.ts is expected for new providers

Add auto-reply logic or modify message processing pipeline

1
src/auto-reply/

Modify the auto-reply orchestration engine. This handles command detection, reply queuing, and streaming.

Pattern: See src/auto-reply/ for the message auto-reply orchestration pipeline including command detection and reply queuing.

2
src/channels/

If the change affects how messages are received from channels, modify the channel plugin system's messaging abstractions.

Pattern: See src/channels/ for the channel plugin system and messaging platform abstractions.

3
src/web/

If the change affects web channel auto-reply specifically, modify the web channel's inbound processing.

Pattern: See src/web/ for web-based messaging channel inbound processing and auto-reply integration.

4
src/infra/

If the change affects outbound message delivery, modify the outbound delivery infrastructure.

Pattern: See src/infra/ for outbound delivery and networking infrastructure.

Conventions to follow:

Auto-reply orchestration is centralized in src/auto-reply/Command detection happens before reply generationReply queuing ensures ordered deliveryStreaming responses are supported through the auto-reply engineChannel-specific message formatting is handled by each channel module, not the auto-reply engine

Coding Conventions

Standards and patterns used in this codebase

Project Structure

Organize source code into domain-specific directories under src/, with each directory representing a bounded context (e.g., agents, gateway, channels, memory). Extensions and third-party integrations live in a separate top-level extensions/ directory.

src/agents/, src/gateway/, src/channels/, src/telegram/, extensions/
openclaw.mjstsdown.config.ts
Build & Bundling

Use tsdown (tsdown.config.ts) as the build tool with multiple entry points targeting Node.js output. The bootstrap entry point (openclaw.mjs) loads the compiled distribution dynamically.

openclaw.mjs imports and initializes from the compiled dist output defined by tsdown.config.ts
openclaw.mjstsdown.config.ts
Testing Strategy

Maintain separate Vitest configurations for unit tests and end-to-end tests. A base vitest.config.ts defines shared settings (coverage thresholds, path aliases), while vitest.unit.config.ts and vitest.e2e.config.ts extend it with specific overrides. E2E tests use environment-aware worker settings.

vitest.unit.config.ts extends base config; vitest.e2e.config.ts adds environment-aware workers
vitest.config.tsvitest.unit.config.tsvitest.e2e.config.ts
Testing Infrastructure

Use dedicated test setup files: global-setup.ts for environment initialization/cleanup, setup.ts for creating stub channel plugins, and test-env.ts for isolating or using live environment variables. E2E test files follow the naming pattern *.e2e.test.ts.

test/gateway.multi.e2e.test.ts, test/provider-timeout.e2e.test.ts
test/global-setup.tstest/setup.tstest/test-env.tstest/gateway.multi.e2e.test.ts
Channel Plugin Architecture

Messaging platforms are implemented as channel plugins with a shared abstraction layer (src/channels) for config, allowlists, and messaging. Each platform (Telegram, Discord, Slack, Signal, iMessage, LINE, Web) has its own src/ directory. Third-party platforms use the extensions/ directory and plugin SDK (src/plugins).

src/channels/ defines the plugin system; src/telegram/, src/discord/, src/slack/ implement specific channels; extensions/ holds Matrix, Teams, Twitch, IRC
test/setup.ts
Entry Point Pattern

Use a lightweight .mjs bootstrap file as the main entry point that dynamically loads the compiled distribution, keeping the entry minimal and decoupled from the build output.

openclaw.mjs initializes the runtime and loads the compiled distribution entry
openclaw.mjs
TypeScript & Language

The project is TypeScript-first with path aliases configured in vitest for module resolution. Swift is used for a companion native package (Swabble) managed via Swift Package Manager.

Path aliases defined in vitest.config.ts; Swabble/Package.swift for native Swift targets
vitest.config.tsSwabble/Package.swift
File Naming

Use kebab-case for TypeScript source files and test files. Test files use the suffix .test.ts for unit tests and .e2e.test.ts for end-to-end tests. Configuration files use the pattern tool.config.ts (e.g., vitest.config.ts, tsdown.config.ts).

provider-timeout.e2e.test.ts, gateway.multi.e2e.test.ts, bench-model.ts
test/provider-timeout.e2e.test.tstest/gateway.multi.e2e.test.tsscripts/bench-model.ts