Plugins for the Adolf gateway:
- hindsight-openclaw-plugin: expanded memory recall/retain surface for the
Cognee -> Hindsight migration
- todoist-capture-plugin: posts captured ideas to agap-mcp's /capture-idea,
sending the kb#180 bearer token when AGAP_MCP_TOKEN is present
- feedback-loop-openclaw-plugin, kimi-quota-footer-plugin, cognee-mcp,
cognee-openclaw-plugin
Plus migrate-adolf-memory-banks.mjs for the memory-bank split,
backup-hindsight-adolf.sh / backup-llm-dbs.sh (the Hindsight and adolf-state
backups that were previously missing), and gpu_preload_check.sh for the
GTX 1070 residency checks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
docker-compose.yml gains healthchecks and depends_on/condition chains for the
litellm/langfuse/postgres tier so dependants wait for a genuinely ready
service instead of a started container. Also plumbs AGAP_MCP_TOKEN into the
adolf and adolf-llm containers, sourced from openai/.env (gitignored), for the
kb#180 bearer auth on the agap MCP server; shared-mcp.json consumes it via
bearerTokenEnvVar so the Kimi backbone authenticates too.
agent-registry.yaml / agent_registry.py: the version-controlled source of
truth for agent identities and trust classes -- the same ids the agap-mcp
token map resolves to (`adolf`, `claude-coder`; note `claude-code-cli` is the
runtime entry, not an agent identity).
model-registry.yaml, litellm-config.yaml, auto-router-routes.json and
provision_litellm_keys.py: model tiering, virtual-key provisioning and
auto-router routes. tei-reranker/ is the local reranker service backing
Hindsight recall.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Retain/extraction moved off the Kimi wrapper (hindsight-llm:8012) onto
ollama/gemma3:4b via LiteLLM, joining consolidation + reflect which were
already local (kb#88). Kimi is no longer in the Hindsight path at all, so
the memory backend consumes zero quota and Adolf's 5h window is left
entirely for conversation.
Accepted tradeoff: kb#84/kb#88 kept retain on Kimi for fact quality, since
gemma3:4b's Russian fluency was never verified and this bank is largely
Russian. A dry-run extraction on Russian input after the change returned
clean, parseable output but captured only one of two facts in the sample,
so extraction is coherent but lossier. Revert this first if facts degrade.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Commits a cluster of entangled agap-mcp / Adolf-tooling WIP that had accumulated
uncommitted in shared files (server.js, the three MCP-config layers). Bundled as
one commit because server.js interleaves all of it and cannot be cleanly split;
each stream is named here for the record. Authorized by alvis 2026-07-23.
- **kb#95 — family MediaWiki tools:** new src/mediawiki.js (wiki_search / wiki_read
/ wiki_edit, MediaWiki login->CSRF->edit flow, no new deps), registered in
server.js and fetched from the family.alogins.net Vaultwarden login item.
Proven standalone against family.alogins.net (search/read/edit, revid 1520 on a
bot-userspace page). Wired into all three layers: openai/shared-mcp.json,
adolf/openclaw.json, openai/agent-registry.yaml.
- **kb#147 — vault trust-gate (A2A-15), DORMANT:** new src/trust-gate.js (+ two
test files), requireVaultAccess() around the vw_* tools, gated by
AGAP_MCP_ENFORCE_VAULT_TRUST (docker-compose.yml, default 0). OFF by default —
vw_* behaviour is byte-for-byte unchanged until an operator sets ENFORCE=1 and
populates AGAP_MCP_AGENT_TOKENS from Vaultwarden. That activation is a separate
human step; kb#147 remains escalated for human verification and is NOT verified
by this commit. js-yaml added to read the registry. agent-registry.yaml mounted
read-only as the trust-class source of truth.
- **Todoist tools:** new src/todoist.js (initTodoist + 6 todoist_* tools),
registered in server.js, sourced from the TODOIST_TOKEN Vaultwarden item.
- **kanboard cutover cleanup:** removes src/kanboard.js and its imports — the
kanboard_* slice moved to the standalone kanboard-mcp on 2026-07-06.
- **openai/validate_capability_grants.py:** cross-checks the registry against the
live openclaw.json + shared-mcp.json layers; passes (exit 0).
No secrets committed: all tokens come from Vaultwarden via env/.env; the trust
gate's AGAP_MCP_AGENT_TOKENS defaults to `{}` (fail-closed). node_modules/ now
gitignored, package-lock.json tracked.
NOT YET ACTIVATED: agap-mcp has not been rebuilt and adolf-llm/adolf not
restarted, so the wiki/todoist tools are wired but not live. That restart is the
outstanding step on kb#95 (and stays a human/orchestrator action).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two related changes to the /usage quota route, committed together because they
are entangled in the same code path.
1. Stop refreshing the Kimi OAuth token from this route (kb#87). Was already
present as uncommitted working-tree WIP, not authored in this commit's
session. Kimi rotates the refresh_token on every refresh (single-use), so an
independent refresh here invalidated the copy the CLI's creds file holds ->
the CLI's next refresh failed invalid_grant and wiped the whole login (the
recurring Adolf logout, incl. the 2026-07-17 06:15 wipe / task #86). Removes
KIMI_OAUTH_HOST, KIMI_CLIENT_ID, refreshKimiToken() and the kimiMemToken
cache; the CLI is now the sole refresher and this route only ever READS.
2. Serve the last good reading when the token is stale, instead of erroring.
Measured 2026-07-22: the access token's expires_in is 900s, so it is only
valid for 15 minutes after the CLI last refreshed it -- i.e. only within 15
minutes of an actual Adolf turn. Adolf is idle most of the day, so bare
reads failed far more often than they succeeded and quota gating was
effectively blind. /usage now caches every success and, on a stale token,
returns that payload with stale/as_of/age_s/stale_reason so callers can
judge whether it is fresh enough. Cache is mirrored to the workspace volume
so it survives restarts, and writes are best-effort so an unwritable volume
cannot break the route. Auth behaviour is unchanged by this half.
Payload shape is additive only -- existing kimi-usage -q filters keep working.
Verified live after rebuild: fresh read returns weekly 16% / 5h 5% with
stale:false; cache file written to /workspace/.adolf-llm/usage-cache.json;
kimi-usage -q '.window_5h.pct' returns 5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per DESIGN-a2a-agents.md v2.1 §2, §5, §5b: an agent is a persona, not a
queue. Sibling of kb#133's model-registry.yaml, same load/get/CLI shape.
- agent-registry.yaml: populates adolf (trusted, scoped core tools),
claude-coder (trusted, implementer), torgash (sandboxed, marketplace-
only, target state - not yet built), researcher (sandboxed/untrusted-
input, target state), kimi-endpoint/local-small-endpoint (trivial
model-agents from #133), and alvis/elizaveta as first-class human
agents with trust=human, own inboxes, own private memory bank targets
(adolf-alvis/adolf-elizaveta/adolf-shared - split itself is kb#153).
Also carries trust_classes with numeric rank, a runtimes: section for
Claude Code (kb#133 explicitly excluded it from model-registry.yaml),
and memory_bank_policy documenting §5b's hard rules.
- agent_registry.py: effective_card() is what makes "backbone swap is
one field" true rather than aspirational - tier/cost_class/lifecycle
are never stored statically on an agent, they're resolved at read
time from `backbone` via model-registry.yaml or runtimes:. Also
trust_rank() and can_reach_vault() (kb#147's vault-access DECIDED
rule as a checkable function, not just a comment).
Several Cards (torgash, researcher, elizaveta's KB identity, the split
memory banks) describe target state for things not yet built/migrated -
flagged with status/note fields rather than implied live, matching the
task's scope (registry only, no runtime migration).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
Per DESIGN-a2a-agents.md v2.1 §2-3b: models are the scarce queued
resource, version-controlled here rather than hardcoded in callers.
- model-registry.yaml: kimi (main reasoning, quota-gated), local-small
(ollama/gemma3:4b, always-on cheap tier), bge-m3 (embedder + routing
classifier, never-evict), tei-reranker (never-evict, interactive-
critical), paid-fallback (metered, opt-in only, unreachable by
default via empty routing.metered_opt_in). GPU residency policy
carries the never-evict set, co-residency groups, and measured
baseline (bge-m3+gemma3:4b+tei-reranker ~6.2/8GB on the GTX 1070).
- model_registry.py: resolve(tier) picks an available model without
the caller naming one, gated so a metered model is only reachable
with both allow_metered=True and an opted-in virtual key;
to_probe_config() bridges registry quota data into kb_worker.py's
existing Probe classes (no duplicated probe logic); preload_check()
expresses the §3b pre-load VRAM check purely from registry data.
Gap noted for follow-up: bge-m3 has no litellm-config.yaml model_list
entry yet (embedder there still points at ollama/nomic-embed-text on
a different port) — out of scope here, registry documents it as-is.
Per-stage LLM routing so Hindsight's high-volume background jobs stop burning
the rate-limited Kimi subscription:
- CONSOLIDATION + REFLECT -> ollama/gemma3:4b via LiteLLM :4000 (local GPU, free)
- RETAIN (fact extraction) stays on Kimi (hindsight-llm) for quality
Fixes the Kimi 5h window maxing at 100% from ~1100 background calls/3h (dropped
to ~38%). Documents the reasoning in HINDSIGHT-MIGRATION.md section 10:
frequent/mechanical/background stages -> cheap local model; user-facing,
quality-critical, low-volume -> Kimi.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
The bridge advertised non-existent gateway actions ("click"/"type"), so Kimi
sent action="type" -> "Unknown action". Corrected to the real vocabulary:
interactions go through action="act" with args={kind, ref, text} (e.g.
{kind:"type", ref:"e59", text:"..."}, {kind:"click", ref}), plus the real
top-level actions (open/navigate/snapshot/screenshot/act/...). Verified Adolf
can now type/click in the browser.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
- openclaw.json: browser.enabled + noSandbox (containers can't sandbox) +
ssrfPolicy.dangerouslyAllowPrivateNetwork (local *.alogins.net resolve to
the private host gateway); "browser" added to gateway.tools.allow.
- docker-compose.yml: extra_hosts family.alogins.net / wiki.alogins.net ->
host-gateway on both adolf and adolf-llm, so the gateway browser AND the
Kimi CLI's fetch reach the local wikis (hairpin-NAT dodge, like matrix).
Enables Adolf to open + log into the family wiki (kb#64). Root 401 on the
openclaw-tools bridge was a separate fix (empty ADOLF_GATEWAY_TOKEN -> just
recreate the bridge container; no file change).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
H4 (kb#76) - Cognee -> Hindsight migration finished:
- New openai/hindsight-llm/ (clone of cognee-llm, :8012, own volume) so
Hindsight's Kimi LLM no longer depends on the cognee stack
- Repointed hindsight service LLM at hindsight-llm:8012 (+ depends_on)
- Removed cognee, cognee-mcp, cognee-llm services + cognee-llm-home volume
from openai/docker-compose.yml
- Removed the disabled cognee-memory plugin entry from openclaw.json
Vault access (kb#64): wired the shared agap-mcp (:3100, same MCP Claude uses)
into Adolf's registry - "agap" server in shared-mcp.json + openclaw.json
mcp.servers. Adolf can now fetch credentials from Vaultwarden (verified).
Note: agap-mcp/docker-compose.yml (repointed to the adolf46 account) is
deliberately NOT in this commit - it holds the master password in plaintext.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
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.
Replace nomic-embed-text (768-d) with bge-m3 (1024-d, GPU-served via the
same :11436 ollama) as cognee's embedding model, for better multilingual
recall. cognee's Qdrant collections held only P4 smoke-test fixtures (no
real conversation data — adolf-llm's cogneeSearch/cogneeAdd are still
stubs), so the stale 768-d collections were dropped and left for cognee
to recreate at 1024-d on next write, rather than migrated.
Verified: bge-m3 returns 1024-dim vectors via ollama /api/embed; after
recreating the cognee container, a remember/recall round trip (including
Russian text) produced correctly dimensioned (1024-d) Qdrant collections
and recalled the exact fact stored, then the test dataset was deleted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Build adolf:local with the matrix extension bundled (OPENCLAW_EXTENSIONS),
route mtx.alogins.net to host-gateway to dodge hairpin NAT, and wire
ADOLF_KEY/Matrix creds through openai/.env (now gitignored + untracked;
it previously held Langfuse keys in cleartext git history). Runtime
openclaw.json + SOUL.md live in the adolf-state volume, not this repo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
- adolf-llm/server.js now loads SHARED_MCP_SERVERS from the mounted
/shared-mcp.json instead of a hardcoded stub, so adding a shared MCP
server is a one-file change. Verified end-to-end: a real chat-completions
turn writes a session .mcp.json containing both cognee and openclaw-tools
entries (kimi itself still needs `kimi login` in adolf-llm-home, unrelated
to this change).
- Documented the Gate-1 transport reconciliation: decompiled the installed
@moonshot-ai/kimi-code package to confirm its .mcp.json schema keys remote
servers on `transport` ("stdio"/"http"/"sse", inferred as "http" from a
bare `url`, never "sse"), while OpenClaw's own canonical mcp.servers schema
uses different literals ("streamable-http"/"sse") for the same field name
and treats `type` as a CLI-native alias it normalizes itself. `type: "http"`
is the one shape both consumers tolerate, so shared-mcp.json keeps it.
- New openai/openclaw-tools/ service: a stateless MCP-over-Streamable-HTTP
bridge (Node, @modelcontextprotocol/sdk) exposing message_send, cron_create,
cron_list, nodes_invoke, and browser_invoke, each proxying to the OpenClaw
gateway's POST /tools/invoke. Verified initialize + tools/list handshake and
a tools/call against the not-yet-running `adolf` gateway returns a clean
isError content instead of breaking the MCP connection. Documented that
cron/nodes are hard-denied on that HTTP surface by default until P6 adds
them to gateway.tools.allow; message/browser are not similarly restricted.
- Wired openclaw-tools into docker-compose.yml (openai network, :8020) and
added its shared-mcp.json entry alongside cognee.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Resolves the 4 P4 blockers and wires cognee/cognee-mcp into the openai
compose stack:
- qdrant: container was gone (data intact under /mnt/ssd/dbs/qdrant);
brought back up, confirmed healthy on :6333.
- Embeddings: switched from a dead LiteLLM route to ollama directly
(host.docker.internal:11436, nomic-embed-text, 768-dim), using cognee's
dedicated OllamaEmbeddingEngine and its native /api/embed endpoint.
Requires extra_hosts: host.docker.internal:host-gateway since ollama
lives in a separate compose project.
- cognee-llm kimi auth: root cause was that cognee-llm had never been
started, so its kimi-agent-home-equivalent volume didn't exist yet.
Seeded cognee-llm-home from the already-authed kimi-agent-home volume
(read-only copy of config/credentials/oauth/device_id); cognee-llm now
serves real completions.
- mkdir'd cognee data/system dirs: confirmed present (done by user).
Also fixed three issues found only during a live end-to-end smoke test:
- VECTOR_DB_PROVIDER must be a real container env var, not just present in
the mounted cognee.env — the qdrant adapter's sitecustomize.py
registration hook reads os.environ directly, which pydantic-settings'
env_file parsing never populates.
- Baked the Kuzu/Ladybug JSON extension into the cognee image. This
deployment's egress to extension.ladybugdb.com is bandwidth-throttled to
~1.2 KB/s, so cognee's own runtime auto-download reliably timed out,
leaving /health permanently unhealthy and graph queries failing. Fetched
the ~827KB extension out-of-band (16-way parallel ranged GETs) and added
it to the image via COPY.
- LLM_ENDPOINT needed an explicit /v1 suffix (litellm appends
"/chat/completions" verbatim) and LLM_INSTRUCTOR_MODE=json_mode is
required since cognee-llm's Kimi wrapper is a text-only pass-through with
no real tool-calling support.
Verified with a full remember -> recall round trip through cognee-mcp's
MCP tool surface: stored a fact containing a codeword, recalled it via
GRAPH_COMPLETION search, got the exact codeword back. Exercises cognee-llm,
ollama embeddings, Qdrant, and Kuzu together.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Reverse the earlier 'default to LiteLLM' recommendation: per user intent,
cognee runs its LLM on the Kimi subscription via cognee-llm (the reason the
wrapper exists). Gate-5 latency is an accepted tradeoff; LiteLLM stays a
documented fallback. Embeddings remain on LiteLLM nomic-embed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Model backend for the Adolf gateway. OpenAI-compatible (model 'adolf'), real
SSE streaming, chat_id session-keying (parsed from OpenClaw's untrusted-metadata
block per SPIKE gate 2) -> 1:1 kimi -r resume, media persistence for the CLI's
ReadMediaFile, per-session project-root .mcp.json (gate 1; no --mcp-config-file).
Cognee auto-memory hooks and shared-MCP server list are non-blocking stubs with
TODO(P4/P5) markers. New service + workspace/home volumes in compose.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Stateless one-shot wrapper for Cognee batch cognify: fresh temp dir per
request, no resume, non-streaming, text-only, bounded concurrency (3).
Per SPIKE-FINDINGS gate 5, Cognee should default its LLM to LiteLLM; this is
the optional low-volume path. New service + cognee-llm-home volume in compose.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
New 'adolf' service builds ../../adolf (the OpenClaw fork), runs the gateway
(node dist/index.js gateway --bind lan --port 18789) with persistent
adolf-state volume. Skeleton only; Matrix/SOUL.md/model-provider config wired
in P6. Existing services untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Wrapper previously passed only the last user message to a fresh 'kimi -p'
per request, so both the OpenWebUI thread history and kimi's own session
state were dropped every turn.
Now each conversation is keyed by a content-hash chain over the messages
array (survives LiteLLM in between) and mapped to a persistent kimi session
resumed via 'kimi -r <id>', with the session_id captured from stream-json
meta. Each conversation also gets its own working dir under
/workspace/conversations/<id> so file state is isolated and persists across
turns. Map persisted to /workspace/.kimi-agent/sessions.json (LRU-capped);
falls back to full-transcript reseed if a mapping is missing.
Runs the kimi-code coding agent in its own container, exposed as an
OpenAI-compatible model ("kimi-agent") that LiteLLM/Open WebUI can call
directly. Backed by the user's own Kimi/Moonshot subscription via
`kimi login`, not the pay-per-token API. Mount is scoped to a dedicated
~/kimi-workspace directory rather than the full home dir.
Accumulated uncommitted infra changes:
- Caddyfile: repoint HA/Zabbix to 192.168.1.4/.3, add ~20 new site routes
- Immich: move media to /mnt/smsg, enable CUDA ML, mem limits, rewrite backup.sh
- Add service stacks: agap-mcp, anki, family, freshrss, iperf3, kanboard,
linkwarden, qbittorrent, radicale, syncthing, vikunja, windows
- openwebui: enable API keys; ollama: drop CPU fallback
- seafile/zabbix: extra_hosts entries; matrix: add user juris
- Remove pihole stack and stale wiki/migrate.py
- Ignore marketplace-mcp (standalone repo) and linkwarden runtime data
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
Move services out of the monolithic openai/docker-compose.yml:
- ollama/ — ollama GPU + CPU inference servers
- openwebui/ — open-webui chat UI (uses env var for ANTHROPIC_API_KEY)
- searxng/ — SearXNG container + searxng-mcp MCP server (port 3102)
openai/ now contains only: litellm, langfuse, qdrant, faster-whisper,
silero-tts, pipecat.
searxng-mcp exposes a single searxng_search tool via MCP HTTP on :3102.
Registered in ~/.claude.json as the "searxng" MCP server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- LiteLLM proxy with langfuse callbacks, postgres backends, and OpenRouter fallbacks.
- Langfuse observability UI.
- Pipecat voice pipeline (LiveKit + STT + TTS + LLM) and Silero TTS build contexts.
- Ollama tuned for GPU (OLLAMA_NUM_GPU=999, mem_limit=4g, max 2 loaded models).
- open-webui wired to litellm + faster-whisper + silero for voice.
- litellm-config.yaml publishes oO's model aliases (tip-generator, embedder, judge)
pointing at the host ollama on :11434 so ml/serving can call them via LiteLLM.
.env skipped (secrets).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add CLAUDE.md with Gitea integration, development guidelines, and wiki interaction instructions
- Add comprehensive README.md with service overview, quick start, and configuration details
- Add service directories: gitea/, openai/, immich-app/, and setup scripts (install-cuda.sh, nvidia-docker-install.sh)
- Update docker-compose.yml structure and immich configuration
- Include restore example script for Immich database backups
This repository now serves as the source of truth for Docker Compose configurations and deployment automation for Agap home server services (Immich, Gitea, Open WebUI).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>