Files
AgapHost/adolf/openclaw.json
alvis 544637c073 Move adolf config to agap_git root (kb#65)
Relocate the OpenClaw gateway config from openai/adolf/ to adolf/ at
the repo root, since it's shared config rather than part of the
openai/ compose project's own tree. Update the docker-compose.yml
bind-mount path (./adolf/openclaw.json -> ../adolf/openclaw.json) and
comments, plus README.md references, to match. Verified: adolf
container recreated healthy with the new bind-mount source resolving
to /home/alvis/agap_git/adolf/openclaw.json, and a fresh
openclaw.json.last-good snapshot confirms the config was accepted.
2026-07-07 08:58:30 +00:00

149 lines
6.1 KiB
JSON

{
// Adolf P6 — OpenClaw gateway config for the "adolf" container.
// Lives in the adolf-state VOLUME (mounted at /home/node/.openclaw), not
// in the openai/ git repo. Secrets referenced below (${VAR}) are resolved
// from this container's process env, itself sourced from openai/.env
// (gitignored) via docker-compose.yml — never inlined here.
gateway: {
mode: "local",
auth: {
// Compose already binds "lan" (0.0.0.0) and publishes 18789/18790 to
// the host, so this is a non-loopback bind and auth is mandatory.
// Shared-secret token auth also gives the openclaw-tools bridge
// (which calls POST /tools/invoke with the same token) full
// trusted-operator scope, which is what lets gateway.tools.allow
// below actually unlock cron/nodes for it.
mode: "token",
token: "${OPENCLAW_GATEWAY_TOKEN}",
},
tools: {
// cron and nodes are owner-only and hard-denied on the HTTP
// /tools/invoke surface by default. The openclaw-tools MCP bridge
// (P5) calls that surface for cron_create/cron_list/nodes_invoke, so
// without this allow-list those tools 404 even with a valid token.
allow: ["cron", "nodes"],
},
},
// Model provider: adolf-llm (P2/P4), the Kimi-CLI OpenAI-compatible
// wrapper on :8010. Its HTTP server (openai/adolf-llm/server.js) performs
// NO api-key/Authorization validation at all -- ADOLF_KEY's value is
// functionally irrelevant to adolf-llm itself. It's still wired through
// env (not hardcoded) because OpenClaw's custom-provider schema requires
// a non-empty apiKey field and ${VAR} substitution fails closed on an
// empty/missing var.
models: {
mode: "merge",
providers: {
"adolf-llm": {
baseUrl: "http://adolf-llm:8010/v1",
apiKey: "${ADOLF_KEY}",
api: "openai-completions",
// Margin above the server.js SSE heartbeat cadence (empty-content
// keepalive delta every ~25s once idle) so the idle watchdog never
// fires on long thinking/tool/MCP phases even if a heartbeat tick
// is delayed (kb #71).
timeoutSeconds: 300,
models: [
{ id: "adolf", name: "Adolf", input: ["text", "image"] },
],
},
},
},
agents: {
defaults: {
model: "adolf-llm/adolf",
},
},
ui: {
assistant: { name: "Adolf" },
},
// Matrix channel (P6). Deliberately no accessToken/userId/password here:
// MATRIX_HOMESERVER / MATRIX_USER_ID / MATRIX_PASSWORD / MATRIX_DEVICE_NAME
// are config-key-backed env vars OpenClaw reads automatically when the
// matching config key is unset, so real creds never touch this file or
// git. Password auth (not the raw access token) mints Adolf its own fresh
// Matrix device instead of reusing the existing matrixbot (Python/nio)
// device -- see the P6 report for why that separation matters.
//
// Conservative defaults on purpose: dm "pairing" (owner must approve
// unknown senders) and groupPolicy "disabled" (no room handling yet).
// Revisit once the legacy matrixbot adapter is retired.
channels: {
matrix: {
enabled: true,
encryption: true,
dm: { policy: "allowlist", allowFrom: ["@admin:mtx.alogins.net", "@elizaveta:mtx.alogins.net"] },
groupPolicy: "disabled",
autoJoin: "always",
// mtx.alogins.net is deliberately mapped to the host-gateway (private)
// IP via extra_hosts in docker-compose.yml to dodge a hairpin-NAT dead
// end on the public route -- not an actual SSRF exposure, so opt out
// of the private-network block for this trusted, self-owned homeserver.
network: { dangerouslyAllowPrivateNetwork: true },
},
},
// MCP registry (P6) -- same servers as openai/shared-mcp.json,
// expressed in OpenClaw's own mcp.servers schema. `type: "http"` is
// OpenClaw's documented CLI-native alias for transport: "streamable-http".
mcp: {
servers: {
cognee: {
type: "http",
url: "http://cognee-mcp:8000/mcp",
},
"openclaw-tools": {
type: "http",
url: "http://openclaw-tools:8020/mcp",
},
// kanboard-mcp-adolf (kb task #58) -- standalone kanboard-mcp image
// (source /home/alvis/kanboard/mcp), second instance on :3104,
// authenticated as the Kanboard "adolf" user via its own personal API
// access token (KANBOARD_AUTH_USER=adolf in that instance's
// .env.adolf) -- a genuinely distinct credential from the "claude"
// instance on :3103 (app-wide jsonrpc token). Not part of the openai
// compose network, so reached via host.docker.internal (already
// extra_hosts-mapped for this container) rather than a service name.
kanboard: {
type: "http",
url: "http://host.docker.internal:3104/mcp",
},
// marketplace-mcp (kb task #61) -- the SAME shared marketplace-mcp
// instance Claude Code and OpenWebUI use (single service, port 3101,
// network_mode: host on the Agap host), not a second copy. It can
// place real orders on live marketplace accounts, so it's gated by a
// shared bearer token (MARKETPLACE_MCP_TOKEN in Vaultwarden / this
// container's env, injected via openai/.env -> docker-compose.yml).
// Reached via host.docker.internal, same reasoning as kanboard above.
marketplace: {
type: "http",
url: "http://host.docker.internal:3101/mcp",
headers: {
Authorization: "Bearer ${MARKETPLACE_MCP_TOKEN}",
},
},
},
},
// Cognee memory plugin (P8) — installed external plugin under
// .openclaw/extensions/cognee-memory. Activation entry is required for the
// gateway to load it at startup (discovery alone is not enough).
plugins: {
entries: {
"cognee-memory": {
enabled: true,
// External (non-bundled) plugins must opt in to conversation + prompt-injection
// hook access explicitly. before_prompt_build => allowPromptInjection;
// agent_end => allowConversationAccess.
hooks: { allowConversationAccess: true, allowPromptInjection: true },
config: {},
},
},
},
}