diff --git a/docs/MEMORY.md b/docs/MEMORY.md
index f122054..2f182f8 100644
--- a/docs/MEMORY.md
+++ b/docs/MEMORY.md
@@ -1,20 +1,70 @@
# Memory — Guide
+> **Migration note:** Clawix's long-term memory is now backed by a per-user **wiki** (`WikiPage` / `WikiLink` / `WikiShare`) instead of the old `MemoryItem` / `MemoryShare` tables. The legacy `save_memory` / `search_memory` / `share_memory` tools have been replaced by the `wiki_*` toolset described below. The `/memory` page now 308-redirects to `/wiki`. User-profile facts continue to live in the file-based `/workspace/USER.md`, **not** in the wiki — keeping two sources of truth would cause drift.
+
+> **Background.** The design follows the **"LLM Wiki"** pattern proposed by Andrej Karpathy ([gist](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)): an LLM-maintained markdown knowledge base with three layers — raw sources, the wiki itself, and a schema document — built around `ingest` / `query` / `lint` operations. Clawix's `WikiPage`, `_schema` page, `[[slug]]` cross-links, and `wiki_write` / `wiki_search` / `wiki_lint` tools are the concrete realisation of that pattern.
+
## What is Memory?
In Clawix, **memory** is the collective term for all persistent context that is loaded into an agent's system prompt at the start of every run. It is what gives agents continuity — the ability to remember who you are, what you have worked on, what you have learned, and what you have decided — across separate conversations.
Memory is **not** a single monolithic file. It is a layered system with four distinct components, each serving a different purpose:
-| Layer | Source | What it contains | Who controls it |
-| ----------------------------------------- | ------------------------------------ | ------------------------------------------------------------- | ------------------------------ |
-| **Soul** (`SOUL.md`) | Static file in workspace | Agent personality, communication style, values | Admin / user (edit the file) |
-| **User Profile** (`USER.md`) | Static file in workspace | User name, preferences, work context, special instructions | Agent learns + user edits |
-| **Long-term Memory** (`memory/MEMORY.md`) | Auto-maintained file | Durable facts, decisions, standards, accumulated knowledge | Agent writes via `save_memory` |
-| **Daily Notes** | Database (tagged `daily:YYYY-MM-DD`) | Short-term activity journal; what happened in the last 3 days | Agent writes via `save_memory` |
+| Layer | Source | What it contains | Who controls it |
+| ---------------------------- | --------------------------------------------- | ------------------------------------------------------------- | ----------------------------- |
+| **Soul** (`SOUL.md`) | Static file in workspace | Agent personality, communication style, values | Admin / user (edit the file) |
+| **User Profile** (`USER.md`) | Static file in workspace | User name, preferences, work context, special instructions | Agent learns + user edits |
+| **Long-term Memory** (Wiki) | DB: `WikiPage` rows with `scope='AMBIENT'` | Durable facts, decisions, standards, current-project state | Agent writes via `wiki_write` |
+| **Daily Notes** | DB: `WikiPage` rows tagged `daily:YYYY-MM-DD` | Short-term activity journal; what happened in the last 3 days | Agent writes via `wiki_write` |
All four layers are injected into the agent's **system prompt** at the start of each run, before any conversation history. This means the agent always "wakes up" with full context — without the user needing to repeat themselves.
+A fifth element, the **Wiki Schema** (`_schema` page, see [`/wiki/schema`](#wiki-schema)), is also auto-injected: it tells the agent how _this user_ wants their wiki organized (naming conventions, when to create pages, etc.).
+
+---
+
+## The Mental Model — Why a wiki, not a memory blob?
+
+If you've worked with other AI agent platforms, "memory" probably meant one of two things. Clawix does neither — it follows the **LLM Wiki** pattern instead. Understanding the difference is the key to understanding why the rest of this doc looks the way it does.
+
+### The two conventional approaches
+
+1. **Append-everything log.** The agent appends raw facts ("user prefers TS strict mode", "we use Zod for validation", …) to a flat list. Over months the list grows large, accumulates contradictions, and the model has to re-read it every turn. There is no structure, no deduplication, no schema.
+2. **RAG over raw sources.** Every query, an embedding model retrieves the _k_ most relevant chunks from a static document store. The store grows, but it is **never digested** — each query reads raw, unstructured text. Conflicting or stale chunks are returned next to fresh ones; the model is left to reconcile them on every call.
+
+### Clawix's approach: the LLM Wiki
+
+Clawix implements the **LLM Wiki** pattern proposed by Andrej Karpathy ([gist](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)). The agent doesn't accumulate raw facts and it doesn't search raw documents — it **maintains a living wiki of distilled, cross-linked knowledge** about you, the work, and the project.
+
+The pattern has three layers:
+
+| Layer | What it is | Who writes it |
+| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
+| **Raw sources** | Conversations, files, agent runs — the inputs the agent reads. | The user / external systems (immutable to the agent). |
+| **The wiki** | A structured, interlinked set of markdown pages (`WikiPage` rows). One page = one coherent topic. | The agent, via `wiki_write` (and the user, via `/wiki`). |
+| **The schema** | A single `_schema` page that tells the agent _how to organize this user's wiki_ — naming conventions, when to create vs append, what counts as a domain. | The user, at `/wiki/schema`. |
+
+…maintained through three operations, mirrored exactly in the agent's toolset:
+
+- **Ingest** (`wiki_write`) — when something new is learned, the agent reads it, decides where it belongs, and either appends to an existing page or creates a new one, linking related pages with `[[slug]]` markers.
+- **Query** (`wiki_index` / `wiki_search` / `wiki_read`) — when answering a question, the agent navigates _its own distilled wiki_ first. Pages that proved valuable get refined further; ones that didn't get pruned.
+- **Lint** (`wiki_lint`) — periodically, the agent or user scans for contradictions, stale claims, orphan pages, missing `domain:*` tags, and broken `[[slug]]` links.
+
+> _"The tedious part of maintaining a knowledge base is not the reading or the thinking — it's the bookkeeping."_ The LLM does the bookkeeping; the user curates sources and edits the schema.
+
+### Why it matters
+
+| Conventional memory | Clawix's wiki |
+| ----------------------------------------------------- | ---------------------------------------------------------------------------------- |
+| Flat list / chat-history blob; grows unboundedly | Structured pages; each topic gets its own home |
+| RAG returns raw chunks — including contradictions | The agent has already reconciled contradictions on ingest |
+| No schema — agent decides structure on the fly | `_schema` page governs structure → consistent over months |
+| Linking and dedup happen at retrieval time (or never) | `[[slug]]` links + `WikiLink` rows + `wiki_lint` keep the graph clean continuously |
+| Hard to inspect or correct manually | It's just markdown — open `/wiki` and edit |
+| Memory and identity tangled in one blob | Identity (`/workspace/USER.md`) and knowledge (wiki) are separate sources of truth |
+
+The rest of this guide describes the concrete pieces: what gets injected into every prompt, what each tool does, and how visibility, sharing, and limits work.
+
---
## Why Use Memory?
@@ -22,64 +72,64 @@ All four layers are injected into the agent's **system prompt** at the start of
Without memory, every conversation with an agent starts from scratch. The agent forgets your name, your preferences, what you decided last week, and what it already tried. With memory:
- **No repetition** — You don't re-explain your stack, style preferences, or ongoing projects every session.
-- **Compounding value** — The agent accumulates knowledge over time. The longer you work together, the more context-aware and accurate the responses become.
-- **Continuity across agents** — When memory items are shared to a group or the org, sub-agents and other users can access the same knowledge base.
-- **Self-improving prompts** — The agent updates `USER.md` and `MEMORY.md` as it learns, keeping its own context current.
-- **Autonomous journaling** — Daily notes (`daily:YYYY-MM-DD` tags) give you and the agent a searchable activity log without manual effort.
-- **Knowledge sharing** — Decisions, standards, and discoveries can be promoted from private memory to group or org-wide memory with a single `share_memory` call.
+- **Compounding value** — The agent accumulates wiki pages over time. The longer you work together, the richer and more navigable the knowledge base becomes.
+- **Continuity across agents** — When pages are shared to a group or the org, sub-agents and other users can read the same knowledge base.
+- **Self-improving prompts** — The agent updates `USER.md` and writes/updates wiki pages as it learns, keeping its own context current.
+- **Autonomous journaling** — Daily notes (`daily:YYYY-MM-DD` tag) give you and the agent a searchable activity log without manual effort.
+- **Knowledge sharing** — Decisions, standards, and discoveries can be promoted from private wiki pages to group or org-wide pages with a single `wiki_share` call.
---
## Public vs Private Memory
-Clawix implements a **three-tier visibility model** for database memory items. The tier is determined by whether a `MemoryShare` record exists and what its `targetType` is.
+Clawix implements a **three-tier visibility model** for wiki pages. The tier is determined by whether one or more `WikiShare` records exist for the page and what their `targetType` is.
```
┌─────────────────────────────────────────────────────────────────────┐
-│ MEMORY VISIBILITY │
+│ WIKI VISIBILITY │
│ │
-│ Private (default) Group-scoped Org-wide │
-│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
-│ │OwnerID only │ │ Group A │ │ All users │ │
-│ │ │ share │ members │share │ in the org │ │
-│ │ MemoryItem │ ──────► │ │────► │ │ │
-│ │ (no share) │ │ MemoryShare │ │ MemoryShare │ │
-│ │ │ │ type=GROUP │ │ type=ORG │ │
-│ └─────────────┘ └─────────────┘ └─────────────┘ │
+│ Private (default) Group-scoped Org-wide │
+│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
+│ │OwnerID only │ │ Group A │ │ All users │ │
+│ │ │ share │ members │share │ in the org │ │
+│ │ WikiPage │ ──────► │ │────► │ │ │
+│ │ (no share) │ │ WikiShare │ │ WikiShare │ │
+│ │ │ │ type=GROUP │ │ type=ORG │ │
+│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
-│ Revocable: sharing can be revoked (isRevoked flag) │
+│ Reversible: each share can be revoked individually │
└─────────────────────────────────────────────────────────────────────┘
```
-### Private memory
+### Private wiki pages
-A memory item with no associated `MemoryShare` record. Only the owning user (and their agents) can read it.
+A page with no associated `WikiShare` record. Only the owning user (and their agents) can read it. **Default for every newly created page.**
-**Use for:** Personal preferences, private notes, individual coding standards, personal API keys or account references, draft ideas not ready to share.
+**Use for:** Personal preferences, private notes, individual coding standards, personal API references, draft ideas not ready to share.
-### Group-scoped memory
+### Group-scoped pages
-A memory item shared to a named **Group** (`targetType = 'GROUP'`). All members of that group can search and read it. Only the original owner can revoke the share.
+A page shared to a named **Group** (`WikiShare.targetType = 'GROUP'`). All members of that group can read it via `wiki_index` / `wiki_search` / `wiki_read`. Only the owner (or a group OWNER) can revoke the share.
**Use for:** Team decisions, shared coding conventions, project knowledge, shared prompt templates, collaborative research findings.
-### Org-wide memory
+### Org-wide pages
-A memory item shared to the entire organisation (`targetType = 'ORG'`, no `groupId`). Every user in the deployment can read it.
+A page shared to the entire organisation (`WikiShare.targetType = 'ORG'`, no `groupId`). Every user in the deployment can read it.
**Use for:** Company-wide standards, approved tool lists, product descriptions, security policies, on-boarding information for new agents.
### Visibility resolution
-When `search_memory` runs, it queries all three tiers simultaneously using this logic:
+When `wiki_index` / `wiki_search` / `wiki_read` runs, it queries all three tiers simultaneously using this logic:
```
Visible = (owned by user)
- ∪ (shared to any group the user is a member of, not revoked)
- ∪ (shared to org, not revoked)
+ ∪ (shared to any group the user is a member of)
+ ∪ (shared to org)
```
-The `isOwned` flag in search results tells the agent whether it owns the item (and thus can share or update it).
+The `isOwned` flag in tool results tells the agent whether it owns the page (and thus can share, update, or delete it).
---
@@ -94,87 +144,55 @@ flowchart TD
C --> D1[SOUL.md\nAgent personality & values]
C --> D2[USER.md\nUser profile & preferences]
C --> D3[Agent System Prompt\nRole-specific instructions]
- C --> D4[memory/MEMORY.md\nLong-term facts & standards]
- C --> D5[Daily Notes DB\nLast 3 days of activity]
- C --> D6[Available Tags Index\nWhat memories exist]
+ C --> D4["## Long-term Memory\nAMBIENT WikiPage rows"]
+ C --> D5["## Daily Notes\nLast 3 days, daily:* tag"]
+ C --> D6["## Wiki Schema\n_schema page content"]
+ C --> D7["## Wiki Index\nTOC by domain"]
end
- D1 & D2 & D3 & D4 & D5 & D6 --> E[Assembled System Prompt]
+ D1 & D2 & D3 & D4 & D5 & D6 & D7 --> E[Assembled System Prompt]
E --> F[LLM Reasoning Loop]
- subgraph TOOLS["Memory Tools (agent can call)"]
- F --> T1[save_memory\nCreate/update memory item]
- F --> T2[search_memory\nQuery private + shared memory]
- F --> T3[list_groups\nDiscover share targets]
- F --> T4[share_memory\nShare item to group or org]
+ subgraph TOOLS["Wiki tools (agent can call)"]
+ F --> T1[wiki_index — list pages]
+ F --> T2[wiki_search — full-text search]
+ F --> T3[wiki_read — fetch full page]
+ F --> T4[wiki_write — create / update]
+ F --> T5[wiki_delete — remove]
+ F --> T6[list_groups — find share targets]
+ F --> T7[wiki_share / wiki_unshare]
+ F --> T8[wiki_log — read audit history]
+ F --> T9[wiki_lint — owner-only quality scan]
end
- T1 -->|writes DB item| G[(MemoryItem DB)]
- T1 -->|updates file| H[memory/MEMORY.md]
- T2 -->|reads| G
- T4 -->|creates| I[(MemoryShare DB)]
+ T4 -->|write WikiPage,\nrebuild WikiLink rows| G[(WikiPage / WikiLink DB)]
+ T1 & T2 & T3 & T8 & T9 -->|read| G
+ T7 -->|create/delete| I[(WikiShare DB)]
subgraph SHARING["Visibility"]
G --> V1[Private\nowner only]
I --> V2[Group-scoped\ngroup members]
I --> V3[Org-wide\nall users]
end
-
- G --> J[Memory Consolidation\nAuto-summarise when\ncontext window near limit]
- J -->|archive old messages| G
- J -->|update| H
```
---
-## The Workspace Memory Files
+## The Workspace Files
Navigate to **Workspace** in the left sidebar (path: `/workspace`).
-
+
-The workspace root contains four items relevant to memory:
+The workspace root contains three items relevant to memory:
| Item | Type | Purpose |
| ------------ | ------ | ----------------------------------------------------------------- |
-| `memory/` | Folder | Contains `MEMORY.md` — the agent's long-term knowledge file |
| `SOUL.md` | File | Agent personality bootstrap — injected before every system prompt |
| `USER.md` | File | User profile bootstrap — injected before every system prompt |
| `projector/` | Folder | UI templates (unrelated to memory) |
-### The `memory/` folder
-
-
-
-The `memory/` folder contains a single file: **`MEMORY.md`**.
-
-
-
-`MEMORY.md` is the agent's **long-term knowledge file**. It is:
-
-- Written and updated by the agent using the `save_memory` tool
-- Auto-generated on first run from existing DB memory items (excluding daily notes)
-- Formatted as markdown with one section per tag
-- Truncated to ~1 500 tokens when injected into context (approx. 6 000 characters)
-- Editable by the user directly in the Workspace file browser
-
-**Example structure of MEMORY.md:**
-
-```markdown
-# Memory
-
-## Coding-standards
-
-- Always use TypeScript strict mode. Prefer functional patterns over classes.
-
-## Project-decisions
-
-- Switched from REST to tRPC for the internal API on 2026-03-15.
-
-## Team-preferences
-
-- PRs must be reviewed by at least 2 engineers before merge.
-```
+> The legacy `memory/MEMORY.md` file is no longer the long-term memory store — those facts now live as individual `WikiPage` rows. (Session-level context compression may still write a `memory/MEMORY.md` artifact inside an agent's runtime container, but it is an internal snapshot of recent activity, not the durable knowledge layer.)
### SOUL.md — Agent Personality
@@ -203,7 +221,53 @@ Editing `SOUL.md` is the primary way to customise an agent's persona without tou
- **Work Context** — Role, ongoing projects, tools used
- **Special Instructions** — User-specific overrides the agent should always follow
-The agent can update `USER.md` directly using the `write` file tool when it learns something new and persistent about the user.
+The agent can update `USER.md` directly using the `edit_file` tool when it learns something new and persistent about the user.
+
+> **Do NOT** mirror user-profile facts into wiki pages. The `wiki_write` tool actively rejects this duplication — `/workspace/USER.md` is the single source of truth for who the user is. Wiki pages capture _what is true about the work_, not _who the user is_.
+
+---
+
+## The Wiki — Long-term Memory at `/wiki`
+
+The wiki is browsable in the dashboard at **`/wiki`** (under **Workspace** in the sidebar; the older **`/memory`** path 308-redirects there). It shows three things in the left rail:
+
+- **Search** — free-text input that drives `wiki_search`.
+- **📚 Wiki Schema** — direct link to `/wiki/schema`, the dedicated editor for the `_schema` page (see below).
+- **Page list** — toggles between _Visible to me_ and _Mine_, plus a button to create a new page or a new daily note.
+
+Each page has: `title`, `slug` (auto-derived), `summary`, markdown `content`, `tags`, `scope`, and an `ownerId`. Pages are linked together with `[[slug]]` markers in the content; those are parsed into `WikiLink` rows and exposed as **backlinks** in the page view.
+
+### Page scope: AMBIENT vs ARCHIVED
+
+Every wiki page has a `scope`:
+
+| Scope | Behaviour |
+| ------------ | ------------------------------------------------------------------------------------------------------------- |
+| **AMBIENT** | Auto-injected into the system prompt under `## Long-term Memory`. Use sparingly — there is a hard cap. |
+| **ARCHIVED** | (Default) Retrieved on demand via `wiki_index` / `wiki_search` / `wiki_read`. Doesn't consume context budget. |
+
+The ambient cap is enforced per-policy (`Policy.maxAmbientPages`, default `5`). Promotion to AMBIENT is atomic — if you are already at cap, the write fails with `WIKI_AMBIENT_FULL` plus a list of the current AMBIENT pages so the agent can decide what to demote.
+
+### Wiki Schema (`_schema`) — your wiki's user guide
+
+Every user has exactly one **`_schema`** page (slug reserved, tagged `kind:schema`, always `scope='AMBIENT'`). It is bootstrapped from a template on first wiki use and is the only page the agent reads to understand _how this user wants the wiki organized_: when to create new pages vs append, naming conventions, when to share, etc.
+
+- Edited at **`/wiki/schema`** — a dedicated split-pane editor (markdown source + live preview).
+- The generic `wiki_write` tool rejects edits to `_schema`; only the dedicated `PATCH /wiki/schema` endpoint can update it.
+- Restricted to developer/admin role at the controller level.
+
+The `_schema` page is a singleton meta-page, not a content page — that is why it has its own UI and API surface rather than being edited inline alongside regular pages.
+
+### Tag conventions
+
+Tags are normalized to lowercase on write and follow three rules:
+
+| Tag form | Purpose | Constraints |
+| ---------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
+| `domain:` | Primary classifier (e.g. `domain:hr`, `domain:engineering`). | Exactly **one** required when any non-daily tag is present. Exempt for pure daily notes. |
+| `daily:YYYY-MM-DD` | Marks an activity-journal entry. Auto-pulled into _Recent Activity_. | Exempt from the `domain:` requirement. |
+| `kind:schema` | Reserved — used only on the `_schema` page. | Do not set manually. |
+| Free-form (e.g. `tooling`, `validation`) | Secondary classifier; combine with `domain:*`. | Must coexist with a `domain:*` tag. |
---
@@ -218,135 +282,141 @@ flowchart LR
A["1. SOUL.md\n(personality & values)"]
B["2. USER.md\n(user profile)"]
C["3. Agent system prompt\n(role instructions)"]
- D["4. Workspace tools hint\n(file paths, memory.md location)"]
- E["5. Memory tools hint\n(daily notes, tags, search guidance)"]
+ D["4. Workspace tools hint\n(file paths, edit_file usage)"]
+ E["5. Wiki tools hint\n(daily notes, tags, search guidance)"]
F["6. Workers list\n(primary agents only)"]
- G["7. ## Long-term Memory\n(memory/MEMORY.md, max 1 500 tokens)"]
- H["8. ## Recent Activity\n(last 3 days of daily notes, max 1 000 tokens)"]
- I["9. ## Available Memory Tags\n(index of all tags for search_memory)"]
- A --> B --> C --> D --> E --> F --> G --> H --> I
+ G["7. ## Long-term Memory\n(AMBIENT WikiPages — capped budget)"]
+ H["8. ## Daily Notes (last 3 days)\n(WikiPages tagged daily:*)"]
+ I["9. ## Wiki Schema\n(_schema page content)"]
+ J["10. ## Wiki Index\n(TOC grouped by domain)"]
+ A --> B --> C --> D --> E --> F --> G --> H --> I --> J
end
```
-> **Sub-agents** receive a simplified prompt: only the agent system prompt (sections 3–5). They do not receive `SOUL.md`, `USER.md`, or memory sections — their context is intentionally minimal and task-focused.
-
-**Token budgets for context injection:**
+> **Sub-agents** receive a simplified prompt: only the agent system prompt (sections 3–5). They do not receive `SOUL.md`, `USER.md`, or wiki sections — their context is intentionally minimal and task-focused.
-| Section | Max tokens | Notes |
-| ------------------------- | ---------- | -------------------------------------- |
-| `MEMORY.md` | 1 500 | ~6 000 characters; truncated if longer |
-| Daily notes (last 3 days) | 1 000 | Per-item truncation at 500 chars |
-| Tags index | minimal | Comma-separated list of tag names |
+The renderer for sections 7–10 lives in `packages/api/src/engine/wiki/render-wiki-context.ts`; each section is truncated independently to its token budget so a runaway page can't starve the others.
---
## Memory Tools
-Agents interact with the memory system using four tools. These tools are available to both primary agents and sub-agents.
+Agents interact with the long-term memory layer using the `wiki_*` toolset plus `list_groups`. These tools are available to primary agents. (Sub-agents receive a minimal prompt and do not get the wiki toolset by default.)
-### `save_memory` — Create or update a memory item
+| Tool | Purpose |
+| -------------- | -------------------------------------------------------------------------------------------------- |
+| `wiki_index` | Get the table of contents (title + summary + id) for every visible page. **Start here.** |
+| `wiki_search` | Full-text hybrid search (`tsvector` + `pg_trgm`) when the index doesn't surface what you need. |
+| `wiki_read` | Fetch one page's full content by id or slug (plus backlinks). |
+| `wiki_write` | Create a new page, or update one by passing `pageId`. Rebuilds `[[slug]]` backlinks every write. |
+| `wiki_delete` | Remove an owned page (also clears its shares and incoming links). |
+| `wiki_share` | Promote an owned page to a group or org-wide. |
+| `wiki_unshare` | Revoke a single share row. |
+| `list_groups` | Discover share targets — returns the user's groups plus a synthetic `org` entry. |
+| `wiki_log` | Read recent audit entries for the user's wiki activity (`wiki.create`, `wiki.update`, …). |
+| `wiki_lint` | Owner-only quality scan: duplicate slugs, orphan pages, missing `domain:*` tag, stale claims, etc. |
-Stores a piece of knowledge in the database and updates `MEMORY.md`.
+### `wiki_write` — Create or update a page
```
Input:
- content (required) — string or JSON object, max 2 000 chars
- tags (optional) — string array, max 10 tags, each max 50 chars
- memoryId (optional) — if provided, updates an existing item instead of creating new
+ pageId (optional) — if provided, update; otherwise create new
+ title (required) — page title; slug derived from this
+ summary (optional) — one-liner shown in the index; ≤200 chars (required for new pages)
+ content (required) — markdown body, ≤10 000 chars; use [[slug]] to link other pages
+ tags (optional) — ≤20 tags, each ≤50 chars; exactly one `domain:*` when non-daily tags present
+ scope (optional) — 'AMBIENT' | 'ARCHIVED' (default 'ARCHIVED')
```
**Examples the agent might call:**
```
-save_memory(
- content = "The team decided to use Zod for all input validation — no manual if/else checks.",
- tags = ["coding-standards", "validation"]
+wiki_write(
+ title = "Validation conventions",
+ summary = "All inputs validated with Zod; no manual checks",
+ content = "We use [[zod]] for every external input. See [[auth]] for an example.",
+ tags = ["domain:engineering", "validation"]
)
-save_memory(
- content = "User prefers bullet-point responses over prose for technical topics.",
- tags = ["user-preferences"]
+wiki_write(
+ title = "Daily — 2026-05-19",
+ summary = "Daily note",
+ content = "Wrapped the wiki migration; legacy /memory now 308-redirects.",
+ tags = ["daily:2026-05-19"]
)
-save_memory(
- content = "Completed: refactored auth middleware to use JWT RS256. 2026-04-24.",
- tags = ["daily:2026-04-24"]
+wiki_write(
+ pageId = "wpg_abc123",
+ title = "Validation conventions",
+ content = "...updated body with new sections...",
+ scope = "AMBIENT"
)
```
-> **Daily notes convention:** Tag with `daily:YYYY-MM-DD` to create activity journal entries. These are automatically included in the last-3-days context injection and excluded from `MEMORY.md`.
+> **Daily notes convention:** Tag with `daily:YYYY-MM-DD` to create activity-journal entries. These are automatically included in the last-3-days context injection and are exempt from the `domain:*` rule.
-> **Quota:** Each user is subject to a `maxMemoryItems` limit set by their Policy (default: 1 000 items).
-
----
+> **Ambient cap:** Promoting a page to `AMBIENT` is rejected with `WIKI_AMBIENT_FULL` once `Policy.maxAmbientPages` is reached. The error body includes the current ambient list so the agent can demote an older page first.
-### `search_memory` — Query accessible memory
+### `wiki_index` — Discover pages
-Searches all memory visible to the user (private + group-shared + org-shared) by text and/or tags.
+Returns a slim list (id, slug, title, summary, tags, scope, `isOwned`, `updatedAt`) of every page visible to the user. Filterable by `tags`, `scope`, and `ownership` (`mine` | `visible`). Limit defaults to 50, max 200.
```
-Input (at least one required):
- query (optional) — case-insensitive substring search on content text
- tags (optional) — AND logic: all specified tags must be present on the item
+wiki_index(tags = ["domain:engineering"], limit = 20)
+wiki_index(scope = "AMBIENT")
+wiki_index(ownership = "mine")
```
-Returns up to **20 results**, each with `memoryId`, `content`, `tags`, `createdAt`, and `isOwned`.
+### `wiki_search` — Full-text search
-**Examples:**
+Hybrid `tsvector` + `pg_trgm` query with snippet highlighting. Returns up to 30 hits (default 10). The result includes a `score` and a `snippet` so the agent can decide which pages to `wiki_read` in full.
```
-search_memory(query = "auth middleware")
-search_memory(tags = ["coding-standards"])
-search_memory(query = "Zod", tags = ["validation"])
-search_memory(tags = ["daily:2026-04-23"]) ← retrieve yesterday's notes
+wiki_search(query = "validation Zod")
+wiki_search(query = "auth", tags = ["domain:engineering"], limit = 5)
+wiki_search(query = "deploy", ownership = "mine")
```
----
-
-### `list_groups` — Discover share targets
-
-Returns all groups the user belongs to, plus a synthetic `org` entry for org-wide sharing.
+### `wiki_share` / `wiki_unshare` — Visibility control
```
-Output:
- [{ groupId, name, type: 'group'|'org', role: 'OWNER'|'MEMBER' }, ...]
+wiki_share(pageId = "wpg_abc123", targetType = "group", groupId = "grp_eng")
+wiki_share(pageId = "wpg_abc123", targetType = "org")
+wiki_unshare(shareId = "wsh_xyz789")
```
-The agent should call `list_groups` before calling `share_memory` to resolve valid `groupId` values.
-
----
-
-### `share_memory` — Promote a private item to group or org
-
-Shares an owned memory item with a group or the whole organisation.
-
-```
-Input:
- memoryId (required) — ID of the memory item to share
- targetType (required) — 'group' or 'org'
- groupId (required if 'group') — ID from list_groups output
-```
-
-Sharing is **idempotent** — calling `share_memory` on an already-shared item returns the existing share. Shares can be revoked, but only via the API (no UI revocation yet).
+`wiki_share` is **idempotent** — calling it again with the same target returns the existing share. Use `list_groups()` first to resolve valid `groupId` values.
**Example workflow — promoting a coding standard to the team:**
```
-1. save_memory(content="Use pnpm, never npm or yarn.", tags=["tooling"])
- → returns memoryId = "clx1234"
+1. wiki_write(title="Validation conventions", content="...", tags=["domain:engineering", "validation"])
+ → returns pageId = "wpg_abc123"
2. list_groups()
→ returns [{ groupId: "grp_eng", name: "Engineering", type: "group", role: "MEMBER" }]
-3. share_memory(memoryId="clx1234", targetType="group", groupId="grp_eng")
- → "Engineering" team members can now search and read this item
+3. wiki_share(pageId="wpg_abc123", targetType="group", groupId="grp_eng")
+ → "Engineering" team members can now wiki_search / wiki_read this page
```
+### `wiki_lint` — Owner-only quality scan
+
+Available when `Policy.wikiLintEnabled` is true (default). Surfaces:
+
+- **duplicate-slugs** — multiple pages sharing the same slug
+- **orphan** — `ARCHIVED` pages with no inbound links and no recent activity
+- **missing-domain** — pages with non-daily tags but no `domain:*` tag
+- **stale-claims** — pages that haven't been touched in a long time but claim current state
+- **broken-links** — `[[slug]]` markers that point to a non-existent page
+
+Returns up to 100 findings; the agent (or user) decides whether to fix or dismiss.
+
---
-## Memory Consolidation (Automatic)
+## Session Context Compression (Automatic)
-When a conversation session grows large enough to approach the **context window limit** (default: 65 536 tokens), Clawix automatically runs **memory consolidation**.
+Session-level context compression is a separate, lower-level mechanism from the long-term wiki. When a single conversation grows large enough to approach the **context window limit** (default: 65 536 tokens), Clawix automatically runs **session memory consolidation**: an LLM call summarises the oldest chunk of messages into a compact synthetic system message so the live session can continue without truncation losing meaning.
```mermaid
flowchart TD
@@ -356,44 +426,40 @@ flowchart TD
B -- "≥ 90%" --> E["🔴 critical warning\nconsolidation triggered"]
E --> F[LLM summarises\noldest chunk of messages]
- F --> G[Writes history_entry\nand memory_update via save_memory]
- G --> H[Old messages archived\nin DB with archivedAt timestamp]
- H --> I[Synthetic MEMORY SUMMARY\nsystem message inserted]
- I --> J[MEMORY.md updated\nin workspace file]
-
- J --> K{More chunks\nto consolidate?}
- K -- Yes, up to 5 rounds --> F
- K -- No --> L[Session continues\nwith compressed context]
+ F --> G[Old messages archived\nin DB with archivedAt timestamp]
+ G --> H[Synthetic MEMORY SUMMARY\nsystem message inserted]
+ H --> I{More chunks\nto consolidate?}
+ I -- Yes, up to 5 rounds --> F
+ I -- No --> J[Session continues\nwith compressed context]
```
-**Key facts about consolidation:**
+**Key facts:**
-- Performed by a separate LLM call using `CONSOLIDATION_MODEL` (default: `gpt-4o-mini`)
-- Up to **5 consolidation rounds** per session
-- Archived messages remain in the database — they are soft-deleted, not erased
-- The consolidation output is a new `save_memory` call that updates `MEMORY.md`
-- If validation fails 3 times, raw archival runs without memory file updates
+- Performed by a separate LLM call (`CONSOLIDATION_PROVIDER` / `CONSOLIDATION_MODEL`, default `openai` / `gpt-4o-mini`).
+- Up to **5 consolidation rounds** per session.
+- Archived messages remain in the database — they are soft-deleted, not erased.
+- Consolidation is **session-scoped**. It does **not** create wiki pages on its own — durable knowledge is still up to the agent to write via `wiki_write`.
---
-## Public vs Private Memory — Decision Guide
+## Public vs Private — Decision Guide
```mermaid
flowchart TD
- A[I want to save something to memory] --> B{Who needs to see this?}
+ A[I want the agent to remember this] --> B{Who needs to see it?}
- B -- "Only me" --> C[save_memory\nno sharing needed\nPrivate by default]
+ B -- "Only me" --> C[wiki_write\nscope='ARCHIVED' (default)\nor 'AMBIENT' if always-on]
- B -- "My team" --> D[save_memory → list_groups\n→ share_memory targetType=group]
+ B -- "My team" --> D[wiki_write → list_groups\n→ wiki_share targetType='group']
- B -- "Everyone in the org" --> E[save_memory\n→ share_memory targetType=org]
+ B -- "Everyone in the org" --> E[wiki_write\n→ wiki_share targetType='org']
C --> F{Is it a daily note?}
- F -- "Yes — activity log" --> G["Tag: daily:YYYY-MM-DD\nAppears in Recent Activity\nfor last 3 days"]
- F -- "No — durable fact" --> H["Tag: topic-name\nAppears in MEMORY.md\nand Available Tags index"]
+ F -- "Yes — activity log" --> G["Tag: daily:YYYY-MM-DD\nAppears in Daily Notes\n(last 3 days)"]
+ F -- "No — durable knowledge" --> H["Tag: domain: + free-form\nIndexed in Wiki Index\nReachable via [[slug]]"]
- D --> I[Group members can\nsearch_memory to find it\nisOwned = false in results]
- E --> J[All users can\nsearch_memory to find it\nisOwned = false in results]
+ D --> I[Group members can\nwiki_search / wiki_read it\nisOwned = false in results]
+ E --> J[All users can\nwiki_search / wiki_read it\nisOwned = false in results]
```
---
@@ -404,8 +470,6 @@ flowchart TD
workspace/
├── SOUL.md ← Agent personality (injected into every system prompt)
├── USER.md ← User profile (injected into every system prompt)
-├── memory/
-│ └── MEMORY.md ← Long-term memory file (auto-maintained by agent)
├── projector/ ← UI output templates (unrelated to memory)
│ ├── color-palette/
│ └── image-sharpener/
@@ -416,50 +480,60 @@ workspace/
Default `WORKSPACE_BASE_PATH`: `./data`
+Long-term memory pages do **not** live in this folder — they are `WikiPage` rows in Postgres and are browsed at `/wiki`.
+
---
-## Memory Limits Reference
-
-| Limit | Value | Source |
-| --------------------------- | --------------------------- | ----------------------------------- |
-| Max memory items per user | 1 000 (policy default) | `Policy.maxMemoryItems` |
-| Max content length per item | 2 000 chars | `save_memory` input validation |
-| Max tags per item | 10 | `save_memory` input validation |
-| Max tag length | 50 chars | `save_memory` input validation |
-| Max search results | 20 items | `search_memory` output |
-| MEMORY.md token budget | 1 500 tokens (~6 000 chars) | `MEMORY_FILE_TOKEN_BUDGET` |
-| Daily notes loaded | Last 3 days | `DAILY_NOTES_DAYS` |
-| Daily notes token budget | 1 000 tokens | `DAILY_NOTES_TOKEN_BUDGET` |
-| Per-item truncation | 500 chars | `MEMORY_ITEM_MAX_CHARS` |
-| Context window threshold | 65 536 tokens | `CONTEXT_WINDOW_TOKENS` |
-| Max consolidation rounds | 5 | hard-coded in consolidation service |
+## Wiki Limits Reference
+
+| Limit | Value | Source |
+| --------------------------- | ------------------- | ------------------------------ |
+| Max AMBIENT pages per user | 5 (policy default) | `Policy.maxAmbientPages` |
+| Max content length per page | 10 000 chars | `wiki_write` input validation |
+| Max summary length | 200 chars | `wiki_write` input validation |
+| Max tags per page | 20 | `wiki_write` input validation |
+| Max tag length | 50 chars | `wiki_write` input validation |
+| `wiki_index` page limit | Default 50, max 200 | `wiki_index` input validation |
+| `wiki_search` result limit | Default 10, max 30 | `wiki_search` input validation |
+| `wiki_lint` finding cap | 100 | `wiki_lint` input validation |
+| Context window threshold | 65 536 tokens | `CONTEXT_WINDOW_TOKENS` |
+| Max consolidation rounds | 5 | session-consolidation service |
+
+Per-section token budgets for the context injection (Long-term Memory / Daily Notes / Wiki Schema / Wiki Index) live alongside the renderer in `engine/wiki/render-wiki-context.ts` and are independently truncated.
---
-## Editing Memory Files Manually
+## Editing Manually
-All workspace files — including `SOUL.md`, `USER.md`, and `memory/MEMORY.md` — can be viewed and edited directly in the **Workspace** file browser.
+### Editing wiki pages
-1. Go to **Workspace** in the sidebar.
-2. Click a file or folder to navigate.
-3. Click a file row to open the preview panel (right side).
-4. Click the **pencil (edit)** icon in the preview header to open the inline editor.
-5. Make changes and save.
+Open **`/wiki`** in the dashboard. Select a page on the left to load its editor on the right — change title, summary, content, tags, scope, and group/org sharing. Use **`/wiki/schema`** to edit the `_schema` page (split-pane source + preview).
-Changes to these files take effect on the **next agent run** — in-flight sessions are not affected.
+Changes take effect on the **next agent run** — in-flight sessions are not affected.
+
+### Editing workspace files
+
+`SOUL.md` and `USER.md` can be viewed and edited directly in the **Workspace** file browser.
+
+1. Go to **Workspace** in the sidebar.
+2. Click a file row to open the preview panel (right side).
+3. Click the **pencil (edit)** icon in the preview header to open the inline editor.
+4. Make changes and save.
-> **Caution:** Direct edits to `MEMORY.md` are valid but may be overwritten by the next consolidation cycle if the session context grows large. Prefer using `save_memory` via conversation for durable facts; use manual edits for structural corrections or seeding initial context.
+> **Caution:** `USER.md` is also kept up to date by the agent itself via the `edit_file` tool. Manual edits and agent edits both work; the agent will not overwrite verbatim sections unless it has a reason to update them.
---
## Troubleshooting
-| Symptom | Likely cause | Fix |
-| -------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------- |
-| Agent doesn't remember something from last session | Item was never saved, or MEMORY.md wasn't updated | Ask the agent to explicitly `save_memory` the fact with a descriptive tag |
-| `search_memory` returns nothing for a group share | User is not a member of the group | Admin adds user to the group via the Users settings page |
-| MEMORY.md keeps getting truncated | Content exceeds 1 500-token budget | Remove stale entries manually or break into more specific tags so only relevant sections load |
-| Daily notes not appearing in context | Notes are older than 3 days | Use `search_memory(tags=["daily:YYYY-MM-DD"])` to retrieve older notes explicitly |
-| Memory quota exceeded | User hit `maxMemoryItems` policy limit | Admin increases limit via Policy settings, or user deletes old items via the API |
-| Consolidation running unexpectedly | Session exceeded 75% of `CONTEXT_WINDOW_TOKENS` | Normal behaviour — consolidation preserves knowledge; no action needed |
-| Shared memory not visible to group member | Share was revoked (`isRevoked = true`) | Re-share via `share_memory` or check revocation status via the API |
+| Symptom | Likely cause | Fix |
+| -------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
+| Agent doesn't remember something from last session | No wiki page was ever written for the fact | Ask the agent to `wiki_write` the fact with a `domain:*` tag, and `scope='AMBIENT'` if always-on |
+| `wiki_search` returns nothing for a group share | User is not a member of the group, or share was revoked | Verify membership via Groups page; re-share if revoked |
+| `wiki_write` fails with `WIKI_AMBIENT_FULL` | Reached `Policy.maxAmbientPages` cap | Demote (set `scope='ARCHIVED'`) one of the listed AMBIENT pages first, then retry |
+| Daily notes not appearing in context | Notes are older than 3 days | Use `wiki_search(tags=["daily:YYYY-MM-DD"])` or `wiki_read` to retrieve older notes explicitly |
+| Long-term Memory section truncated | AMBIENT page bodies exceed the section's token budget | Split a long page, or move some pages back to `ARCHIVED` so the budget fits |
+| Wiki Schema page can't be edited via `wiki_write` | `_schema` is reserved — must use `/wiki/schema` or its API | Edit at `/wiki/schema` (or `PATCH /wiki/schema`); developer/admin role required |
+| Consolidation running unexpectedly | Session exceeded 75 % of `CONTEXT_WINDOW_TOKENS` | Normal behaviour — consolidation preserves working context; no action needed |
+| `/memory` link from old bookmarks 404s | Replaced by `/wiki` | Use `/wiki`; old `/memory` URL 308-redirects automatically |
+| Shared page not visible to group member | Share row was revoked (`wiki_unshare` called) | Re-share via `wiki_share` and verify with `list_groups` |