Concepts
On this page
Moltlazy has two systems that work together: the Config Module (startup-time) and the SDK Module (runtime).
Config Module (startup)
The Config Module runs once at container startup via moltlazy patch. It generates an immutable moltlazy.json file and injects a $include directive into openclaw.json.
flowchart LR
ENV["Env vars\n(secrets)"]
FLAGS["Feature flags\n(MOLTLAZY_FEATURE_FLAGS)"]
ENV --> PATCH["moltlazy patch"]
FLAGS --> PATCH
PATCH --> JSON["/home/openclaw/.openclaw/moltlazy.json"]
PATCH --> INCLUDE["$include injection\ninto openclaw.json"]
INCLUDE --> GW["OpenClaw loads\nboth files"]
JSON --> GWHow it works
start-openclaw.shrunsmoltlazy patchmoltlazy patchreads env vars andMOLTLAZY_FEATURE_FLAGSJSON- Assembles all mandatory config sections (gateway, session, tools, logging)
- Assembles feature-gated sections (agents, channels, skills, memory, plugins)
- Writes
/home/openclaw/.openclaw/moltlazy.json(regenerated from scratch each startup) - Injects
$include: "./moltlazy.json"intoopenclaw.jsonif not present - OpenClaw starts, loads both files, merges them natively
Always-on config modules
These modules always run regardless of feature flags:
| Module | Config section | Purpose |
|---|---|---|
config/gateway | gateway.* | Auth mode, trustedProxies, controlUi |
config/session | session.dmScope | Per-channel-peer session isolation |
config/tools | tools.toolSearch | Enable tool search in “tools” mode |
config/logging | logging.* | Production logging with redaction |
Feature-gated config modules
These modules only run when their corresponding flag is enabled:
| Module | Flag | Config section |
|---|---|---|
agents/ | (always-on) | agents.defaults, agents.entries |
config/channels | channelsTelegram, channelsDiscord, channelsSlack | channels.* |
config/memory | knowledgeGraph | memory.*, plugins.* |
config/plugins | unifiedBilling | plugins.* |
config/microsoftGraph | microsoftGraph | plugins.entries.microsoft-graph |
Secrets are never in moltlazy.json
Tokens, API keys, and bot credentials are excluded from moltlazy.json via an IGNORE_KEYS filter. They come from environment variables that the gateway reads directly.
SDK Module (runtime)
The SDK Module provides a typed RPC client for interacting with a running gateway via the Admin HTTP RPC API at POST /api/v1/admin/rpc. No filesystem writes — pure typed RPC calls.
RPC Client
RpcClient is the low-level HTTP client that handles authentication, retries, and timeouts for all Admin HTTP RPC calls.
sequenceDiagram
participant App as Your Code
participant Client as RpcClient
participant GW as OpenClaw Gateway
App->>Client: client.config.get()
Client->>GW: POST /api/v1/admin/rpc<br/>Authorization: Bearer<br/>{"method": "config.get", "id": "moltlazy-..."}
alt Success
GW-->>Client: {"id": "...", "ok": true, "payload": {...}}
Client-->>App: RpcSuccess
else Error
GW-->>Client: {"id": "...", "ok": false, "error": {...}}
Client-->>App: RpcError
end
Key properties:
- Auth — Bearer token sent in the
Authorizationheader, never in request body - Retry — Automatic retry on HTTP 503 with configurable
maxRetriesandretryDelay - Timeout — Configurable request timeout (default: 10 seconds)
- Request IDs — Auto-generated with
moltlazy-prefix for tracing
Domain modules
createClient() returns a MoltlazyClient that attaches 7 domain modules to the RpcClient:
const client = createClient({ baseUrl: '...', token: '...' });
client.config; // ConfigModule — config.get, config.set, config.apply
client.agents; // AgentsModule — agents.list, agents.create, agents.update, agents.delete
client.channels; // ChannelsModule — channels.status, channels.start, channels.stop
client.devices; // DevicesModule — device.pair.list, device.pair.approve, device.pair.reject, device.pair.remove
client.cron; // CronModule — cron.list, cron.get, cron.add, cron.update, cron.remove, cron.run
client.models; // ModelsModule — models.list, models.authStatus
client.gateway; // GatewayModule — health, status, gateway.restart.request, logs.tail
Each module method maps 1:1 to an Admin HTTP RPC method. Modules are thin wrappers that:
- Build the
paramsobject from typed arguments - Call
client.call(method, params) - Return the typed
RpcResponse<T>
Config methods
The config module exposes three methods matching the upstream protocol contract:
| Method | Upstream RPC | Params |
|---|---|---|
config.get() | config.get | none |
config.set() | config.set | { raw: string, baseHash?: string } |
config.apply() | config.apply | { raw: string, baseHash?: string } |
raw is a serialised JSON string of the config fragment to apply. baseHash is an optional optimistic concurrency token.
Response shape
Every call returns RpcResponse<T>, a discriminated union:
type RpcResponse<T> =
| { ok: true; id: string; payload: T }
| {
ok: false;
id: string;
error: {
code: number;
message: string;
details?: unknown;
retryable?: boolean;
retryAfterMs?: number;
};
};
Check result.ok before accessing result.payload.