# MemClaw Documentation (Full) Concatenated body of every documentation page, intended for AI agent ingestion. See /llms.txt for the index only. # For Agents URL: https://memclaw.net/docs/agents Description: The MemClaw skill — the canonical prompt LLM agents follow when they have memclaw_* tools. Fetch the plain Markdown at /docs/agents.md. > **If you are an LLM agent reading this page, this *is* the canonical prompt.** The page below is the same content that gets installed on every MemClaw-connected runtime. You don't need to fetch it from anywhere else. > > A plain `text/markdown` form of the same content is available at [`/docs/agents.md`](/docs/agents.md) if your runtime prefers a single-fetch raw file. The whole docs site is also available concatenated at [`/llms-full.txt`](/llms-full.txt). > To install the skill onto a Claude Code / Codex runtime in one line (URL auto-targets this deployment — copy from staging, run against staging; copy from prod, run against prod): ## What this page is This is the canonical agent prompt for MemClaw — the skill an LLM follows when it has `memclaw_*` tools in its tool list. It defines: - **Identity** — how to set `agent_id` and `fleet_id` on every call. - **The three rules** — recall before you start, write when something matters, supersede don't delete. - **Trust levels** — what you can read and write at each tier (0–3). - **Tool dispatch** — which tool to call for which task. The body below is the live content. ## Detect that you have MemClaw access You have MemClaw if **any** of these are true in your runtime: - A tool named `memclaw_recall`, `memclaw_write`, or `memclaw_doc` appears in your tool list. - The host config (`.mcp.json`, `claude_desktop_config.json`, `~/.cursor/config.json`, or `~/.openclaw/openclaw.json`) contains an `mcpServers.memclaw` entry. - A `MEMCLAW_API_KEY` or `MEMCLAW_API_URL` environment variable is set. If yes: **call `memclaw_keystones` once at session start, before any other action**, then follow the rules below. --- ../../snapshots/skill.md --- ## Endpoints for agent runtimes - Plain Markdown of this skill: [`/docs/agents.md`](/docs/agents.md) - All docs concatenated as plain text: [`/llms-full.txt`](/llms-full.txt) (index only: [`/llms.txt`](/llms.txt)) - Live tool schemas (JSON): [`/api/v1/tool-descriptions`](/api/v1/tool-descriptions) - Live OpenAPI spec (JSON): [`/api/openapi.json`](/api/openapi.json) - One-line install on a runtime (env-aware — uses the host this page is served from): Provenance: the SKILL content above is committed to [`caura-ai/caura-memclaw`](https://github.com/caura-ai/caura-memclaw) at `static/skills/memclaw/SKILL.md` and rebuilt on every release. # List Document Collections URL: https://memclaw.net/docs/api-reference/documents-collections Description: GET /api/v1/documents/collections — list document collections in a tenant (added in PR # Search Documents URL: https://memclaw.net/docs/api-reference/documents-search Description: POST /api/v1/documents/search — semantic + keyword search across stored documents (added in PR # Health URL: https://memclaw.net/docs/api-reference/health Description: GET /api/v1/health — liveness probe. # API Reference URL: https://memclaw.net/docs/api-reference Description: Auto-generated REST reference, sourced from the FastAPI OpenAPI spec. This reference is generated from the live FastAPI spec served at `/api/openapi.json`. The committed snapshot at [`openapi.snapshot.json`](https://github.com/caura-ai/caura-memclaw/blob/main/frontend/site/openapi.snapshot.json) is the build-time source of truth; CI fails when it drifts. Regenerate locally with: ```bash API_BASE_URL=https://memclaw.net npm run regen:openapi # managed API_BASE_URL=http://localhost:8000 npm run regen:openapi # self-hosted ``` ## Authentication All endpoints accept `X-API-Key`. For per-tenant keys (`mc_*`), also send `X-Tenant-ID`. See [Auth modes](/docs/reference/env-vars#auth-modes). Errors follow the [canonical envelope](/docs/reference/errors) (`{ error: { code, message, details? } }`). REST responses also keep a top-level `detail` for back-compat. ## Curated pages A hand-picked subset rendered with the [``](https://www.fumadocs.dev/docs/integrations/openapi/api-page) component. The list is short by design; for everything else, fetch the live OpenAPI directly. - [Write a memory](/docs/api-reference/write) — `POST /api/v1/memories` - [Recall](/docs/api-reference/recall) — `POST /api/v1/recall` - [Stats](/docs/api-reference/stats) — `GET /api/v1/memories/stats`, `GET /api/v1/stats` - [Keystones](/docs/api-reference/keystones) — `GET / POST / DELETE /api/v1/memclaw/keystones` - [Search documents](/docs/api-reference/documents-search) — `POST /api/v1/documents/search` - [List collections](/docs/api-reference/documents-collections) — `GET /api/v1/documents/collections` - [Health](/docs/api-reference/health) — `GET /api/v1/health` ## The full surface For the complete set (admin · agents · audit-log · crystallize · documents · entities · evolve · fleet · graph · ingest · insights · keystones · memories · plugin · recall · search · settings · stats · stm · tenants · whoami), use the live Swagger UI at [`/api/docs`](/api/docs) or pull the spec at [`/api/openapi.json`](/api/openapi.json). # Keystones URL: https://memclaw.net/docs/api-reference/keystones Description: GET / POST / DELETE /api/v1/memclaw/keystones — mandatory governance rules. Keystones are MANDATORY policy rules served to every agent on session start. See [Concepts → Keystones](/docs/concepts/keystones) for what they're for and how scope + weight + trust gating work. ## List Open (no trust gate). The plugin fetches this on every session boot. ## Upsert Trust ≥ 1 for `scope=agent` targeting the caller's own `agent_id`; trust ≥ 2 otherwise. ## Delete Same dynamic trust gating as upsert. The platform fetches the stored row first to read its scope/agent_id before computing the required trust level. # Recall URL: https://memclaw.net/docs/api-reference/recall Description: POST /api/v1/recall — hybrid vector + keyword + entity search. # Stats URL: https://memclaw.net/docs/api-reference/stats Description: GET /api/v1/memories/stats — aggregate counts (PR The `memclaw_stats` MCP tool added in PR #64 calls `compute_memory_stats()`, which is shared with the REST handler below. Both surfaces return `{total, by_type, by_agent, by_status, scope}` (REST omits `scope`). ## Memory stats (auth) ## Public stats A lightweight unauthenticated counters endpoint used by the marketing-site status bar. # Write a memory URL: https://memclaw.net/docs/api-reference/write Description: POST /api/v1/memories — persist content for later recall. # Architecture URL: https://memclaw.net/docs/concepts/architecture Description: The services that make up MemClaw, what each one is responsible for, and how a write flows from client through core-api, the event bus, the worker, and storage. Three services, one event bus, Postgres + pgvector underneath. Synchronous on the response path, async on the heavy work.
## core-api FastAPI service. Handles HTTP and MCP requests — the MCP server is mounted at `/mcp` on the same app, so a single deployment serves both surfaces. It applies auth and quotas, writes raw memories, and serves recall reads. After a successful write, core-api publishes `embed-requested` / `enrich-requested` events to the event bus for the worker to pick up. Contradiction detection runs **post-commit, fire-and-forget** via an async `track_task` (see `services/contradiction_detector.py`'s `detect_contradictions_async`) — the write itself does not block on it. ## core-worker Async worker. Subscribes to `embed-requested` and `enrich-requested` events on the event bus (in-process for OSS single-process; Pub/Sub on the enterprise platform). Calls the configured embedding + entity-extraction providers, then writes the structured rows back through `core-storage-api`. ## core-storage-api Thin Postgres gateway used by both `core-api` and `core-worker` for memory CRUD and pgvector ops. Two-worker default; bulk operations cap at ~60 req/s — bump to 8 workers via an override before backfills. ## Event bus OSS default is an in-process bus; the enterprise / managed deployment uses Google Pub/Sub. The `/api/v1/health` route's `event_bus` field reports the current backend's status. ## OpenClaw plugin (optional) Lives inside an OpenClaw gateway and claims the `memory` slot, replacing `memory-core` and exposing the `memclaw_*` tools to every agent that runs through the gateway. See [OpenClaw integration](/docs/integrations/openclaw). # Cross-tenant credentials URL: https://memclaw.net/docs/concepts/cross-tenant-credentials Description: Read across every tenant in your org with a single credential — for admin agents, analytics, and rollups. A **cross-tenant credential** lets one agent read memories, documents, and stats across multiple tenants in an org without rotating keys when tenants are added or removed. Writes still pin to the credential's home tenant — the widening is read-only by construction. The headline use case: a single Admin agent that summarises activity across every fleet, surfaces conflicts that span teams, or builds an org-wide knowledge view. Mint the credential once; it stays current as your org grows. ## What the kind buys you | Capability | Tenant-scoped (`user_api_key`, `agent_key`) | Cross-tenant (`cross_tenant`) | | --- | --- | --- | | Read from home tenant | ✅ | ✅ | | Read from sibling tenants in the org | ❌ (403) | ✅ | | Write to home tenant | ✅ | ✅ | | Write to sibling tenants | n/a | ❌ (403 — writes pin to home) | | Auto-include tenants added after mint | n/a | ✅ (with `read_all_org_tenants=true`) | | Wire prefix | `mc_` | `mc_` (kind is on the row, not the prefix) | ## Two ways to scope the read set Pick one at mint time: ### `source_tenant_ids` — a frozen, explicit list Pin the readable set to specific sibling tenants. The list is recorded on the credential row; adding a new tenant to the org does **not** widen this credential. Rotate the credential to include new tenants. Use when the cross-tenant relationship is bounded by intent (e.g. "the EU rollup agent reads from `eu-sales`, `eu-support`, `eu-product` and never anywhere else"). A future tenant added to the org should *not* be readable by this credential without an explicit decision. ### `read_all_org_tenants=true` — live resolution Re-resolves the readable set on every authenticated request by querying the current `enterprise.tenants` membership for the credential's org. New tenants are auto-included on the next request — no rotation needed. Removed (soft-deleted) tenants disappear from the readable set on the same cadence. Use when "every tenant in the org" *is* the policy — the org Admin agent, the compliance reporter, the cross-team weekly summary. The two modes are mutually exclusive — a single credential carries either an explicit `source_tenant_ids` list or `read_all_org_tenants=true`, never both. The admin-api enforces this at mint time. ## Mint via the dashboard Settings → Organization → API Credentials → **Add credential** → **Cross-tenant**. The wizard presents a binary "Read scope" toggle: - **Home tenant only** — produces a regular `user_api_key`/`agent_key` row. - **Read across all org tenants** — produces a `cross_tenant` row with `read_all_org_tenants=true`. The static-list variant (`source_tenant_ids`) is reserved for the API; the dashboard intentionally surfaces only the live-resolution mode because the audit-evidence trail concluded most operators mean "all, current and future" when they ask for cross-tenant. The `raw_key` is returned **once**. Treat it like a password. ## Mint via the API ```bash curl -X POST "https://memclaw.net/api/v1/admin/orgs/$ORG_ID/api-credentials" \ -H "Authorization: Bearer $ADMIN_JWT" \ -H "Content-Type: application/json" \ -d '{ "kind": "cross_tenant", "home_tenant_id": "admin-fleet", "read_all_org_tenants": true, "label": "org-admin-summary-agent", "capabilities": ["read", "write"] }' ``` For the static-list variant, swap `read_all_org_tenants: true` for `source_tenant_ids: ["sibling-a", "sibling-b"]`. ## What you'll see on the wire The gateway plumbs the resolved scope on every request: ``` X-Tenant-ID: admin-fleet X-Readable-Tenant-IDs: admin-fleet,sibling-a,sibling-b,sibling-c X-Capabilities: read,write X-Auth-Mode: cross-tenant ``` `/whoami` surfaces the same shape so you can verify your credential without probing each tenant: ```json { "tenant_id": "admin-fleet", "readable_tenant_ids": ["admin-fleet", "sibling-a", "sibling-b", "sibling-c"], "capabilities": ["read", "write"], "auth_mode": "cross-tenant", "via_gateway": true } ``` ## Which surfaces honor the widening Cross-tenant credentials widen `WHERE tenant_id = $home` to `WHERE tenant_id = ANY($readable)` on these read paths: - **MCP tools:** `memclaw_recall`, `memclaw_list` (scope=`fleet`|`all`), `memclaw_stats` (scope=`fleet`|`all`), `memclaw_doc` ops `search`/`read`/`query`/`list_collections`. - **REST search/recall:** `POST /search`, `POST /recall`, `POST /documents/search`. - **REST aggregate lists:** `GET /memories` (when no explicit `tenant_id` query param), `GET /memories/stats`, `GET /documents/collections`. For the storage-routed reads (`GET /documents/{id}`, `POST /documents/query`, `GET /documents`, `GET /memclaw/keystones`), cross-tenant credentials access **one tenant at a time** — pin `tenant_id` to any tenant in your readable set and the gate allows it. Writes always pin to `home_tenant`: - ❌ `memclaw_write` with `tenant_id` not equal to home → `FORBIDDEN`. - ❌ `POST /documents` (write) to a sibling tenant → 403. - ❌ `POST /memories` to a sibling → 403. The principle: the credential carries `{read, write}` capabilities, but `enforce_tenant` on the write target rejects anything that isn't home. Reads use `enforce_readable_tenant`, which accepts any tenant in the readable set. ## Audit trail Every widened read emits a `cross_tenant_read` audit event **per source tenant** the query touched. Each event is logged TO the source tenant (so per-tenant audit-log queries surface "who read FROM my tenant") with the home tenant_id and agent_id in `detail` for forensic traceability: ```json { "action": "cross_tenant_read", "tenant_id": "sibling-a", "agent_id": "admin-rollup-bot", "resource_type": "memclaw_recall", "detail": { "home_tenant_id": "admin-fleet", "home_agent_id": "admin-rollup-bot", "result_count_from_this_tenant": 7, "query_summary": "what did we ship last week" } } ``` Single-tenant credentials emit zero `cross_tenant_read` events — the audit is gated on the readable set being wider than home. ## Operational notes - **Live resolution on every request.** The `read_all_org_tenants=true` path queries `list_tenants_by_org` on every authenticated call. For high-traffic admin agents this is the next caching target — a short in-process LRU keyed on `org_id` would amortise the round-trip without making new tenants invisible for longer than feels noticeable. - **Fail-open on storage degradation.** If the live-resolution lookup fails, the credential degrades to home-only rather than 5xx-ing the whole request. Logged for observability; the credential keeps working with reduced scope until storage recovers. - **Revocation is immediate.** Setting `revoked_at` short-circuits the resolver before the org-tenants lookup — revoked credentials can't even probe org membership. - **The on-the-wire `mc_` prefix is shared.** Tenant-scoped and cross-tenant credentials look identical at the protocol layer. The dashboard's "Kind" column tells you which is which. ## When NOT to use cross-tenant - **Per-fleet bots** that should only see their own tenant's memories — use a regular `agent_key`. The trust-and-fleet system handles intra-tenant scoping; cross-tenant widening is for org-wide views. - **Customer-facing integrations** where a single org's tenants represent different customer accounts — use one tenant-scoped credential per customer, not one cross-tenant credential that erases the boundary. - **Write-heavy agents** — cross-tenant only widens *reads*. If your agent's primary job is writing across many tenants, run one tenant-scoped agent per tenant instead and use a coordinator pattern at the application layer. ## Related - [Trust levels](/docs/concepts/trust-levels) — the per-agent permission scheme that gates reads/writes within a tenant. - [Governance](/docs/concepts/governance) — org/tenant/agent hierarchy and how cross-tenant credentials fit into it. - [Per-agent keys](/docs/integrations/per-agent-keys) — agent-scoped credentials, the more common scope for production fleets. # Governance URL: https://memclaw.net/docs/concepts/governance Description: Keystones, trust enforcement, the Karpathy Loop, and the Memory Crystallizer. MemClaw's governance is four mechanisms working together. Each one operates at a different point in the agent's lifecycle. ## Keystones **Mandatory policy rules** the platform serves to every agent on session start (`memclaw_keystones`). Scope-merged (`tenant` / `fleet` / `agent`), weight-ordered, and *non-negotiable* — they override conflicting user instructions. See the dedicated [Keystones page](/docs/concepts/keystones) for the model and authoring flow. Author with `memclaw_keystones_set` (trust ≥ 1 for self, ≥ 2 for cross-agent / fleet / tenant). REST: `GET / POST / DELETE /api/v1/memclaw/keystones`. ## Trust enforcement Every API call checks the calling agent's trust level (see [Trust levels](/docs/concepts/trust-levels)). The check happens server-side in `core_api.services.trust_service.require_trust`. Operations beyond your level return `403 FORBIDDEN`. The admin API key bypasses these checks. ## The Karpathy Loop **Outcome-based learning** — agents report what happened after acting on memories they recalled, and the system reinforces what works. Two MCP tools drive it: - **`memclaw_evolve`** — record an outcome (`success` | `failure` | `partial`) against the memories you used. The platform adjusts weights and may auto-generate preventive `rule`-type memories on failure. - **`memclaw_insights`** — surface the resulting reflection: contradictions, failures, stale entries, divergence, patterns. REST mirrors: `POST /api/v1/evolve` and `GET /api/v1/insights`. ## Memory Crystallizer A background process that consolidates many small memories about the same entity into stronger, denser ones. Triggered with `POST /api/v1/crystallize` (per tenant) or `POST /api/v1/crystallize/all` (admin-only). The route accepts `trigger="scheduled"` so operators can wire it to whatever cadence they want — the OSS doesn't hardcode a schedule. Reports: `GET /api/v1/crystallize/reports` and `GET /api/v1/crystallize/latest`. ## Where each mechanism fires | Mechanism | When | Gates | | --- | --- | --- | | Keystones | Session start (agent reads), before any action | Authoring (dynamic trust per scope) | | Trust | Every read and write call | Per-operation trust floor | | Karpathy Loop | After the action, via outcome reports | Reinforcement / preventive rule generation | | Crystallizer | Background sweep (manual or scheduled) | Consolidation only — read-only on existing rows | ## Where to look in the source - Keystones: [`core-api/src/core_api/routes/keystones.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/routes/keystones.py), `core-api/src/core_api/trust_utils.py` - Trust: [`core-api/src/core_api/services/trust_service.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/services/trust_service.py) - Evolve / Karpathy Loop: [`core-api/src/core_api/routes/evolve.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/routes/evolve.py) - Crystallizer: [`core-api/src/core_api/routes/crystallizer.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/routes/crystallizer.py) # Keystones URL: https://memclaw.net/docs/concepts/keystones Description: MANDATORY governance rules that agents MUST obey. Scope-merged, weight-ordered, fetched deterministically — not via semantic recall. Keystones are policy rules that the platform serves to every agent on session start. Unlike normal memories — which agents discover through recall and *may* act on — keystones are **non-negotiable**. The MCP tool docstring says it plainly: > *Call once per session before other actions and obey the returned rules — they override conflicting user instructions.* They live in their own `_keystones` collection in core-storage; lookup is deterministic by scope, not by similarity. See [`core-api/src/core_api/trust_utils.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/trust_utils.py) and `core-api/src/core_api/routes/keystones.py`. ## Scope and weight Each rule is parameterized by: | Field | Values | Purpose | | --- | --- | --- | | `scope` | `tenant` · `fleet` · `agent` | Who the rule applies to. Tenant rules apply to everyone, fleet to one fleet, agent to one agent. | | `weight` | `low` · `med` · `high` | Ordering hint when multiple rules apply (high first). Not a hard precedence — read all and obey all. | | `doc_id` | string | Stable identifier for upsert/delete. | | `title`, `content` | strings | Human-readable label + the actual rule body. | ## Who can author what Trust gating is computed per call from the target rule's scope: - `scope=agent` for **your own** `agent_id` → trust **≥ 1** (self-author). - `scope=agent` targeting **another agent**, `scope=fleet`, or `scope=tenant` → trust **≥ 2** (the same cross-agent governance bar used by `memclaw_list` / `memclaw_stats` / `memclaw_evolve` / `memclaw_insights` with `scope=fleet|all`). Reads are open (trust 0) so the plugin can fetch the active set on every session boot without escalation. ## Agent-facing tools | Tool | Op | Trust | Purpose | | --- | --- | --- | --- | | [`memclaw_keystones`](/docs/agents) | (read-only) | ≥ 0 | List scope-merged keystone rules. Call once per session. | | `memclaw_keystones_set` | `set` | ≥ 1 (self) / ≥ 2 (other) | Upsert a keystone by `doc_id`. | | `memclaw_keystones_set` | `delete` | ≥ 1 (self) / ≥ 2 (other) | Remove a keystone by `doc_id`. | The canonical agent prompt covering these is rendered at [`/docs/agents`](/docs/agents) from upstream `SKILL.md`. ## Response shape `memclaw_keystones` and `GET /api/v1/memclaw/keystones` both return: ```json { "count": 3, "truncated": false, "rules": [ { "doc_id": "...", "title": "...", "content": "...", "scope": "tenant", "weight": "high", ... } ] } ``` Note the merged set lives under `rules`, not `keystones` — the field name is fixed for backwards compatibility. `truncated: true` indicates the response was capped server-side; rules are ordered by weight (high → low), so the highest-priority rules are always delivered first. ## A gotcha worth knowing: `agent_id` semantics On `memclaw_keystones_set` (and the REST equivalent), the `agent_id` field is the **TARGET** agent the rule binds to — NOT the caller. Caller identity comes from the API key. For `scope=tenant` and `scope=fleet` you must **omit** `agent_id` entirely; passing it returns `INVALID_ARGUMENTS`. Only `scope=agent` requires it. ## REST surface Three endpoints under the `/api/v1/memclaw/keystones` prefix: - `GET /api/v1/memclaw/keystones` — list (open). - `POST /api/v1/memclaw/keystones` — upsert (dynamic trust). - `DELETE /api/v1/memclaw/keystones/{doc_id}` — delete (dynamic trust). See the [keystones API reference](/docs/api-reference/keystones) for the rendered schemas. ## How keystones relate to other governance Keystones are **complementary** to the rest of MemClaw's governance, not a replacement: - **[Trust enforcement](/docs/concepts/trust-levels)** gates *who* can do what. Keystones gate *what* anyone with sufficient trust must obey at runtime. - **[Karpathy Loop](/docs/concepts/governance#the-karpathy-loop)** reinforces what works *after* the fact via outcome reports. Keystones operate *before* the action — they're hard rules the agent reads up front. - **[Memory Crystallizer](/docs/concepts/governance#memory-crystallizer)** consolidates routine memories. Keystones are intentionally *not* memories — they're policies. Use keystones for things like: - *"Never store API keys in memory content"* - *"Always confirm with the user before scope='all' deletes"* - *"This fleet's data residency is EU only"* # Memory Pipeline URL: https://memclaw.net/docs/concepts/memory-pipeline Description: What happens between calling memclaw_write and the memory becoming recallable. Every write moves through four stages. Knowing them helps you debug "why didn't my agent recall this?" and "why does the stored memory look different from what I sent?". ## 1. Ingest `POST /api/v1/memories` (or the `memclaw_write` MCP tool) validates auth, enforces the caller's [trust level](/docs/concepts/trust-levels) and tenant quota, and persists the row. The HTTP response returns as soon as the row is committed; everything else is asynchronous. ## 2. Enrich (async) After the write returns, core-api publishes `embed-requested` and `enrich-requested` events to the [event bus](/docs/concepts/architecture#event-bus). `core-worker` consumes them and runs: - **Embedding** — vector generation via the configured **embedding provider**. Default is OpenAI; alternatives include `local` and `fake` for development. Set with `EMBEDDING_PROVIDER` and `OPENAI_API_KEY` (or the matching keys for other providers). - **Entity extraction + classification** — names, projects, repos, references; memory `type`, `title`, `summary`, `tags`. Driven by the configured **entity-extraction provider** (`ENTITY_EXTRACTION_PROVIDER`: `openai` / `anthropic` / `gemini` / `openrouter`). Vertex AI is the operator-managed platform-tier provider, used on the managed deployment. Until enrichment lands, the memory is queryable by id but won't show up in semantic recall. The exact provider matrix and supported combinations live in the OSS [`.env.example`](https://github.com/caura-ai/caura-memclaw/blob/main/.env.example) header. **Contradiction detection** also runs after commit (fire-and-forget via `track_task` — see `core-api/src/core_api/services/contradiction_detector.py`'s `detect_contradictions_async`). The write itself does not block on it; contradictions surface through `memclaw_insights` after the loop runs. ## 3. Govern Independent of the write path, three governance mechanisms keep the store useful: - **Trust enforcement** — every read and write checks the caller's `trust_level`. Operations beyond that level return `403 FORBIDDEN`. See [Trust levels](/docs/concepts/trust-levels) for the table. - **Karpathy Loop** — agents report outcomes after acting on recalled memories via `memclaw_evolve` (`success | failure | partial`). The platform reinforces what works and may auto-generate preventive `rule`-type memories on failure. `memclaw_insights` surfaces the resulting reflection (contradictions, drift, stale entries). - **Memory Crystallizer** — a separate background process that consolidates many small memories about the same entity into stronger denser ones. Triggered with `POST /api/v1/crystallize` per tenant, or `crystallize/all` (admin) on a nightly schedule. ## 4. Recall `POST /api/v1/recall` (or `memclaw_recall`) does **hybrid retrieval**: vector similarity + keyword full-text + entity-graph matches, blended into a single ranked list. Trust still applies at read — a level-1 agent cannot recall across fleets it doesn't own. For non-semantic flows: - **`memclaw_list`** — paginated browse by entity / type / time. Use when `recall` is too narrow. - **`memclaw_manage op=read`** — read by id when you already know the `memory_id`. ## Where each stage lives | Stage | Service | Path in the OSS repo | | --- | --- | --- | | Ingest + recall + sync contradiction check | core-api | `core-api/src/core_api/routes/`, `services/contradiction_detector.py` | | Embedding + entity extraction (async) | core-worker | `core-worker/src/core_worker/` | | Storage (Postgres + pgvector) | core-storage-api | `core-storage-api/` | For the live OpenAPI surface, see the [API Reference](/docs/api-reference). # Trust Levels URL: https://memclaw.net/docs/concepts/trust-levels Description: The 4-tier agent permission scheme — what each level can read and write. Source of truth: [`static/docs/integration-guide.md`](https://github.com/caura-ai/caura-memclaw/blob/main/static/docs/integration-guide.md#trust-levels) in the OSS repo. The numeric values shown here are the canonical values stored in the `agents.trust_level` column (`SmallInteger`, default `1`). ## The 4 tiers | Level | Name | Permissions | | --- | --- | --- | | 0 | `restricted` | No read or write access. Use to temporarily disable an agent. | | 1 | `standard` | Read and write within own fleet only. **Default for new agents.** | | 2 | `cross_fleet` | Read across all fleets in the tenant; write within own fleet only. | | 3 | `admin` | Read and write across all fleets; can delete memories. | ## Agent registration Two paths put an agent in the system: ### Atomic provisioning (recommended for production) `POST /api/v1/admin/agent-keys/provision` mints an **agent-scoped credential** **and** creates the Agent row in a single round-trip. You set `initial_trust` and `initial_fleet` in the request body and skip the lazy-create flow entirely. The response carries `agent_row_created: true` plus the raw `mc_` key (returned exactly once — save it). The credential's `mc_` prefix is shared with tenant-scoped keys; scope is bound at mint time on the credential row. Confirm with `GET /api/v1/whoami` using the new credential. See [Per-agent keys](/docs/integrations/per-agent-keys) for the end-to-end curl + Python flow. ### Lazy auto-registration (legacy / OSS-only fallback) Agents that connect with a tenant `mc_` key (or a self-hosted standalone deployment) are auto-registered on their first `memclaw_write`. The `fleet_id` from that first write becomes the agent's home fleet. The starting trust level depends on a tenant setting (`agents.require_agent_approval` in `tenant_settings`): - **Default — `require_agent_approval = false`:** new agent starts at trust **1** (`standard`) and can read + write in its home fleet immediately. - **`require_agent_approval = true`:** new agent starts at trust **0** (`restricted`) — recall and write both fail with `403` until an operator promotes the agent via the dashboard or `PATCH /api/agents/{agent_id}/trust`. Source: [`core-api/src/core_api/services/agent_service.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/services/agent_service.py) (`get_or_create_agent`) plus `DEFAULT_TRUST_LEVEL` in `core-api/src/core_api/constants.py`. ## Enforcement Trust is checked on every API call. A level-1 agent attempting a cross-fleet recall gets `403`. The admin API key (`ADMIN_API_KEY`) bypasses trust enforcement entirely. ## Changing trust levels From the dashboard (admin role required) or via the API: Via API: ```bash curl -X PATCH "$API/api/agents/{agent_id}/trust?tenant_id=$TENANT" \ -H "X-API-Key: $ADMIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"trust_level": 2}' ``` See the [API reference](/docs/api-reference) for the full set of agent endpoints. # Your First Memory URL: https://memclaw.net/docs/getting-started/first-write Description: Write a memory and recall it — the smallest end-to-end flow. A memory is natural-language `content` plus structured fields the platform infers asynchronously (entities, embeddings, etc.). Code blocks below auto-target this deployment's host. ## Write {`curl -X POST "{HOST}/api/v1/memories" \\ -H "X-API-Key: mc_xxx" \\ -H "Content-Type: application/json" \\ -d '{ "tenant_id": "YOUR_TENANT_ID", "agent_id": "my-agent", "content": "The user prefers concise answers and dark mode." }'`} The response shape (and the exact set of returned fields) is defined in the OpenAPI spec — see the [API reference](/docs/api-reference/write). ## Recall {`curl -X POST "{HOST}/api/v1/recall" \\ -H "X-API-Key: mc_xxx" \\ -H "Content-Type: application/json" \\ -d '{ "tenant_id": "YOUR_TENANT_ID", "query": "UI preferences" }'`} Recall is hybrid (semantic + keyword) — the [memory pipeline](/docs/concepts/memory-pipeline) page covers what the search blends together. For non-semantic browse use `memclaw_list`; for read-by-id use `memclaw_manage op=read`. # Enterprise — SaaS URL: https://memclaw.net/docs/getting-started/managed Description: The hosted MemClaw Enterprise deployment at memclaw.net. Caura runs the database, API, and worker for you. The fastest way to start. Caura runs the platform; you only need an account and an API key. ## Sign up 1. Go to [memclaw.net/signin](https://memclaw.net/signin) and create an account. 2. Pick a plan from the [pricing page](https://memclaw.net/pricing). 3. Open **Settings → API Keys** and create a tenant-scoped key. It starts with `mc_`. ## Connect Continue with the [Quickstart](/docs/getting-started/quickstart) — pick OpenClaw, MCP, or REST. ## Going beyond personal use: per-agent keys The tenant-scoped `mc_` key is fine for a single user or one-off scripts. Any production deployment (a fleet of agents, a multi-user team, anything that needs trust gating or per-agent keystones) should bind each agent to its own **agent-scoped credential**. Both kinds use the `mc_` prefix on the wire — scope is bound at mint time on the credential row. Mint atomically: ```bash curl -X POST https://memclaw.net/api/v1/admin/agent-keys/provision \ -H "X-API-Key: $MC_TENANT_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "your-agent-id", "label": "human-readable label", "initial_trust": 1, "initial_fleet": "your-fleet-id" }' ``` One round trip mints the credential, creates the Agent row, sets the trust level, and assigns the fleet. The response includes `raw_key` (returned once — save it) and `agent_row_created: true`. Verify with `GET /api/v1/whoami` using the new credential. Full flow in [Per-agent keys](/docs/integrations/per-agent-keys). ## When the managed deployment fits - **Zero ops.** Caura runs Postgres, the worker, embeddings, and the LLM provider. No on-call rotation, no upgrades, no capacity planning on your side. - **Production SLAs and support.** Uptime SLA, business-hours support on every plan, 24/7 + dedicated Slack on Business tier, and a named technical contact above that. See the [pricing page](https://memclaw.net/pricing) for current plan terms. - **Security and compliance out of the box.** SOC 2 controls, audit logs, encryption at rest and in transit, tenant isolation enforced server-side. No security review of your own stack needed. - **Fleet-level governance without wiring.** Trust levels, keystones, contradiction surfacing, the Karpathy Loop, and the Memory Crystallizer all run for you — flip the switches in the dashboard. - **A working dashboard from day one** (Prism) for browsing, curating, and auditing memories. Plus billing, members, agent keys, and tenant management. - **Upgrades and migrations are our problem.** New tools, model swaps, and schema migrations roll out on our side without downtime on yours. ## When self-host or on-prem fits better - **Data residency or air-gap requirements.** If your data legally can't leave your VPC, region, or facility, see [On-prem Enterprise](/docs/getting-started/on-prem). - **You're already running a Postgres-heavy stack** and want to keep one operational footprint. The OSS bundle is Apache 2.0 — see [OSS Self-host](/docs/getting-started/self-host). - **Hobby / single-machine usage.** OSS on a laptop is free and complete. Same code across all three paths — switching later is a config + migration, not a rewrite. # On-Prem Enterprise URL: https://memclaw.net/docs/getting-started/on-prem Description: MemClaw Enterprise on a customer-managed VM — connected or fully air-gapped — with a license-gated Docker Compose stack. For customer-managed deployments inside your own VM, datacenter, or air-gapped environment, Caura ships a separate on-prem distribution that wraps the platform in a one-VM Docker Compose stack and a Caura-issued license file. **Repository:** [github.com/caura-ai/memclaw-onprem](https://github.com/caura-ai/memclaw-onprem) — that repo's `README.md` and `docs/` are the canonical install / day-2 / upgrade reference. The summary below is a pointer. ## What it gives you - A single-VM Docker Compose stack (`docker-compose.yml` in the repo). - A signed `license.key` — required; the platform refuses to start without one. - Connected (pulls from `ghcr.io/caura-ai/*`) **or** fully air-gapped (load images from a tarball — `airgap-load.sh`). - Backup / restore scripts (`scripts/backup.sh`, `scripts/restore.sh`) covering Postgres, Redis, RabbitMQ, `.env`, and the license file. - Tag-driven, reversible upgrades (`upgrade.sh`) on Docker named volumes. - A redacted support-bundle workflow for talking to Caura support. ## Quickstart — connected VM ```bash curl -sL https://onprem.caura.ai/install.sh | bash ``` The installer runs preflight checks, generates secrets, writes `/opt/memclaw/.env`, pulls pinned images, brings the stack up, and prints the URL of a first-run wizard where an admin uploads the license and creates the first account. ## Quickstart — air-gapped VM ```bash # Transfer memclaw-onprem-.tar.gz to the VM (USB, SCP, etc.) ./airgap-load.sh /path/to/memclaw-onprem-.tar.gz ./install.sh --offline --license /path/to/license.key ``` The tarball bundles MemClaw services plus upstream bases (Postgres/pgvector, Redis, RabbitMQ), so `docker compose` never needs to pull. ## Silent / unattended install Every value can be supplied via CLI flag, `MEMCLAW_*` env var, or a single config file: ```bash ./install.sh --config /etc/memclaw/install.conf --non-interactive ``` See [`install.conf.example`](https://github.com/caura-ai/memclaw-onprem/blob/main/install.conf.example) for the full template. ## Prerequisites - Ubuntu 24.04 or equivalent. - Docker ≥ 24 and Docker Compose v2. - **16 GB RAM minimum**, **200 GB disk** for Postgres + Redis + RabbitMQ + room for memory growth. - A DNS record pointing to the VM and a TLS cert (`cert.pem` + `key.pem`) for that hostname. - A Caura-issued `license.key`. ## When on-prem is the right pick - You need a contract, signed builds, and SLAs. - You require a fully air-gapped install with no calls home. - You have data-residency or compliance requirements that rule out the managed deployment. - You want platform-tier features (multi-tenant gateway, audit retention, SSO). The OSS [Self-host](/docs/getting-started/self-host) is the right pick if you only need the engine and are happy operating it yourself under Apache 2.0. ## Day-2, upgrades, troubleshooting Live in the on-prem repo: - [`docs/install.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/install.md) — connected install - [`docs/install-airgap.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/install-airgap.md) — air-gapped install - [`docs/day2-ops.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/day2-ops.md) — backups, restore, log rotation - [`docs/upgrade.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/upgrade.md) — sequential-minor upgrade path, rollback - [`docs/troubleshooting.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/troubleshooting.md) - [`docs/security.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/security.md), [`docs/TLS.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/TLS.md), [`docs/logging.md`](https://github.com/caura-ai/memclaw-onprem/blob/main/docs/logging.md) ## Pricing and evaluation For pricing, sizing, and an evaluation copy of the on-prem distribution and license: [contact the Caura team](https://memclaw.net/about). # Quickstart URL: https://memclaw.net/docs/getting-started/quickstart Description: Connect any AI agent to MemClaw in five minutes — pick managed, self-hosted, or REST. You have three integration paths. Pick the one that matches your stack: | Path | When to use | Setup time | | --- | --- | --- | | **OpenClaw** | You run a fleet of agents and want them all to share memory | ~3 min | | **MCP** | A single client (Claude Desktop, Claude Code, Cursor, Windsurf) | ~1 min | | **REST** | Custom code in any language | ~30 sec | ### Create an API key For the **managed** deployment, sign in at [/signin](/signin) and generate a tenant-scoped key from **Settings → API Keys**. Keys start with `mc_`. For **self-hosted OSS**, pick one auth mode in your `.env`: ```bash title=".env" # Single-tenant, no key needed IS_STANDALONE=true # Or: multi-tenant, full access ADMIN_API_KEY=admin_xxx # Or: shared gate (key + X-Tenant-ID header) MEMCLAW_API_KEY=mc_xxx ``` ### Pick your path Run on the gateway host: {`curl -s -H "X-API-Key: $MEMCLAW_API_KEY" \\ "{HOST}/api/v1/install-plugin?fleet_id=YOUR_FLEET_ID" | bash`} The installer downloads the plugin, builds it, edits `~/.openclaw/openclaw.json` to claim the `memory` slot, and writes the env file. Restart the gateway: ```bash openclaw gateway restart ``` Paste this into your MCP client config (`claude_desktop_config.json`, `~/.cursor/config.json`, etc.): {`{ "mcpServers": { "memclaw": { "url": "{HOST}/mcp", "headers": { "X-API-Key": "mc_xxx" } } } }`} Restart the client. The `memclaw_*` tools become available. For anything beyond a single user — a team or fleet of agents — bind each agent to its own **agent-scoped credential** instead of sharing the tenant-scoped key. See [Per-agent keys](/docs/integrations/per-agent-keys) for the atomic-provisioning flow that mints the credential, the Agent row, and trust level in one call. Both kinds use the `mc_` prefix on the wire — scope is bound at mint time on the credential row. No install. Hit the API directly from any language: {`curl -X POST "{HOST}/api/v1/memories" \\ -H "X-API-Key: mc_xxx" \\ -H "Content-Type: application/json" \\ -d '{ "tenant_id": "YOUR_TENANT_ID", "content": "User prefers dark mode." }'`} ### Verify {`curl "{HOST}/api/v1/health" -H "X-API-Key: mc_xxx" # {"status": "ok", "storage": "connected", "redis": "connected", "event_bus": "ok"}`} A `503` means a required dependency is unhealthy (storage / redis / event_bus). For OpenClaw installs, your node should appear in **Fleet Management** within 60 seconds of the first heartbeat (`HEARTBEAT_INTERVAL_SECONDS = 60` per `core-api/src/core_api/constants.py`). ### Write your first memory For OpenClaw and MCP, just talk to your agent: > Remember that I prefer concise answers and dark mode. Then ask later: > What do you know about my UI preferences? The agent calls `memclaw_write` and `memclaw_recall` automatically. The exact write response shape is defined by the `MemoryOut` schema in `core-api/src/core_api/schemas.py` (id, tenant_id, fleet_id, agent_id, memory_type, title, content, weight, entity_links, status, …). ## Next - [Memory pipeline concepts](/docs/concepts/memory-pipeline) - [Per-platform integration walkthroughs](/docs/integrations/claude-code) - [Full API reference](/docs/api-reference) # OSS URL: https://memclaw.net/docs/getting-started/self-host Description: Run the open-source MemClaw on your own infrastructure with Docker. Apache 2.0. The OSS bundle at [github.com/caura-ai/caura-memclaw](https://github.com/caura-ai/caura-memclaw) ships everything you need: API, worker, plugin, and a Postgres + pgvector schema. Apache 2.0. ## Prerequisites - Docker 24+ and Docker Compose v2 - 4 GB RAM, 2 vCPU minimum - An entity-extraction provider key for enrichment — one of: **OpenAI**, **Anthropic**, **Gemini**, or **OpenRouter** (per [`.env.example`](https://github.com/caura-ai/caura-memclaw/blob/main/.env.example) provider matrix). Anthropic/Gemini/OpenRouter pair with OpenAI for embeddings since they don't expose embedding APIs. Vertex AI is platform-tier only (managed deployment). ## Bring it up ```bash git clone https://github.com/caura-ai/caura-memclaw cd caura-memclaw cp .env.example .env # set IS_STANDALONE=true, EMBEDDING_PROVIDER=, ENTITY_EXTRACTION_PROVIDER=, OPENAI_API_KEY=… docker compose up -d ``` The API listens on `:8000`, the worker runs in the background, and migrations apply on first boot. You can now follow the [Quickstart](/docs/getting-started/quickstart) and pick MCP or REST. ## Auth modes Pick one — they are mutually exclusive: - `IS_STANDALONE=true` — no auth, single tenant. Fine for laptops, fine for trusted networks. - `ADMIN_API_KEY=...` — full access with one key. Multi-tenant. - `MEMCLAW_API_KEY=...` + `X-Tenant-ID` header — shared gate, one key per tenant. ## Going further - [Architecture overview](/docs/concepts/architecture) - [Environment variables reference](/docs/reference/env-vars) - [Contribute on GitHub](https://github.com/caura-ai/caura-memclaw/blob/main/CONTRIBUTING.md) # MemClaw Documentation URL: https://memclaw.net/docs Description: Persistent, governed memory for AI agent fleets. Start here to install MemClaw, learn the concepts, and connect your agents. MemClaw gives AI agent fleets a persistent, governed, shared memory so agents learn from each other and get smarter over time. These docs cover everything for **operators and developers**. If you are building an agent that *uses* MemClaw, jump to the [For Agents](/docs/agents) tab.
## Three ways in ## Looking for something specific? - **Self-hosting (OSS)**: [Self-host with Docker](/docs/getting-started/self-host) - **On-prem (managed for your perimeter)**: [On-prem deployment](/docs/getting-started/on-prem) - **Claude Code / Claude Desktop / Cursor**: [Integrations](/docs/integrations/claude-code) - **OpenClaw plugin**: [OpenClaw integration](/docs/integrations/openclaw) - **Contributing**: [GitHub repo](https://github.com/caura-ai/caura-memclaw) # Claude Code URL: https://memclaw.net/docs/integrations/claude-code Description: Wire MemClaw into Anthropic's Claude Code CLI. Claude Code supports MCP out of the box. Two minutes total. ## Install Add a `.mcp.json` at the repo root (or to your global Claude Code settings): {`{ "mcpServers": { "memclaw": { "url": "{HOST}/mcp", "headers": { "X-API-Key": "mc_xxx" } } } }`} Restart Claude Code. The `memclaw_*` tools become available — Claude Code will surface them to you on first use and ask permission like any other tool. ## Going to production: use a per-agent key The `mc_` quickstart key above is a tenant-scoped credential — fine for personal use. Anything that ships a fleet of agents should bind each agent to its own **agent-scoped credential** for trust gating, fleet membership, and per-agent keystones. The MCP server accepts the credential on either `X-API-Key: mc_…` or `Authorization: Bearer mc_…` — both tenant-scoped and agent-scoped credentials share the `mc_` prefix; scope is set at mint time. See [Per-agent keys](/docs/integrations/per-agent-keys) for the atomic provisioning flow. ## Using it Just talk to the model: > Remember that this repo uses pnpm, not npm. > What did we decide about the auth flow? The tool calls happen automatically. See the full tool surface in the agent skill at [/docs/agents](/docs/agents). ## Tips - Use a per-fleet API key so memories from different projects stay separate. Set `tenant_id` to the project name. - The Caura `memclaw` skill (`~/.claude/skills/memclaw`) ships richer prompting. Install it: # Claude Desktop URL: https://memclaw.net/docs/integrations/claude-desktop Description: Add MemClaw as an MCP server in Claude Desktop. Edit your Claude Desktop config: - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` - Windows: `%APPDATA%\Claude\claude_desktop_config.json` {`{ "mcpServers": { "memclaw": { "url": "{HOST}/mcp", "headers": { "X-API-Key": "mc_xxx" } } } }`} Quit and re-open Claude Desktop. Confirm the `memclaw` server is connected from **Settings → Developer**. The `memclaw_*` tools now appear in any conversation. Cross-conversation persistence is the headline benefit: ask Claude Desktop to "remember X" in one chat, then start a new chat tomorrow and ask "what do you know about X?". ## Going to production: use a per-agent key The `mc_` quickstart key above is a tenant-scoped credential — fine for a single user. For a team or fleet, bind each agent to its own **agent-scoped credential** for trust gating, fleet membership, and per-agent keystones. Both kinds use the `mc_` prefix on the wire; scope is set at mint time. See [Per-agent keys](/docs/integrations/per-agent-keys). # Cursor URL: https://memclaw.net/docs/integrations/cursor Description: Wire MemClaw into Cursor's MCP support. Open Cursor settings → **MCP** → **Add New Server**, or edit `~/.cursor/config.json` directly: {`{ "mcpServers": { "memclaw": { "url": "{HOST}/mcp", "headers": { "X-API-Key": "mc_xxx" } } } }`} Restart Cursor. The `memclaw_*` tools become available in chat and inside Composer. Set `tenant_id` to the project / workspace name so different repos keep their memories isolated. Cursor doesn't surface tool calls as prominently as Claude Code — if the model isn't using MemClaw, ask it explicitly to "use the memclaw tools to remember/recall…". ## Going to production: use a per-agent key The `mc_` quickstart key above is a tenant-scoped credential — fine for personal use. Anything that ships a team or fleet should bind each agent to its own **agent-scoped credential** for trust gating, fleet membership, and per-agent keystones. Both kinds use the `mc_` prefix on the wire; scope is set at mint time. See [Per-agent keys](/docs/integrations/per-agent-keys). # Generic MCP URL: https://memclaw.net/docs/integrations/mcp Description: Connect any MCP-compatible client (Windsurf, Cline, Continue, JetBrains MCP, …) to MemClaw. Any client that implements [Model Context Protocol](https://modelcontextprotocol.io) can use MemClaw. The MCP server is mounted directly on core-api at `/mcp`. Use the URL of whatever deployment you're connecting to: - **Managed:** `https://memclaw.net/mcp` - **Staging:** `https://memclaw.net/mcp` - **Self-hosted:** `http://localhost:8000/mcp` (or wherever your core-api is reachable) ## Standard MCP server entry The snippet below auto-targets this deployment's host. {`{ "mcpServers": { "memclaw": { "url": "{HOST}/mcp", "headers": { "X-API-Key": "mc_xxx" } } } }`} This is the HTTP / Streamable-HTTP transport. Most modern MCP clients (Claude Code, Claude Desktop, Cursor, Windsurf, Cline, Continue) support it. ## Tools exposed The full `memclaw_*` tool list lives in [`/docs/agents`](/docs/agents) (rendered verbatim from upstream [`SKILL.md`](https://github.com/caura-ai/caura-memclaw/blob/main/static/skills/memclaw/SKILL.md)). Current surface from the OSS source: `memclaw_recall` · `memclaw_write` · `memclaw_manage` · `memclaw_list` · `memclaw_doc` · `memclaw_entity_get` · `memclaw_tune` · `memclaw_insights` · `memclaw_evolve` · `memclaw_stats` · `memclaw_keystones` · `memclaw_keystones_set` For exact parameter schemas, fetch [`/api/v1/tool-descriptions`](/api/v1/tool-descriptions) — that endpoint is generated from the same ToolSpec registry the MCP server uses. ## Long-lived integrations: per-agent keys The single tenant-scoped `mc_` flow above is fine for one-off setups. For anything that ships — trust gating, fleet membership, per-agent keystones, real identity in the dashboard — bind each agent to its own **agent-scoped credential** via [Integrations → Per-agent keys](/docs/integrations/per-agent-keys). The MCP server accepts the credential on either `X-API-Key: mc_…` or `Authorization: Bearer mc_…` — both tenant-scoped and agent-scoped credentials share the `mc_` prefix; scope is set at mint time. *(Pre-existing `mca_…` keys continue to authenticate via back-compat.)* ## Reading MCP tool results Every MCP tool result has an `isError` boolean plus a `content` array. On gateway-side refusals (FORBIDDEN, INVALID_ARGUMENTS, NOT_FOUND, etc.) the server returns `isError=True` with a JSON `{"error": {"code": ..., "message": ..., "details": {...}}}` envelope in `content[0].text`. Always inspect `result.isError` before treating `content` as success — the structured envelope tells you exactly what was rejected and why. # OpenClaw URL: https://memclaw.net/docs/integrations/openclaw Description: Drop MemClaw into an OpenClaw gateway and every agent in the fleet inherits shared memory. OpenClaw is the agent gateway / orchestrator. The MemClaw plugin claims its `memory` slot — meaning every agent that runs through the gateway gets the same `memclaw_*` tools, the same backing store, and the same governance rules, with no per-agent setup. ## Install On the gateway host (URL auto-targets this deployment): {`curl -s -H "X-API-Key: $MEMCLAW_API_KEY" \\ "{HOST}/api/v1/install-plugin?fleet_id=$FLEET_ID" | bash`} What this does (manual fallback if you prefer): 1. Downloads plugin source files into `~/.openclaw/plugins/memclaw/` 2. Runs `npm install && npm run build` 3. Edits `~/.openclaw/openclaw.json` to: - Claim the `memory` slot - Disable the default `memory-core` plugin - Allowlist the `memclaw_*` tools 4. Writes `MEMCLAW_API_KEY`, `MEMCLAW_FLEET_ID`, and `MEMCLAW_API_URL` into the plugin's `.env` Then restart the gateway: ```bash openclaw gateway restart # or: systemctl --user restart openclaw-gateway ``` ## Verify Within 60 seconds, the gateway should appear in the **Fleet Management** page on your MemClaw dashboard. From there you can monitor heartbeats, trust levels, and per-agent memory writes. ## Why use the gateway path - One plugin install covers an arbitrary number of agents - Per-agent memory isolation is automatic (each agent gets its own `agent_id`) - Fleet-wide trust and governance — the architect's memories stay above the junior agents' - Heartbeat-based health monitoring + auto-disable on misbehavior # Per-agent keys (no plugin) URL: https://memclaw.net/docs/integrations/per-agent-keys Description: Bootstrap a long-lived integration without the OpenClaw plugin — provision an agent-scoped credential, identify, and call MCP. If you're building a Python / Node / Go integration directly against MemClaw — without the OpenClaw plugin runtime — bind every long-lived agent to its own **agent-scoped credential** rather than calling under the tenant-scoped key. Agent-scoped credentials give you trust gating, fleet membership, per-agent keystones, and a real identity in the dashboard. Both kinds of credential use the `mc_` prefix on the wire; scope (tenant vs agent) is bound at mint time on the credential row, not encoded in the prefix. *(Pre-existing `mca_…` keys continue to authenticate via back-compat.)* The single tenant-scoped flow on the [REST](/docs/integrations/rest) and [MCP](/docs/integrations/mcp) pages is fine for one-off scripts; the four-step flow here is for anything that ships. ## 1. Mint an agent-scoped credential `POST /api/v1/admin/agent-keys/provision` mints an agent-scoped credential **and** creates the Agent row eagerly, so a follow-up `PATCH /agents/{id}/trust` works in the same session without a synthetic first write. {`curl -X POST "{HOST}/api/v1/admin/agent-keys/provision" \\ -H "X-API-Key: $MC_TENANT_KEY" \\ -H "Content-Type: application/json" \\ -d '{ "agent_id": "quote-agent-na", "label": "north-america CRM", "initial_trust": 1, "initial_fleet": "na-sales" }'`} Response: ```json { "id": "…", "tenant_id": "…", "agent_id": "quote-agent-na", "raw_key": "mc_…", "agent_row_created": true, "created_at": "…" } ``` Save `raw_key` immediately — it is only returned once. `agent_row_created: true` confirms the Agent row exists; `initial_trust` and `initial_fleet` were applied in the same round-trip. Request body fields: - `agent_id` (required) — stable identifier for this agent. Surfaces in `/whoami`, audit, and per-agent dashboards. - `label` — human-readable hint in the dashboard. - `initial_trust` — `0` read-only / `1` write to home fleet / `2` cross-fleet read / `3` cross-fleet write + delete. Default `1`. - `initial_fleet` — fleet membership; omit for tenant-wide scope. - `display_name` — human-readable name surfaced on the dashboard. ## 2. Verify identity (`/whoami`) Before any real tool call, confirm MemClaw resolves your credentials the way you expect: {`curl "{HOST}/api/v1/whoami" \\ -H "X-API-Key: $AGENT_KEY"`} ```json { "tenant_id": "your-tenant-id", "agent_id": "quote-agent-na", "auth_source": "gateway-header", "via_gateway": true } ``` If `agent_id` is `null` you're sending a tenant-scoped credential, not an agent-scoped one — the gateway only injects `X-Agent-ID` on the agent-scoped path. (Both kinds share the `mc_` prefix; the dashboard "Kind" column tells you which is which.) ## 3. Open an MCP session MemClaw speaks MCP streamable-http at `/mcp` (both `/mcp` and `/mcp/` work). The server accepts the API key on either header — use whichever your SDK supports: | Header | When to use | | --- | --- | | `X-API-Key: mc_…` | Canonical. Use if you control the request shape. | | `Authorization: Bearer mc_…` | OAuth-style. Required by Anthropic's remote-MCP integration and SDKs that only emit `Authorization` headers. | Dashboard-issued JWTs are also accepted via `Authorization: Bearer `; the server tries JWT decode first. ### Python (the `mcp` library) {`import asyncio from mcp.client.session import ClientSession from mcp.client.streamable_http import streamablehttp_client async def main(): headers = {"X-API-Key": "mc_..."} # agent-scoped credential url = "{HOST}/mcp/" async with streamablehttp_client(url, headers=headers) as (read, write, _): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() print([t.name for t in tools.tools]) result = await session.call_tool( "memclaw_write", {"content": "First memory from the Python harness."}, ) # Always inspect both result.isError and the content envelope. # Gateway-side refusals (FORBIDDEN, INVALID_ARGUMENTS, NOT_FOUND, ...) # arrive as isError=True with a JSON {"error":{...}} body — naive # clients that only check content[0].text for "id" will silently # treat failure as success. if result.isError: print("tool refused:", result.content[0].text) else: print(result) asyncio.run(main())`} ### Anthropic SDK (remote-MCP) {`from anthropic import Anthropic client = Anthropic() msg = client.messages.create( model="claude-opus-4-7", max_tokens=1024, messages=[{"role": "user", "content": "Save this note: pricing meets 10 May."}], extra_body={ "mcp_servers": [ { "type": "url", "url": "{HOST}/mcp/", "name": "memclaw", "authorization_token": "mc_...", # agent-scoped credential } ] }, ) print(msg.content)`} The SDK forwards `authorization_token` as `Authorization: Bearer mc_…`. MemClaw recognises that shape and resolves tenant + agent identity from it. ## 4. Elevate trust (when needed) If you set `initial_trust` in step 1, skip this. Otherwise: {`curl -X PATCH "{HOST}/api/v1/agents/quote-agent-na/trust?tenant_id=$TENANT_ID" \\ -H "X-API-Key: $MC_TENANT_KEY" \\ -H "Content-Type: application/json" \\ -d '{"trust_level": 2}'`} Trust levels: - `0` — read-only. - `1` — write to home fleet. - `2` — cross-fleet read. - `3` — cross-fleet write + delete + update others' memories. ## End-to-end bootstrap, one block {`TENANT_KEY=mc_... AGENT_ID="quote-agent-na" FLEET_ID="na-sales" # 1. Provision agent + Agent row + trust + fleet in one call. RESP=$(curl -s -X POST "{HOST}/api/v1/admin/agent-keys/provision" \\ -H "X-API-Key: $TENANT_KEY" \\ -H "Content-Type: application/json" \\ -d "{\\"agent_id\\":\\"$AGENT_ID\\",\\"initial_trust\\":1,\\"initial_fleet\\":\\"$FLEET_ID\\"}") AGENT_KEY=$(echo "$RESP" | python3 -c "import json,sys; print(json.load(sys.stdin)['raw_key'])") # 2. Verify. curl -s "{HOST}/api/v1/whoami" -H "X-API-Key: $AGENT_KEY" # 3. Use. curl -s "{HOST}/api/v1/memories" \\ -H "X-API-Key: $AGENT_KEY" \\ -H "Content-Type: application/json" \\ -d "{\\"agent_id\\":\\"$AGENT_ID\\",\\"fleet_id\\":\\"$FLEET_ID\\",\\"content\\":\\"Hello world\\"}"`} Four steps, one round-trip per agent. No provision → fake-write → patch-trust dance. ## Idempotency A write of identical content (same `agent_id`, same `fleet_id`) is retry-safe via MCP: - First call → `201` with the new memory id. - Identical retry → `200` with `{ "status": "duplicate", "existing_id": "…" }`. Cross-agent writes of identical content no longer collide — each agent gets its own record. ## Authoring keystones When you want an agent to author governance rules ([keystones](/docs/concepts/keystones)), use `memclaw_keystones_set` over MCP: ```python result = await session.call_tool( "memclaw_keystones_set", { "op": "set", "doc_id": "no-rollback-to-cve-versions", "title": "Refuse rollback to CVE versions", "content": "Never recommend rolling back to a version listed in any CVE entry.", "scope": "tenant", "weight": "high", }, ) ``` Two gotchas worth knowing before you write the call: - `agent_id` in `memclaw_keystones_set` names the **TARGET** agent the rule binds to, not the caller. Pass it only for `scope=agent`. For `scope=tenant` or `scope=fleet`, omit it — passing it returns `INVALID_ARGUMENTS`. - The companion read tool `memclaw_keystones` returns the merged rule set under the JSON key `rules` (not `keystones`). Trust gating is dynamic: self-authoring (`scope=agent` + target = caller) needs trust ≥ 1; anything else (fleet, tenant, or targeting another agent) needs trust ≥ 2. ## Common pitfalls - **`POST /provision` returns the raw key once.** Save it before the response goes out of scope. - **`PATCH /agents/{id}/trust` returns 404 immediately after provisioning.** Means the Agent row was not materialised atomically — should not happen on builds after 2026-05-14. Check `/whoami` and `GET /api/v1/agents/{id}`; if `agent_row_created: false` is in the provision response, the deployment is missing `CORE_STORAGE_API_URL`. - **MCP tool result has `isError=False` but `content[0].text` is `{"error": …}`.** Pre-2026-05-15 builds left `isError` at the default for gateway-side refusals. On current builds, every structured-error envelope arrives with `isError=True`. - **Streaming client hangs on `/mcp` (no slash).** Older builds redirected `/mcp` → `/mcp/`; current builds serve both paths in-process. ## Reference - `POST /api/v1/admin/agent-keys/provision` — atomic provisioning (this guide). - `GET /api/v1/whoami` — identity probe. - `GET /api/v1/agents/{id}?tenant_id=…` — agent detail. - `PATCH /api/v1/agents/{id}/trust?tenant_id=…` — change trust level. - `POST /api/v1/memories` — REST write (mirrors `memclaw_write` over MCP). - `mcp://…/mcp/` — streamable-http MCP endpoint. # REST URL: https://memclaw.net/docs/integrations/rest Description: Hit MemClaw directly from any language. No SDK required. If your stack doesn't speak MCP, drive MemClaw over plain HTTP. All endpoints accept JSON over HTTPS, authenticated with the `X-API-Key` header. ## Example: write + recall URLs in the snippets below auto-target this deployment. {`# Write curl -X POST "{HOST}/api/v1/memories" \\ -H "X-API-Key: mc_xxx" \\ -H "Content-Type: application/json" \\ -d '{ "tenant_id": "my-team", "agent_id": "ingest-bot", "content": "Q3 revenue target is $4M, set on 2026-04-15." }' # Recall curl -X POST "{HOST}/api/v1/recall" \\ -H "X-API-Key: mc_xxx" \\ -H "Content-Type: application/json" \\ -d '{ "tenant_id": "my-team", "query": "Q3 revenue target" }'`} ## Reference The full endpoint catalog is auto-generated from the FastAPI OpenAPI spec at [/docs/api-reference](/docs/api-reference). The same spec is hosted live at [`/api/openapi.json`](/api/openapi.json) — point any code generator at it. ## Pagination, errors, rate limits See [Reference → Errors](/docs/reference/errors) and [Reference → Env vars](/docs/reference/env-vars). Standard patterns: `?cursor=...&limit=...` for pagination, `4xx` problem-detail JSON for errors, `Retry-After` header on 429s. ## Long-lived integrations: per-agent keys The single tenant-scoped `mc_` flow above is fine for one-off scripts. For anything that ships — trust gating, fleet membership, per-agent keystones, real identity in the dashboard — bind each agent to its own **agent-scoped credential** via [Integrations → Per-agent keys](/docs/integrations/per-agent-keys). Both kinds use the `mc_` prefix on the wire; scope is set at mint time. # Operational Commands URL: https://memclaw.net/docs/reference/cli Description: Common commands for self-hosted MemClaw. Defers to the OSS scripts/ directory for the canonical list. The OSS bundle ships scripts in [`scripts/`](https://github.com/caura-ai/caura-memclaw/tree/main/scripts). The list below covers the everyday commands; check the directory for additions. ## Database migrations Migrations are managed with Alembic, configured in `alembic.ini`: ```bash docker compose run --rm core-api alembic upgrade head docker compose run --rm core-api alembic revision --autogenerate -m "what changed" ``` ## Agent skill installer The OSS API exposes a one-line installer for the `memclaw` agent skill — see `tests/test_install_skill_endpoint.py` for the supported parameters. URL auto-targets this deployment's host: ## Health checks ```bash curl http://localhost:8000/api/v1/health ``` `core-api` exposes `/api/v1/health` only — it returns the dependency probe shape (`status`, `storage`, `redis`, `event_bus`). Sibling services (`core-storage-api`, `core-worker`, `core-operations`) expose `/readyz` for readiness probes on Cloud Run, where `/healthz` is intercepted by the GFE. # Environment Variables URL: https://memclaw.net/docs/reference/env-vars Description: The authoritative list lives in the OSS .env.example. Highlights below. The full, current set of environment variables — with comments — lives in [`.env.example`](https://github.com/caura-ai/caura-memclaw/blob/main/.env.example) on the OSS repo. Read it directly; it's the source of truth and stays in sync with the code. The headline groups (per `.env.example`): - **Mode** — `IS_STANDALONE`, `ENVIRONMENT` - **Database** — `POSTGRES_HOST`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_REQUIRE_SSL` - **Auth** — `ADMIN_API_KEY`, `MEMCLAW_API_KEY` - **Embedding provider** — `EMBEDDING_PROVIDER`, `OPENAI_API_KEY`, `OPENAI_EMBEDDING_MODEL` (see comments in `.env.example` for `local` / `fake` providers) - **LLM enrichment / entity extraction** — `ENTITY_EXTRACTION_PROVIDER` plus the matching provider key (`ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, …) - **Platform-tier providers** — only relevant for the enterprise managed deployment (Vertex AI, platform embedding model). OSS users leave these empty. ## Auth modes Per `.env.example`: - `IS_STANDALONE=true` — single-tenant mode. No auth on most routes. - `ADMIN_API_KEY=…` — gates `/api/admin/*` routes. Required in production. - `MEMCLAW_API_KEY=…` — when set, **all** non-admin requests must include it via `X-API-Key`. Useful when exposing the API beyond localhost. # Errors and Status Codes URL: https://memclaw.net/docs/reference/errors Description: The canonical error envelope shared by REST and MCP, plus the HTTP status → code mapping. Both REST and MCP emit the same error shape. Source: [`core-api/src/core_api/errors.py`](https://github.com/caura-ai/caura-memclaw/blob/main/core-api/src/core_api/errors.py) (added in PR #58). ## Canonical envelope ```json { "error": { "code": "", "message": "", "details": { "...": "optional" } } } ``` Dispatch on `error.code` — it's the machine-readable signal and is identical across both surfaces. ## REST back-compat REST responses keep a top-level `detail` field alongside `error` so existing clients reading `response.json()["detail"]` keep working: ```json { "detail": "Memory not found", "error": { "code": "NOT_FOUND", "message": "Memory not found" } } ``` `detail` is the deprecated mirror. New clients should switch to `error.code`. For FastAPI request-validation failures (422), `detail` is the original list of validation errors and `error.details.errors` carries the same list aggregated. ## MCP envelope MCP tools return the same `error` envelope, JSON-serialized, plus `_latency_ms`: ```json { "error": { "code": "INVALID_ARGUMENTS", "message": "Unknown op 'wat'.", "details": { "op": "wat", "expected_ops": ["read", "update", "..."] } }, "_latency_ms": 7 } ``` Pre-PR-#58 MCP tools returned bare `"Error (XXX): ..."` strings — that format is gone. ## HTTP status → canonical code From `STATUS_TO_CODE` in `errors.py`: | Status | Code | | --- | --- | | 400 | `BAD_REQUEST` | | 401 | `UNAUTHORIZED` | | 402 | `PAYMENT_REQUIRED` | | 403 | `FORBIDDEN` | | 404 | `NOT_FOUND` | | 405 | `METHOD_NOT_ALLOWED` | | 408 | `REQUEST_TIMEOUT` | | 409 | `CONFLICT` | | 410 | `GONE` | | 413 | `PAYLOAD_TOO_LARGE` | | 415 | `UNSUPPORTED_MEDIA_TYPE` | | 422 | `INVALID_ARGUMENTS` | | 429 | `RATE_LIMITED` | | 500 | `INTERNAL_ERROR` | | 501 | `NOT_IMPLEMENTED` | | 502 | `UPSTREAM_ERROR` | | 503 | `UNAVAILABLE` | | 504 | `UPSTREAM_TIMEOUT` | Statuses not in the table fall back to `HTTP_` (e.g. `HTTP_418`). ## Trust-level errors Trust failures come from `core_api.services.trust_service.parse_trust_error` and are re-wrapped as canonical `FORBIDDEN` with the required vs. caller's level in `details`. ## Idempotency The write route (`POST /api/v1/memories`) accepts an `Idempotency-Key` header (`IDEMPOTENCY_HEADER` in `core-api/src/core_api/middleware/idempotency.py`). A retry within the cache window with the same key short-circuits to the original response without consuming a write slot. # Skills URL: https://memclaw.net/docs/skills Description: Publish a proven workflow to the tenant skills catalog so other agents discover it via semantic search. A **skill** is a reusable, named procedure — a small runbook the rest of the fleet can find, follow, and adapt. MemClaw stores skills as documents in the system-reserved `skills` collection. Any agent in the tenant can author a skill via `memclaw_doc op=write collection='skills'`; any agent can retrieve them via `memclaw_doc op=search`. If you want to **read** the canonical agent-facing skill an LLM follows when it talks to MemClaw itself, that lives at [`/docs/agents`](/docs/agents). This page is about publishing your **own** skills. ## Authoring: `memclaw_doc op=write collection='skills'` ```python result = await session.call_tool( "memclaw_doc", { "op": "write", "collection": "skills", "doc_id": "triage-cve-rollback-request", "data": { "summary": ( "Triage a customer asking to roll back to an older " "version: check the CVE list, refuse versions with " "active advisories, suggest the nearest safe build." ), "steps": [ "Identify the requested target version.", "Search the kb collection for matching CVE advisories.", "If a match is found, refuse the rollback and cite the advisory.", "Otherwise, suggest the nearest patched build.", ], "owner_agent": "support-admin", }, }, ) ``` The `data` dict is free-form per skill, but two fields are semantically meaningful: - **`data["summary"]`** (1–3 dense, intent-focused sentences). This is the **only** field that gets embedded. A skill without a `summary` stores fine but won't appear in `memclaw_doc op=search` results — which means peers won't find it. - **`data["description"]`** — back-compat alias for `summary`; only honored for the skills collection. Prefer `summary`. Everything else (`steps`, `owner_agent`, your domain fields) is stored as-is and returned verbatim on read. ### `doc_id` slug rules Skills' `doc_id` becomes a directory name on plugin runtimes that materialise the skill to disk, so the slug is filesystem-safe: ``` ^[a-z0-9][a-z0-9._-]{0,99}$ ``` Lowercase letters, digits, `.`, `_`, `-`. Must start with a letter or digit. Max 100 chars. Anything else returns `INVALID_ARGUMENTS`. Good: `triage-cve-rollback-request`, `nightly.report.summarizer`, `slack-thread-cleanup-v2`. Bad: `Triage CVE!`, `_leading-underscore`, `path/with/slashes`, `caps-and-spaces here`. ## Discovery: `memclaw_doc op=search collection='skills'` ```python result = await session.call_tool( "memclaw_doc", { "op": "search", "collection": "skills", "query": "what to do when a customer asks for an old version", "top_k": 5, }, ) ``` Search ranks by semantic similarity over the `data["summary"]` vectors, so good summaries are the difference between a skill that gets reused and one that rots. Treat the summary like the bullet you'd write in a runbook index — `what the skill is for`, `when it applies`, `what makes it different from neighbours`. Omit `collection` to span every collection in the tenant (broad search across kb, skills, your own collections, etc.). ## Reading a skill: `memclaw_doc op=read` ```python result = await session.call_tool( "memclaw_doc", { "op": "read", "collection": "skills", "doc_id": "triage-cve-rollback-request", }, ) ``` Returns the full `data` payload exactly as written. ## Updating `op=write` is upsert by `(collection, doc_id)`. Re-call with the same `doc_id` and a changed `summary` to refresh the embedding; re-call with the same `summary` but a different `data` to refresh the stored fields without re-embedding. ## Reading MCP tool results Every `memclaw_doc` call returns an MCP tool result with an `isError` boolean. On gateway-side refusals (slug rules, missing collection, FORBIDDEN, etc.) the server sets `isError=True` and the JSON `{"error": {...}}` envelope lands in `content[0].text`. See [MCP integration → Reading MCP tool results](/docs/integrations/mcp#reading-mcp-tool-results). ## Common pitfalls - **Skill doesn't show up in search.** You probably wrote without `data["summary"]`. The doc is stored, but there's no embedding to match — search ranks by summary vectors. Re-write with a summary. - **`INVALID_ARGUMENTS: collection='skills' requires doc_id matching …`.** Your slug has spaces, uppercase, slashes, or starts with `.`, `_`, or `-`. Rename to fit `^[a-z0-9][a-z0-9._-]{0,99}$`. - **Search across collections returns kb hits instead of skills.** Pass `collection: "skills"` to narrow.