9 Commits
master ... main

Author SHA1 Message Date
4e67186c08 docs: A2A-3 — task schema, field-by-field KB-literal mapping
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Stale / stale (push) Has been cancelled
Stale / backfill-stale-closures (push) Has been cancelled
Stale / lock-closed-issues (push) Has been cancelled
OpenClaw Scheduled Live And E2E Checks / live_and_openwebui_checks (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
QA-Lab - All Lanes / Authorize workflow actor (push) Has been cancelled
QA-Lab - All Lanes / Validate selected ref (push) Has been cancelled
QA-Lab - All Lanes / Run QA Lab mock parity lane (push) Has been cancelled
QA-Lab - All Lanes / Run live runtime token-efficiency lane (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-cli) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-deep) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-smoke) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (media) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (transport) (push) Has been cancelled
QA-Lab - All Lanes / Run Telegram live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run Discord live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run WhatsApp live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run Slack live QA lane with Convex leases (push) Has been cancelled
OpenClaw Performance / Kova live OpenAI GPT 5.5 agent turn (push) Has been cancelled
OpenClaw Performance / Kova mock provider performance (push) Has been cancelled
OpenClaw Performance / Kova mock provider deep profile (push) Has been cancelled
CodeQL Critical Quality / Select Critical Quality shards (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (core-auth-secrets) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (config-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (gateway-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (channel-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (network-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (agent-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (mcp-process-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (memory-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (session-diagnostics-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-reply-runtime) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (provider-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (ui-control-plane) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (web-media-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-package-contract) (push) Has been cancelled
CodeQL Android Critical Security / Critical Security (android) (push) Has been cancelled
CodeQL macOS Critical Security / Critical Security (macOS) (push) Has been cancelled
Adds §6a documenting how each Task field (id, intent, required tier,
target queue, priority, status, context refs, result ref, submitter,
deadline) is actually represented in Kanboard today (columns, tags,
score, priority, comments, native fields), per the already-agreed
KB-literal decision (§10.2). Ground truth taken from kb-claim and
kb_worker.py, not written in the abstract.

Kanboard #135
2026-07-22 11:06:34 +00:00
df2071d5ee docs: v2.1 — no metered API by default; embedding-based routing
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Stale / stale (push) Has been cancelled
Stale / backfill-stale-closures (push) Has been cancelled
Stale / lock-closed-issues (push) Has been cancelled
OpenClaw Scheduled Live And E2E Checks / live_and_openwebui_checks (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
QA-Lab - All Lanes / Run Telegram live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run Discord live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run WhatsApp live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run Slack live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Authorize workflow actor (push) Has been cancelled
QA-Lab - All Lanes / Validate selected ref (push) Has been cancelled
QA-Lab - All Lanes / Run QA Lab mock parity lane (push) Has been cancelled
QA-Lab - All Lanes / Run live runtime token-efficiency lane (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-cli) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-deep) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-smoke) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (media) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (transport) (push) Has been cancelled
OpenClaw Performance / Kova live OpenAI GPT 5.5 agent turn (push) Has been cancelled
OpenClaw Performance / Kova mock provider performance (push) Has been cancelled
OpenClaw Performance / Kova mock provider deep profile (push) Has been cancelled
CodeQL Critical Quality / Select Critical Quality shards (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (core-auth-secrets) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (config-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (gateway-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (channel-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (network-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (agent-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (mcp-process-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (memory-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (session-diagnostics-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-reply-runtime) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (provider-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (ui-control-plane) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (web-media-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-package-contract) (push) Has been cancelled
CodeQL Android Critical Security / Critical Security (android) (push) Has been cancelled
alvis: the workflow is scoped to Claude Code + Kimi wrapper + local GPU
embedder + small local model. We do not pay per-token for API usage.

- NEW §3a cost model: the binding constraints are QUOTA and VRAM, not
  money. The "cheap tier" is the LOCAL small model, not a cheap paid
  one; paid deployments are opt-in fallback per virtual key and never
  route implicitly. Claude Code is a flat-subscription runtime, not a
  metered API.
- Routing classification is EMBEDDING-based on the already-resident
  local bge-m3 (LiteLLM Auto Router / semantic-router takes a
  configurable embedding_model) — no classifier LLM, no API spend.
  Keep a heuristic fallback: Auto Router v2 is a week old with an open
  embedding bug report.
- Budget governor reframed: arbitrates quota and GPU, not spend.
- GPU residency section renumbered 3b.
- Decision log 23-25 (incl. Hindsight caller-supplied cognition mode as
  an optional extra path, default API/queue path unchanged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-21 09:02:24 +00:00
1db3dd1b34 docs: v2.1 fix — cron catch-up leaves the keeper; faults are incidents
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
alvis: a missed cron is an operational fault, not a task-lifecycle event,
and re-firing it would make the keeper a trigger. Removed cron catch-up
from fabric-keeper duties entirely.

- Keeper is now strictly janitorial: neither assigns NOR triggers work
  (lease sweeps, deadlines, dead-letter, digests, metrics only).
- Schedules that must not be missed are monitored in Zabbix like any
  other infra fault.
- NEW §6d: faults are incidents, handled PER PROBLEM CLASS by a future
  ops-agent (watches Zabbix, applies known mitigation or files a task
  with the incident as context) — never a blanket catch-up policy, since
  a missed briefing / backup / consolidation want different responses.
- Decision log entry 22.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-21 08:03:27 +00:00
714a9ca785 docs: agent platform v2.1 — hardening review (agreed 2026-07-21)
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Fixes two v2 design bugs and closes the review gaps alvis accepted:
- Transport rule: sync = direct A2A RPC (journaled to KB); async = KB
  polling; polling never on a sync path.
- GPU residency: local a(t)=f(VRAM), never-evict set, pre-load checks.
- NEW §5b Humans (plural): per-human private banks + shared household
  bank, interlocutor-scoped recall, cross-human leakage forbidden;
  human inbox design (priority-routed notifications, digest, no
  default-approve, vacation mode).
- NEW §6b fabric-keeper: scheduling decomposed (triggering/dispatch/
  admission/time); the keeper janitor owns leases, deadlines, cron
  catch-up, dead-letter, digests.
- NEW §6c KB as tier-0 (backup/monitoring/degraded mode).
- Completion vs verification: Done column = unverified, closed task =
  verified, producer never closes own task.
- A2A auth mandatory (LAN untrusted: VPN peers); fabric hygiene
  (creation quotas, ancestry cap, dead-letter); personas/Cards in git;
  golden-set eval gate on backbone swaps.
- Decision log entries 12-21.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-21 07:34:19 +00:00
7be30c7174 docs: agent platform design v2 — the agent algebra (agreed 2026-07-21)
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Unified redesign: two axioms (everything that can receive work is an Agent
with a Card and availability function; one verb submit(task, target)) from
which the v1 rules follow as theorems — per-model queues (scarcity), quota
parking (a(t)=0), reflect-as-task, backbone swap as constraint edit, the
Claude Code loop as an ordinary consumer, human-as-agent (KB waiting column
= his inbox).

Adds what v1 lacked: trust classes (vault=trusted only), prompt-injection
taint boundary, always-ask escalation, global budget governor, per-task
workspace-lease sandboxing with PR-only merges, KB-literal fabric decision,
LiteLLM Auto Router v2 for sync routing, thin KB-polling workers as the
executor, Langfuse kept as observability, real A2A protocol adoption.
Includes decision log from alvis.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-21 07:13:54 +00:00
2499218c18 docs: add Agap agent platform design (A2A, per-model queues, agents)
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CodeQL Critical Quality / Select Critical Quality shards (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (core-auth-secrets) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (config-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (gateway-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (channel-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (network-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (agent-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (mcp-process-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (memory-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (session-diagnostics-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-reply-runtime) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (provider-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (ui-control-plane) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (web-media-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-package-contract) (push) Has been cancelled
CodeQL Android Critical Security / Critical Security (android) (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Overall design for moving from a single tool-heavy Adolf to a multi-agent
platform: agents as personas (prompt+memory+tools) that can swap backbones,
models as the scarce queued resource (per-model queues with always-on /
quota-gated / cost-gated / on-demand lifecycles), and A2A patterns
(agent cards, task lifecycle, context-by-reference) to move work between them.

Covers the required cases: Hindsight reflect as an async queued task to the
large model, the Claude Code loop as just another queue-consuming agent, why
queues are keyed by model rather than agent, and how the lab grows to remote
llama / extra GPUs / research agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-21 06:03:29 +00:00
c69d047f3c Dockerfile: install chromium for the OpenClaw browser plugin
The node:24-bookworm-slim runtime ships no browser, so the `browser` plugin
fails with "No supported browser found". Add Debian's real `chromium` (not
snap) to the runtime apt layer; its shared libs (libnss3, libgbm1, ...) come
in as Depends. Adolf fork addition for authenticated web access.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
2026-07-16 14:40:12 +00:00
6308471b2a fix(docker): ship packages/ai so gateway resolves @openclaw/ai at runtime
Some checks failed
CI / security-fast (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Stale / stale (push) Has been cancelled
Stale / backfill-stale-closures (push) Has been cancelled
Stale / lock-closed-issues (push) Has been cancelled
OpenClaw Scheduled Live And E2E Checks / live_and_openwebui_checks (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (transport) (push) Has been cancelled
QA-Lab - All Lanes / Run Telegram live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run Discord live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run WhatsApp live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Run Slack live QA lane with Convex leases (push) Has been cancelled
QA-Lab - All Lanes / Authorize workflow actor (push) Has been cancelled
QA-Lab - All Lanes / Validate selected ref (push) Has been cancelled
QA-Lab - All Lanes / Run QA Lab mock parity lane (push) Has been cancelled
QA-Lab - All Lanes / Run live runtime token-efficiency lane (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-cli) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-deep) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (e2ee-smoke) (push) Has been cancelled
QA-Lab - All Lanes / Run Matrix live QA lane (media) (push) Has been cancelled
OpenClaw Performance / Kova live OpenAI GPT 5.5 agent turn (push) Has been cancelled
OpenClaw Performance / Kova mock provider performance (push) Has been cancelled
OpenClaw Performance / Kova mock provider deep profile (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (network-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (agent-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (mcp-process-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (memory-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (session-diagnostics-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-reply-runtime) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (provider-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (ui-control-plane) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (web-media-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (plugin-sdk-package-contract) (push) Has been cancelled
CodeQL Critical Quality / Select Critical Quality shards (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (core-auth-secrets) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (config-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (gateway-runtime-boundary) (push) Has been cancelled
CodeQL Critical Quality / Critical Quality (channel-runtime-boundary) (push) Has been cancelled
CodeQL Android Critical Security / Critical Security (android) (push) Has been cancelled
CodeQL macOS Critical Security / Critical Security (macOS) (push) Has been cancelled
The runtime stage copied node_modules (with the @openclaw/ai workspace
symlink -> ../../packages/ai) but not packages/ai itself, leaving a dangling
symlink. Gateway boot failed: 'Cannot find package @openclaw/ai'. Copy the
built lib into the runtime image. Verified: gateway now boots, loads config,
and stays listening with --allow-unconfigured.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:49:46 +00:00
f214eb2fae docs: add P0 spike findings for the 5 open architecture gates
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
Resolves ARCHITECTURE.md §4: confirms kimi-code (not kimi-cli) is
already the current upstream package with working -r/-p/stream-json
and portable CLI-home auth; documents OpenClaw's chat_id metadata
block as the session-identity mechanism; verifies headless image
input via the built-in ReadMediaFile tool; recommends Kuzu over
Neo4j for Cognee's graph store; and recommends LiteLLM over the
Kimi CLI for cognee's batch-cognify LLM backend based on measured
per-call latency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:43:54 +00:00
3 changed files with 676 additions and 1 deletions

483
DESIGN-a2a-agents.md Normal file
View File

@@ -0,0 +1,483 @@
# DESIGN — Agap Agent Platform v2.1: the agent algebra
Status: **v2.1, agreed with alvis 2026-07-21** (v2 `7be30c71` + hardening review)
Owner: alvis · Written with Claude
One design, two axioms, one verb. Everything alvis asked for — per-model queues,
quota parking, Hindsight reflect as an async task, the Claude Code loop as a task
puller, semantic/tier/direct routing — falls out as a special case rather than a
rule. This document is the reference; the Kanboard A2A tasks implement it.
---
## 0. Glossary
- **Task plane / "the fabric"** — the task-passing substrate connecting all
agents: **Kanboard** (the durable task store and queue — for humans *and*
agents) + **A2A protocol semantics** (submit/status/result, Agent Cards,
context-by-reference) + the **conventions** on top (claim/lease, priorities,
parking, trust-class routing). Not a deployable component; the collective name,
the way "the network" names cables + IP + routing.
- **Card** — an agent's self-description: capabilities, tier, cost class, trust
class, availability. Maps 1:1 to an A2A Agent Card.
- **Backbone** — the concrete LLM an agent currently uses for reasoning.
- **Context ref** — a pointer (Hindsight bank id, git ref, KB task id, file
path) passed *instead of* pasted content.
- **fabric-keeper** — the janitor daemon owning time semantics (§6b): lease
sweeps, deadlines, dead-letter, inbox digests. It never assigns work and
never triggers work.
## 1. Why
Observed on the live stack:
- **Duplicated LLM spend** — an Adolf turn costs a ~32.8K-token reply call plus a
~22.8K-token background Hindsight extraction; ~425 tokens are the conversation.
- **Tool bloat** — one Adolf carries ~84 MCP tool schemas + ~26 built-in tools
every turn (~22K tokens), relevant or not.
- **Quota cliffs** — Kimi's flat window (~60 msgs/5h, ~300/wk measured) makes
Adolf go dark with no degradation path and no way to park work.
- **Hardcoded background cognition** — Hindsight reflect/consolidation call a
fixed model directly: no scheduling, no priority, no quota awareness.
- **No growth path** — the ambition is autonomous research agents, remote llama
nodes, more GPUs, more agents.
## 2. The algebra
### Axiom 1 — everything that can receive work is an Agent
An agent is `(identity, Card, Policy, State)`. The Card advertises capabilities,
**tier** (model strength it offers or needs), **cost class**, **trust class**
(§5), and an **availability function a(t)**. Special cases:
| Agent | Persona | Memory | Card highlights |
|---|---|---|---|
| LLM endpoint (`kimi`, `gemma3:4b`, …) | trivial (identity) | none | tier, cost, quota-shaped a(t) |
| **Adolf** | proactive auditor (SOUL.md) | Hindsight bank `adolf` | trusted; scoped core tools |
| **claude-coder** (Claude Code loop) | implementer | session + repo | trusted; pulls complex coding tasks |
| **Torgash** | marketplace analyst | own bank | sandboxed; marketplace tools only |
| **researcher** | autonomous researcher | own bank | sandboxed/untrusted inputs; own KB project |
| router | delegator | none | resolves constraints → agents |
| **alvis (the human)** | — | — | trust=human; a(t)=waking hours; **inbox = KB "waiting-on-me"** |
The human being an agent is not a metaphor: approval gates, escalations and
decisions are ordinary tasks submitted to his inbox. The KB column he already
processes *is* that inbox.
### Axiom 2 — one verb
```
submit(task, target) -> taskRef # await(taskRef) optional => sync
task = (intent, context-refs, constraints, priority, deadline, provenance)
target ∈ { agent-id # direct: “this backbone / this specialist”
| constraint-set # tier/capability: “any large model with tools”
| auto } # router decides by availability/quota/complexity
```
Context travels **by reference, never by value** — the single most important
efficiency rule for inter-agent communication (A2A context-passing practice).
`sync` vs `async` is not a second mechanism: sync = submit + await.
**Transport rule.** Sync and async share the algebra but not the transport:
**sync goes direct** — an A2A `message/send` RPC straight to the target agent's
endpoint, journaled to KB afterwards; **async/durable goes through KB** and is
drained by polling workers. KB polling must never sit on a sync path — a sync
call may not inherit poll-interval latency.
### Completion vs verification
KB convention (native semantics, no new machinery): the **Done column =
unverified completion** — the worker/agent finished and self-reported. **Closing
the task = verified completion.** The producer never closes its own task; the
submitter, a human, or (later) a reviewer-agent closes after checking the
task's acceptance criteria. Lifecycle: … → done (unverified) → closed
(verified). For code, the PR review is the verification; closing follows merge.
### Theorems — the old rules become consequences
1. **"Queues are per model, not per agent."** Every agent has an inbox, but
queues *accumulate* only where a(t) or throughput binds — at scarce agents:
model-agents and the human. Persona agents transform-and-delegate, so their
inboxes stay near-empty. The v1 rule is the scarcity special case.
2. **Quota lifecycles are shapes of a(t).** always-on: a(t)=1. quota-gated
(Kimi): a(t)=0 when the window is spent — the queue **parks**, nothing fails,
drains on reset. cost-gated: a(t)=0 past budget. on-demand (remote llama):
a(t)=0 until woken. Four lifecycles, one function.
**Note on "cost":** in this lab the binding constraint is **quota and VRAM,
not money** — see §3a. The cost-gated shape exists for the optional paid
fallback only; it is not the normal case.
3. **Hindsight reflect is just a submit** — `{intent: reflect, refs: bank+query,
constraints: tier≥large}`, async. Same for consolidation (low priority).
4. **Backbone swap is a constraint edit.** Persona agents name constraints, not
endpoints; the backbone resolves per-submit. Adolf-on-Kimi today,
Adolf-on-local tomorrow — no code change.
5. **The Claude Code loop is an ordinary consumer** — an agent whose policy is
"pull complex coding tasks from the fabric". It was never special.
6. **For free:** escalation = re-submit with wider constraints (gated by policy,
§5); approval = submit(…, target=alvis); proactivity/cron = delayed
self-submission; the researcher = a low-priority self-submitting loop.
### Granularity rule
A **Task** is a durable work item with a lifecycle worth auditing. A single LLM
completion inside an agent's turn is **not** a Task — it is an implementation
detail, observable in Langfuse, invisible to Kanboard. This keeps the KB-literal
fabric free of micro-churn by construction.
## 3. Planes
```
┌─ Task plane (“the fabric”) ─────────────────────────────────────────┐
│ Kanboard = the queue + audit + human inboxes (KB-LITERAL: no │
│ separate store). A2A semantics; claim/lease; priorities; parking. │
└─────────────────────────────────────────────────────────────────────┘
┌─ Agent plane ───────────────────────────────────────────────────────┐
│ Registry of Cards (persona, memory bank, tool scope, trust class, │
│ preferred tier, current backbone). Runtimes: OpenClaw (Adolf + │
│ specialists), Claude Code CLI, thin workers. │
└─────────────────────────────────────────────────────────────────────┘
┌─ Model plane ───────────────────────────────────────────────────────┐
│ LiteLLM gateway (:4000). Auto Router v2 (2026-07-14) does the SYNC │
│ routing natively: pinned model | tier pools | complexity/semantic │
│ auto-routing (SIMPLE<MEDIUM<COMPLEX<REASONING), plus virtual keys, │
│ budgets, 429-fallback. alvis's three routing modes map 1:1: │
│ specific backbone → pinned model_name │
│ “tier” routing → tier pool │
│ automatic router → auto_router/complexity_router │
│ Classification is EMBEDDING-based on the local bge-m3 (semantic- │
│ router): no classifier LLM, no API spend (§3a). │
│ Deployments: kimi (wrapper) | local small model | local embedder; │
│ metered/paid = opt-in fallback only, never implicit. │
│ The fabric owns everything LiteLLM cannot: ASYNC queueing, parking │
│ across quota windows, leases, cross-agent quota/GPU arbitration. │
└─────────────────────────────────────────────────────────────────────┘
┌─ Context stores ────────────────────────────────────────────────────┐
│ Hindsight banks (per-agent memory) · gitea (code, docs, this file) │
│ · KB task bodies · files. Tasks point here; payloads never inline. │
└─────────────────────────────────────────────────────────────────────┘
```
### 3a. Cost model — no metered API by default
**Hard scope constraint (alvis):** the workflow is **Claude Code + the Kimi
wrapper + a local GPU embedder + a small weak local model**. We do **not** pay
per-token for API usage. Consequences that shape the design:
| Resource | Nature | Constraint |
|---|---|---|
| **Claude Code** | flat subscription; a *runtime*, not a metered API | the `claude-coder` agent's capacity |
| **Kimi** (via adolf-llm / hindsight-llm wrappers) | flat subscription, windowed | ~60 msgs/5h, ~300/wk — quota, not money |
| **local small model** (ollama) | free | GPU/VRAM contention (§3b) |
| **local embedder** (bge-m3) | free, already resident | never-evict |
| paid API (Haiku/Flash/…) | metered | **optional fallback only — disabled by default, explicitly opt-in** |
So the "cheap tier" is the **local small model**, not a cheap paid model. The
budget governor (§5) therefore arbitrates **quota and GPU**, not spend. Any
paid deployment in the LiteLLM config must be explicitly enabled per agent via
its virtual key; nothing routes to a metered model implicitly.
**Routing classification is embedding-based, not model-based.** LiteLLM's Auto
Router (built on `semantic-router`) takes a configurable `embedding_model` +
`match_threshold`, so complexity/semantic classification runs on the **local
bge-m3** we already keep resident — no classifier LLM call, no API spend, ~zero
marginal cost. (Auto Router v2 is new as of 2026-07-14 and has an open
embedding-related bug report: verify hands-on and keep a heuristic
keyword/length fallback for the classifier.)
### 3b. GPU residency — a local model's a(t) is not 1
Local "free" models contend for VRAM with interactive components (measured on
the 8 GB GTX 1070: bge-m3 + gemma3:4b + tei-reranker ≈ 6.2 GB; loading anything
bigger evicts the reranker and silently regresses recall latency). So a local
model's availability is **a(t) = f(VRAM headroom)**, and the model registry
carries a **residency policy**: a never-evict set (embedder, reranker —
interactive-critical), allowed co-residency groups, and a pre-load check every
worker must pass before pulling a model onto a GPU. With more GPUs this becomes
a placement problem — same policy, more slots.
### Personas and Cards are code
SOUL.md files and agent Cards live **in git** and are deployed to runtimes —
never edited live in volumes. "Who changed Adolf's soul" must be a `git log`
answer. (The current SOUL.md in the adolf-state volume is migration debt.)
### Eval gate on backbone/routing changes
Backbone swap being "one constraint edit" is quality-blind. Each agent keeps a
**golden set** (1020 canonical exchanges); any backbone or routing change is
shadow-replayed against it and compared (Langfuse datasets/evals) before taking
effect. The algebra's flexibility must not become a silent-degradation machine.
## 4. A2A: the protocol, adopted now
The algebra maps 1:1 onto A2A v1.0 (Jan 2026), which is why we implement the
real protocol immediately rather than "patterns first":
| Algebra | A2A |
|---|---|
| Card | Agent Card (`/.well-known/agent.json`) |
| submit / await | `message/send` (sync-ish) / `tasks/get` (async) |
| task lifecycle | submitted → working → input-required → completed/failed/canceled |
| notify | push notifications |
Implementation: JSON-RPC 2.0 over HTTP on the LAN; each runtime (OpenClaw,
Claude loop, workers) exposes/consumes A2A; Kanboard remains the durable state
behind the endpoints. Scalability/extensibility later (remote nodes, third-party
agents) then needs zero redesign.
**Auth is mandatory on every A2A surface.** The LAN is **not trusted** — the
xray/3x-ui VPN terminates other people's peers on it. No unauthenticated
JSON-RPC listener, ever: shared tokens minimum, mTLS preferred.
## 5. Trust & sandboxing
**Trust classes** (on every Card):
```
human > trusted > sandboxed > untrusted
```
- **trusted** (Adolf, claude-coder): vault access **yes**; outward actions per
existing ask-first rules.
- **sandboxed** (Torgash, researcher): **no vault**, no outward sends; scoped
MCP allowlist; KB access **project-scoped** (researcher gets its own KB
project(s)).
- **untrusted** = anything ingesting the open web: its *outputs* are tainted.
**Taint / prompt-injection boundary:** tainted output may be written only to the
agent's own bank/notes/project. Promotion into a trusted agent's memory or into
any action requires a gate (initially: a task to alvis's inbox; later possibly a
reviewer-agent).
**Escalation policy (initial): always-ask.** A task that fails on its tier is
not silently retried on a bigger model; it becomes a decision task in alvis's
inbox. Revisit once behavior is observed (debugging phase by design).
**Sandboxed coding — workspace lease:** per **task**, not per agent:
`workspaces/<agent>/<task-id>/` = ephemeral gitea clone + branch; execution
inside a container (no vault creds by default, network allowlist, resource
caps); merge **only via PR** to gitea; autonomous agents never push to main.
Reviewer = human, or later a reviewer-agent (just another persona).
**Global budget governor:** near the end of a quota window, interactive agents
(Adolf) outrank background ones (researcher, consolidation) — arbitration lives
in the fabric (priorities + a small governor rule), not in LiteLLM.
**Fabric hygiene (runaway protection):** agents submit tasks that cause agents
to submit tasks — idempotency keys stop duplicates, not generative loops. So:
per-agent **task-creation quotas**; an **ancestry depth cap** on provenance
chains; cycle detection at submit; and a **dead-letter** state for poison tasks
after max-retries — never an infinite retry loop through paid quota.
## 5b. Humans (plural) and memory partitioning
There is more than one human already (alvis and elizaveta are both on Adolf's
Matrix allowlist) and there will be more. Every human is an agent with
trust=human, their own inbox, and — critically — **their own privacy domain**.
**Memory partitioning (hard rules):**
- **Per-human private banks**: `adolf-alvis`, `adolf-elizaveta`, … Everything
learned in conversation with human H goes to H's private bank by default.
**Content from one human's conversations must never surface to another
human.** This is a correctness property, not a preference.
- **One shared household bank** for facts that are explicitly household-wide
(addresses, devices, routines, shared plans). Trusted agents may write;
**promotion from a private bank happens only by that human's explicit action
or approval task** — never automatically.
- **Recall is interlocutor-scoped**: when Adolf talks to H it recalls from H's
private bank + the shared bank, nothing else. The recall/retain hooks select
the bank by interlocutor identity.
- Sandboxed agents (Torgash, researcher) read at most the shared bank; never
any private bank. This is the cross-human face of the memory matrix.
- The current single `adolf` bank is migration debt: split into
`adolf-alvis` + shared.
**Human inbox design:** notifications are priority-routed — gate/urgent tasks
ping the human via Matrix (Adolf initiates them; cf. proactive-messaging work),
everything else lands in a daily digest from the fabric-keeper. Ignored gate
tasks park and re-remind; **they never default-approve**. Vacation mode: a
human's a(t)=0 parks their inbox like any other scarce queue — gated flows
wait; predefined degraded defaults apply where explicitly configured.
## 6. Executor — thin KB-polling workers
No Temporal/Hatchet: at homelab scale (dozens of tasks/day) a durable-execution
platform would duplicate Kanboard as a second source of truth. Instead, one
small worker daemon per model-queue (compose services, ~200 lines, shared lib):
```
loop:
a(t) check # quota/budget/health probe; if 0 → park (sleep, re-probe)
poll KB view # filtered: my queue, status=queued, by priority
claim # atomic: assign-to-self + column move + lease timestamp
resolve refs # fetch context by reference
execute # via LiteLLM (model-agents) / agent runtime (persona)
write result ref # to the shared store; never inline
update status # done | failed(retry policy) | input-required(→ inbox)
```
Leases + heartbeats make dead workers safe: an expired lease returns the task to
queued. Two workers on one queue never double-run a task (claim is atomic).
Idempotency keys on submission prevent duplicate proactive tasks. OpenClaw cron
is the proactive *submitter* (Adolf's schedule); workers are the *drainers*.
### 6a. Task schema — the KB-literal mapping
Per the **KB-literal decision** (§10.2: *"Kanboard is the queue, humans
included; no separate store"*): there is no separate task schema or task
table anywhere — a Task (§2, Axiom 2: `(intent, context-refs, constraints,
priority, deadline, provenance)`) is **entirely represented by native
Kanboard task fields plus a small set of conventions layered on top**
(columns, tags, comments). The table below is that mapping, field by field.
It is not aspirational: every row is what `kb-claim` and `kb_worker.py`
(`/home/alvis/kanboard/bin/`) already read or write today — those two files
are the ground truth this table documents, not a separate spec to keep in
sync by hand.
| Task field | Represented as | Notes |
|---|---|---|
| **id** | native Kanboard task `id` | Globally unique per Kanboard instance. A `taskRef` in the algebra (§2) is `(project_id, task_id)` — project scopes columns/tags, so the pair (not the bare id) is what a worker needs to act on a task. |
| **intent** | `title` (short) + `description` (full spec, Markdown) | `description` is the literal task body — what to do, acceptance criteria, links. `kb-claim next`/`take` print it verbatim under `--- spec ---`; nothing paraphrases it. |
| **required tier** | *derived*, not stored — from native `score` | `score` is Kanboard's complexity field (Fibonacci: 1,2,3,5,8,13,21), normally set by the human, settable via `create_task`/`update_task`. `kb-claim`'s `tier_for(score)` maps it: `0` (unrated) → `sonnet` (safe default, task should be flagged for rating, not silently run cheap) · `≤2` → `haiku` · `≤5` → `sonnet` · `>5` → `opus`. The **complexity gate** (kb/CLAUDE.md): an unrated task is tagged `blocked` with a comment asking for a score, instead of being dispatched on the default tier. |
| **target queue** | Kanboard **project** | Each queue is a Kanboard project — e.g. the `Adolf` project is what the always-on-local and Kimi-quota worker configs point `"project"` at (`workers/*.example.json`). Trust-scoped agents get their own project (§5: researcher gets its own KB project). `swimlane_id` is read and carried through every claim/park/done move but is not yet used to subdivide a queue further — headroom for later without a new field. |
| **priority** | native `priority` field, `0``3` | Take-order (kb/CLAUDE.md): `p1 > p2 > p0 > p3` (note `p0` sits between `p2` and `p3`, not below `p3`). `kb-claim`'s `eligible()` sorts candidates by `(-priority, board position)`; the interactive `/kb` loop layers a WIP-resume dimension on top (resuming WIP outranks fresh `p2`) — that extra ordering lives in the orchestrator convention, not in `kb-claim` itself. |
| **status** | *derived* from column + tags + open/closed — no single status field | **Column** (`Backlog`→`Ready`→`Work in progress`→`Done`, looked up by title via `columns()`) is the coarse lifecycle stage. **Open vs closed** (`status_id`/`closeTask`) is unverified vs verified completion (§2 "Completion vs verification", decision log #15): Done+open = unverified (`kb-claim done`, never closes its own task); Done+closed = verified (`kb-claim close`, by someone other than the producer). **Tags** carry the remaining states: `blocked` = input-required / parked for a human (escalation, missing score, or a fabric-keeper deadline escalation — same tag, one park primitive); `dead-letter` = poison, retries exhausted (`kb-claim deadletter`); `needs-human-verify` = machine-verified but sensitive, left open for a human to close (`kb-claim escalate`). Maps onto the A2A lifecycle (§4): submitted≈Backlog/Ready, working≈WIP, input-required≈WIP+`blocked`, completed≈Done+closed, failed≈`dead-letter`. (`canceled` has no Kanboard convention yet — not in scope here.) Claim freshness (the lease) is a **comment**, not a field: `🔒 claimed by \`agent\` at <ts>` / `lease renewed by …`, parsed back out by `lease-status` via regex — this is what lets an expired lease be swept back to `Ready` without a dedicated lease column. |
| **context refs** | plain text *inside* `description` (and follow-up `comment`s) — convention, not a typed field | Per Axiom 2, "context travels by reference, never by value": a bank id, git ref/SHA, another KB task id (`#N`, which Kanboard auto-links), or a filesystem path, written as text. Enforced by review/convention, consistent with KB-literal — there is no schema-validation layer sitting in front of Kanboard to enforce it mechanically. |
| **result ref** | the `note` on the `done`/`park`/`deadletter` comment | `kb_worker.py`'s `Outcome.note` (in-process) is flushed by `report_outcome()` to a Kanboard comment (`✅ {note}` for done) via `kb-claim done --note …`. No separate result store: the comment thread *is* the audit trail (kb#159's "closing is verification" model reads it). |
| **submitter** | native Kanboard `creator_id` | Set automatically by `createTask`; exists on every task already. Distinct from `owner_id`, which is the *current claimant* and is what `claim`/`park`/`done` mutate. Not yet read by `kb-claim`/`kb_worker.py`/`fabric-keeper.py` — available, unused, out of scope for this task. |
| **deadline** | native Kanboard `date_due` field | Enforced by `fabric-keeper.py`'s `enforce_deadlines()` (§6b "time semantics"): a fabric-owned, open, unparked task with `date_due` in the past gets `kb-claim park`ed (tagged `blocked`, comment naming the responsible inbox = current owner, or alvis if unassigned). Idempotent — already-`blocked`/`dead-letter` tasks are skipped so re-sweeps don't spam. |
### 6b. Who is "the scheduler"? — decomposed, plus one janitor
There is deliberately **no central dispatcher**. Scheduling decomposes into
four concerns, each with its own owner:
| Concern | Question | Owner |
|---|---|---|
| Triggering | when do tasks appear? | OpenClaw cron, agents' delayed self-submissions, humans |
| Dispatch | which task runs next? | each queue's worker (claim by priority under its a(t)) |
| Admission | may it run now? | LiteLLM budgets/rate + the budget governor |
| **Time semantics** | expired leases, deadlines, stuck tasks? | **the fabric-keeper** |
| Failure/anomaly response | something went wrong — now what? | Zabbix → the ops-agent (§6d) |
The **fabric-keeper** is one tiny always-on daemon that neither assigns nor
triggers work. It sweeps expired leases back to queued, enforces task deadlines
(escalating to the responsible inbox), moves poison tasks to dead-letter, emits
the human daily digest, and exports queue depths/ages to Zabbix.
Its defining property is being **off the critical path**: kill it and work still
flows (workers keep pulling and running) — only hygiene degrades. That is what
separates a janitor from a scheduler, which in a push system would stop
everything.
**Deliberately NOT a keeper duty: missed crons.** A cron window missed because
the host was down is not a task-lifecycle event — it's an *operational fault*,
and re-firing it would make the keeper a trigger. Instead: schedules that must
not be missed are **monitored in Zabbix** (a missed run raises a warning like
any other infra fault), and the response is handled per-incident, not by a
blanket catch-up policy (§6d).
### 6d. Faults are incidents, not keeper chores
Anything that "went wrong" — a missed critical cron, a service down, a queue
backing up, a stale backup — surfaces as a **Zabbix problem**. Zabbix is the
single place operational faults are detected.
Response is **per-incident, not global**: each Zabbix problem class gets its own
mitigation path, expressed as a task. Later this is automated by a dedicated
**ops-agent** — a worker that watches Zabbix problems and, per problem class,
either applies a known mitigation or files a task (to the right agent, or to a
human inbox) with the incident as context. One blanket "catch-up policy" would
be exactly the wrong abstraction: a missed briefing, a missed backup and a
missed consolidation want completely different responses.
### 6c. Kanboard is tier-0 now
Promoting KB to the fabric's backbone promotes its ops class: **backups on par
with the vault**, Zabbix monitoring of the service and API, and a defined
**degraded mode** — if KB is down, Adolf still answers Matrix chat (no fabric
operations, no task memory), workers park, nothing crashes or data-loses.
## 7. Observability — Langfuse (kept), wired for real
Decision: keep **Langfuse** (already deployed; best-in-class self-hosted:
traces + per-token cost + prompt management + evals, MIT). Grafana rejected for
this role — generic metrics with no LLM semantics (the source of past
dissatisfaction); Zabbix keeps infra monitoring. To do (it currently receives
nothing): LiteLLM success/failure callbacks → Langfuse; tag every trace with
`agent`, `task-id`, `queue`; per-agent cost dashboards; upgrade v2→v3. Every
completion is traced here — this is where sub-Task granularity lives.
## 8. Growing the lab
- **More GPUs / remote llama** → new model-agent Cards with `on-demand` a(t)
(health probe, wake hook, graceful absence). Routing skips absent nodes.
- **More specialists** → new Cards + scoped tools + own banks. The fabric and
A2A don't change.
- **Autonomous research agents** → low-priority loops on always-on local queues,
escalating (via always-ask, initially) for large-model synthesis; own KB
project; tainted outputs until promoted.
## 9. Migration order
1. Registries: model Cards + agent Cards (schema + populate).
2. First thin worker end-to-end on an always-on local queue.
3. Quota-gated worker (Kimi park/resume). Claim/lease semantics.
4. A2A protocol surface (JSON-RPC + Agent Cards) over the fabric.
5. Cutovers: Hindsight reflect → fabric; consolidation → fabric (low prio);
claude-coder + Adolf declared as registry agents (Adolf's tools shrink to
scoped core).
6. Trust enforcement: capability grants (virtual keys + MCP allowlists), taint
gate, budget governor, langfuse wiring.
7. Scale: Torgash, researcher (own KB project), on-demand nodes.
## 10. Decision log (2026-07-21, alvis)
1. Single completions are not Tasks (langfuse-only) → no micro-churn.
2. **KB-literal**: Kanboard is the queue, humans included; no separate store.
3. Trust classes as §5; vault = trusted only.
4. Escalation = always-ask initially.
5. Researcher: KB access allowed, own project(s), scope-limited.
6. Real A2A protocol now (JSON-RPC + Agent Cards).
7. Proactive schedules: OpenClaw cron → fabric.
8. Langfuse kept as the observability layer; Grafana rejected; Zabbix = infra.
9. Executor = thin KB-polling workers; no Hatchet/Temporal at this scale.
10. Sync routing = LiteLLM Auto Router v2; fabric owns async/parking.
11. Sandbox = per-task workspace lease + container + PR-only merges.
Added in v2.1 (hardening review, same day):
12. **Multi-human**: per-human private banks + shared household bank;
interlocutor-scoped recall; cross-human leakage forbidden (hard rule);
promotion to shared only by the owning human's action/approval.
13. A2A auth mandatory everywhere — the LAN is untrusted (VPN peers).
14. KB = tier-0 infrastructure (backup, monitoring, degraded mode).
15. Done column = unverified completion; closed task = verified; the producer
never closes its own task.
16. Scheduler = decomposed (cron/self-submission triggers; workers dispatch;
LiteLLM+governor admit); the **fabric-keeper** janitor owns time semantics
(leases, deadlines, dead-letter, digests) and neither assigns nor triggers.
17. Personas/Cards live in git, deployed — never edited live.
18. Backbone/routing changes gated by golden-set shadow eval (Langfuse).
19. Fabric hygiene: creation quotas, ancestry depth cap, cycle detection,
dead-letter for poison tasks.
20. GPU residency policy: local a(t)=f(VRAM); never-evict set (embedder,
reranker); pre-load checks.
21. Transport: sync = direct A2A RPC (journaled); async = KB polling; polling
never on a sync path.
22. **Missed crons are not a keeper duty**: schedules that must not be missed
are monitored in **Zabbix**; faults are incidents handled **per problem
class** by a future **ops-agent** (§6d), never by a blanket catch-up policy.
23. **No metered API by default** (§3a): scope = Claude Code + Kimi wrapper +
local GPU embedder + small local model. The cheap tier is the *local*
model, not a paid one; paid deployments are opt-in fallback per virtual
key. The governor arbitrates **quota and GPU, not money**.
24. **Routing classification is embedding-based** on the local bge-m3 via
LiteLLM Auto Router (`semantic-router`): no classifier LLM call, no API
spend. Keep a heuristic fallback — Auto Router v2 is new (2026-07-14) with
an open embedding bug report.
25. Hindsight gains an **optional caller-supplied cognition mode** (#131) so it
can run inside a Claude Code session with zero extra API calls; the
API/queue path stays the default. Same verb, different `target`.

View File

@@ -191,13 +191,21 @@ RUN --mount=type=cache,id=openclaw-bookworm-apt-cache,target=/var/cache/apt,shar
--mount=type=cache,id=openclaw-bookworm-apt-lists,target=/var/lib/apt,sharing=locked \ --mount=type=cache,id=openclaw-bookworm-apt-lists,target=/var/lib/apt,sharing=locked \
apt-get update && \ apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates curl git hostname lsof openssl procps python3 tini && \ ca-certificates chromium curl git hostname lsof openssl procps python3 tini && \
update-ca-certificates update-ca-certificates
# chromium (Debian's real package, not snap) added for the OpenClaw `browser`
# plugin — it resolves a system Chrome/Chromium to drive via CDP, and the
# node:*-slim base ships none. Its shared libs (libnss3, libgbm1, ...) come in
# as chromium's Depends. Adolf fork addition (kb#64: authenticated web access).
RUN chown node:node /app RUN chown node:node /app
COPY --from=runtime-assets --chown=node:node /app/dist ./dist COPY --from=runtime-assets --chown=node:node /app/dist ./dist
COPY --from=runtime-assets --chown=node:node /app/node_modules ./node_modules COPY --from=runtime-assets --chown=node:node /app/node_modules ./node_modules
# node_modules/@openclaw/ai is a workspace symlink -> ../../packages/ai; the
# built lib must ship so the gateway's `import "@openclaw/ai"` resolves at
# runtime (otherwise: "Cannot find package '@openclaw/ai'"). Adolf fork fix.
COPY --from=runtime-assets --chown=node:node /app/packages/ai ./packages/ai
COPY --from=runtime-assets --chown=node:node /app/package.json . COPY --from=runtime-assets --chown=node:node /app/package.json .
COPY --from=runtime-assets --chown=node:node /app/pnpm-workspace.yaml . COPY --from=runtime-assets --chown=node:node /app/pnpm-workspace.yaml .
COPY --from=runtime-assets --chown=node:node /app/patches ./patches COPY --from=runtime-assets --chown=node:node /app/patches ./patches

184
docs/SPIKE-FINDINGS.md Normal file
View File

@@ -0,0 +1,184 @@
# Adolf — P0 De-Risking Spike Findings
**Date:** 2026-07-05 · **Status:** Resolved — see verdicts below · **Scope:** ARCHITECTURE.md §4 gates 1-5
Method: live inspection of the running `kimi-agent` container/image (Dockerfile, `server.js`,
`docker exec` into it), throwaway containers built from the same image with a **copy** of its
`/root/.kimi-code` volume (created, tested, and fully destroyed — the live `kimi-agent` service was
never stopped, restarted, or modified), decompiled/grepped `@moonshot-ai/kimi-code` bundle source,
and direct reads of the vendored OpenClaw source already in this repo (`src/auto-reply/reply/*`,
`docs/concepts/model-providers.md`) plus upstream web docs/search.
---
## Gate 1 — Kimi CLI package, home dir, MCP path, flags, auth persistence
**Verdict: architecture assumption was backwards. No change needed — current setup is already correct.**
- The running `kimi-agent` container uses `@moonshot-ai/kimi-code@0.22.3` (binary `kimi`), home dir
`/root/.kimi-code`. This **is** the current upstream package — `MoonshotAI/kimi-code` is the
active/maintained CLI; `MoonshotAI/kimi-cli` (home `~/.kimi/`) is the **legacy** predecessor being
phased out. Confirmed both externally (web search: "Kimi CLI is evolving into Kimi Code CLI... the
kimi-cli project will be gradually wound down") and internally — the shipped binary's own `kimi
migrate` command copies data **from** `~/.kimi/` (legacy) **into** `~/.kimi-code/` (current), and its
bundle contains the string `"Old data kept at ~/.kimi/ — kimi-cli still works."` So `~/.kimi/mcp.json`
is the *old* path, not the upstream target.
- **MCP config**: there is no `kimi mcp` subcommand and no `--mcp-config-file` flag in this version
(`kimi --help` confirmed; grepped the bundle for the flag string — absent). MCP servers are
configured via a **project-root `.mcp.json`** (Claude-Code-compatible schema, auto-discovered by
walking up from cwd) or the interactive `/mcp-config` TUI command. Verified empirically: placing
`.mcp.json` in a headless run's working directory does not error and `kimi doctor` validates config
files cleanly from that directory. **Action for `adolf-llm`/`cognee-llm`: drop `shared-mcp.json` as
`.mcp.json` into each session's working directory** rather than relying on a CLI flag that doesn't exist.
- **Resume flags**: `-r`/`--resume` are **hidden, undocumented aliases for `-S`/`--session`** (confirmed
by the CLI's own `session.resume_hint` meta line: `"command":"kimi -r session_..."`, and empirically
by resuming a session with `-r <id>` and getting correct context recall). `-p`, `--output-format
stream-json` both exist and work exactly as `kimi-agent/server.js` already uses them.
- **Auth persistence in a fresh container/volume — confirmed YES.** Copied the live `kimi-agent`'s
`/root/.kimi-code` into a brand-new named volume, mounted it on a throwaway container (different
container, same image), and made a real API call (`kimi -p "..." --output-format stream-json`) —
it authenticated and returned a real completion, and session resume (`-r <id>`) worked correctly
across separate `docker exec` invocations. **Subscription auth is fully portable via the CLI-home
volume** — `adolf-llm`/`cognee-llm` can each get their own volume seeded from (or sharing) the same
OAuth credential files.
- Cleanup: throwaway container, throwaway volume, and the host-side credential copy under `/tmp` were
all deleted after testing. The live `kimi-agent` container was untouched throughout (never
stopped/restarted/execed with anything destructive) and is still `Up` on its original uptime.
---
## Gate 2 — OpenClaw → provider session identity
**Verdict: no header/`user`-field wiring for custom providers — but OpenClaw gives us something
better: a structured, parseable session-identity JSON block embedded directly in every request's
prompt content. Use it as the primary session key; history-hash is not needed as a fallback for the
common case.**
Read directly from the vendored OpenClaw source in this repo
(`src/auto-reply/reply/inbound-meta.ts`) plus `docs/concepts/model-providers.md`:
- **Confirmed no hidden attribution headers or dynamic `user` field for custom `openai-completions`
baseUrl providers.** `docs/concepts/model-providers.md:680`: *"Proxy-style OpenAI-compatible routes
also skip native OpenAI-only request shaping: ... and no hidden OpenClaw attribution headers."*
Attribution headers (`originator`, `version`, `User-Agent`) are attached **only** on verified native
hosts (`api.openai.com`, `chatgpt.com/backend-api`) — `adolf-llm` will not receive them.
- **The actual mechanism**: `buildInboundMetaSystemPrompt()` injects a stable
`schema: "openclaw.inbound_meta.v2"` JSON block (`account_id`, `channel`, `provider`, `surface`,
`chat_type`) into the **system prompt** of every turn — deliberately excluding anything that
changes per-turn, to preserve provider-side prompt-cache prefix stability.
- **The stable per-conversation key we need — `chat_id`** — is emitted by
`buildInboundUserContextPrefix()` into the **user-role** message content instead, specifically as a
`"Conversation info (untrusted metadata):"` JSON code block containing
`chat_id: ctx.OriginatingTo` (plus `message_id`, `sender`, `timestamp`, etc.). `OriginatingTo` is a
channel-agnostic routing id (e.g. `"whatsapp:+1555..."`, `"telegram:chat-1"`; for us it will be the
Matrix room/peer id) and is confirmed present for direct-message channels that aren't `webchat`
(Matrix qualifies) via `shouldIncludeConversationInfo = !isDirect || (channel && channel !== "webchat")`.
This is populated by the core reply pipeline (`get-reply-run.*`) for **every** provider, native or
custom — it's provider-agnostic.
- **Action for `adolf-llm`**: on each incoming request, scan the latest user message content for the
`"Conversation info (untrusted metadata):"` JSON block, parse `chat_id`, and use it directly as the
session-map key → 1:1 Kimi session resume. This is strictly more robust than a history hash (it's
stable even across edited/truncated history) and needs no OpenClaw-side config changes. Keep the
history-hash approach only as a defensive fallback if the block is ever absent (e.g. webchat surface,
or a future OpenClaw version relocates the field — grep on the label string, don't assume a fixed
line offset).
- Escape hatch confirmed but not needed here: `agents.defaults.models["provider/model"].params.extra_body`
can merge static extra JSON into the outbound body for vendor-specific fields, but it's a config-time
value, not a per-request dynamic session id, so it doesn't help with mapping.
---
## Gate 3 — Headless image input via file-path reference
**Verdict: confirmed working end-to-end.** No CLI flag is needed — the agent has a built-in
`ReadMediaFile` tool it invokes autonomously.
Empirical test in a throwaway authed container: prompted `kimi -p "Look at ./test2.png and tell me its
exact pixel dimensions and dominant color."` (a real 64×64 solid-color PNG placed in the cwd). Observed
in the `stream-json` output:
1. `{"role":"assistant","tool_calls":[{"function":{"name":"ReadMediaFile","arguments":"{\"path\":\"./test2.png\"}"}}]}`
2. Tool result: reads the file, reports `Original dimensions: 64x64 pixels`, and returns an
`image_url` content part with a base64 `data:image/png;base64,...` payload wired into the model context.
3. Final assistant answer correctly identified the exact color used (`rgb(200, 30, 30)`).
(A first attempt with a degenerate 1×1 pixel PNG failed at the provider with `400 ... failed to decode
image: invalid or unsupported image format` — that's the upstream vision API rejecting a
near-empty test fixture, not a CLI/tool-path limitation; the 64×64 real PNG round-tripped cleanly.)
**Action for `adolf-llm`**: persist inbound Matrix images to the session's working directory and
reference them by relative path in the prompt text (e.g. "See attached image: `./img_3.jpg`") — the CLI
will autonomously call `ReadMediaFile` on it. No special flag or placeholder syntax
(`[image #N ...]`, which is TUI-paste-only) is required for headless mode.
---
## Gate 4 — Graph store: Kuzu vs Neo4j for Cognee
**Verdict: Kuzu (embedded). Use it; do not stand up Neo4j.**
- **Kuzu is Cognee's own default graph backend** (`GRAPH_DATABASE_PROVIDER=kuzu`), file-based, runs
embedded in-process with no network setup, no extra container, no auth surface, and stores its data
as plain files (fits directly under `/mnt/ssd/dbs/cognee/`, consistent with the rest of Adolf's
storage layout).
- Cognee's own guidance: Kuzu is recommended for local/single-user use; it uses file-based locking and
is explicitly **not** meant for multi-agent/concurrent-process access — that's when Cognee's docs
point to Neo4j instead.
- Adolf is explicitly single-user, single-agent, home-server scale (§1: "auto + tool" memory, one
Matrix bot). Neo4j would add: a whole extra JVM-based service (~0.5-1GB+ RAM), its own
backup/upgrade/security surface, and a network-exposed port — for zero benefit at this scale, since
we don't need Cypher-browser visualization or concurrent multi-writer access.
- **Recommendation**: Kuzu embedded, no separate container. Revisit only if/when a second concurrent
agent needs to write to the same graph, or ad-hoc Cypher-browser graph exploration becomes a real
requirement — neither applies to the current design.
---
## Gate 5 — `cognee-llm` suitability: agentic Kimi CLI vs LiteLLM fallback for batch cognify
**Verdict: default cognee's LLM backend to LiteLLM (fallback plan in ARCHITECTURE.md §3.3); keep
`cognee-llm`/Kimi CLI as an optional low-volume path only. JSON reliability is fine; per-call latency
and subscription/concurrency risk are the real blockers for batch use.**
Empirical test in a throwaway authed container (same one used for gate 1, cleaned up after):
| Call | Wall time | JSON cleanliness |
|---|---|---|
| Trivial prompt (`{"ok":true}`) — process floor | **~5.1 s** | clean |
| Structured entity/relationship extraction, inline text (no tool call) | **~21.9 s** | clean, exact schema match |
| Same extraction via file reference (adds a `Read` tool round-trip) | **~24.0 s** | clean, exact schema match |
Findings:
- **JSON reliability is good** — in both extraction runs the final assistant `content` was strict,
schema-conformant JSON with no prose/markdown fences, when explicitly instructed. This de-risks the
"won't emit clean JSON" half of the concern.
- **Latency is the real problem.** ~5 s is the CLI's fixed per-invocation floor (Node process cold
start, config/credential load, provider round-trip) even for a near-empty completion; a realistic
extraction call runs ~20-25 s. Cognify issues one such call per chunk/entity-extraction step — for a
batch of even a few dozen chunks, serialized wall time reaches many minutes, and true parallelism is
unverified: the Kimi subscription is a single-seat, interactive-coding-oriented plan, and hammering it
with concurrent batch CLI invocations risks rate-limiting or provider-side throttling that this spike
did not (and should not) test at scale — that's a live-account risk, not something to probe casually.
- **Every call is also agentic** (tool-call round trips are possible/likely even for "just extract
JSON" prompts, as seen in the file-reference test), adding non-determinism to latency and requiring
the wrapper to reliably strip tool-call/meta lines from `stream-json` output before parsing the final
JSON payload — extra parsing complexity for zero benefit in a task that doesn't need agentic tool use.
- **Recommendation**: point Cognee's `LLM_API_BASE` at a LiteLLM-routed model (`judge`/local qwen, per
ARCHITECTURE.md §3.3's own stated fallback) as the default for cognify. This is materially faster (no
process-spawn floor, no agent loop, no tool-call risk) and avoids risking the shared subscription
under batch load. Keep the `cognee-llm` Kimi-CLI wrapper buildable/available for low-volume or
experimental use, but do not make it the default path.
---
## Summary table
| Gate | Verdict |
|---|---|
| 1. Kimi CLI package/home/MCP/auth | `@moonshot-ai/kimi-code` + `/root/.kimi-code` **is already current upstream** (kimi-cli/`~/.kimi/` is legacy). No `--mcp-config-file`/`kimi mcp`; use project-root `.mcp.json` instead. `-r`/`-p`/`--output-format stream-json` all confirmed. Subscription auth **persists** across a fresh container given a copied CLI-home volume. |
| 2. OpenClaw session identity | No header/`user`-field wiring for custom providers. Use the `chat_id` (`ctx.OriginatingTo`) embedded in every turn's user-content "Conversation info" JSON block as the session key — parse it from prompt content, not headers. |
| 3. Headless image input | Confirmed working: CLI autonomously calls a built-in `ReadMediaFile` tool on a referenced file path in `-p` mode; no flag/placeholder syntax needed. |
| 4. Graph store | **Kuzu (embedded)** — Cognee's own default, matches single-user/no-extra-service goal. Neo4j not justified at this scale. |
| 5. cognee-llm suitability | JSON output is clean, but ~5-24 s per call plus unverified batch-concurrency limits on a single-seat subscription make it unsuitable as the default. **Default to LiteLLM fallback** for cognify; keep Kimi-CLI path optional. |
All gates are resolved with either direct empirical verification (1, 3, 5) or authoritative source
reading (2, plus corroborating docs for 4). No gate required an unresolved forbidden action.