ClickHouse Loom
OfficialServer Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
Loom-first mode active for this conversation.
1. Session context. At the start of a substantial task, call loom_context_pack once if you need a bounded bundle of profile, relevant memories, procedures, and optional docs. For simple activation, this primer is already enough.
2. Recall lookup order. When I ask about preferences, decisions, family/relationships, work, bills, contracts, documents I've uploaded, or 'what is X' / 'what do I know about Y':
a. Call loom_search once. It searches memory, profile, knowledge (your namespaces' documents and the collections you can read; loom_op (op collection.list) names those collections), and conversations server-side in one round trip.
b. If it returns nothing relevant, fall through to native memory / past-conversation context — don't surface 'not in Loom' as a final answer.
3. Save. On any remember/save/store intent, call loom_memory_set. Loom persists across Claude Desktop, Claude Code, Cursor, and any other AI tool the user runs.
4. Shape. loom_memory_set takes one plain-text claim per readable key (<scope>/<kind>/<id>): send text or the object, never json.dumps twice or base64; a document or anything over ~2 KB goes to loom_op (op knowledge.add); leases and pointers go to loom_op (op working_memory.set); a revision rewrites the same key. A document for a shared collection (col-…) goes to loom_op (op knowledge.add) with the collection's name as namespace.
5. Defaults. My default Loom namespace is local — use it unless I explicitly name another. Don't ask which namespace; trust the default.
6. Native memory. Use as fallback when Loom returns nothing, or as primary store for Claude-only ephemeral scratchpad. For anything cross-tool or shared with teammates, write to Loom.
7. Using Loom. loom_op (op mentor.guide) returns how to use Loom: where each kind of state goes and how to read what comes back (part: "reference" lists every plane).
Default Loom workspace: namespace=local, agent=claude-desktop. The server fills these in automatically when you omit them — call this tool with ONLY the action-specific args (e.g. query, memory_key, value) and the defaults will be applied. Don't ask the user which namespace; the server knows.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| loom_memory_getA | WHAT: Fetch one memory by exact |
| loom_memory_setA | Save a fact to Loom — shared across every AI tool the user runs; native memory is the Claude-only scratchpad. Call this proactively whenever the user states a personal fact, decision, preference, or current state — even without 'remember' or 'save'. Declarative statements ARE save triggers: 'my X is Y', 'I prefer X over Y', 'we decided X', 'we're at X', 'I deploy on X' — one call per fact. Don't search before saving. A stated fact is a write, not a recall; the server dedups. Revision policy: if a read this session returned the key of a fact that has now changed or got more precise, update it under that same key with memory.update — never save a second copy and never delete + re-save. A fact about a new subject or scope gets its own memory_key (include the project / scope token in the key). Auto-tag from scope words: 'for billing, X is Y' → Do NOT save: questions, code help, world knowledge, acknowledgements, hypotheticals, echoes of your own words. Writes land in ONE namespace (the caller's home); pass A fact with a natural lifetime gets one at write time. A deadline, a temporary state ('on call this week'), a rotating value: pass |
| loom_memory_pinA | WHAT: Save a standing fact and protect it. A pinned memory is never evicted by a later conflicting write: the newer fact is stored beside it and answers 409 PINNED_CONFLICT, and pinned rows rank ahead of unpinned ones in file context. Same arguments as memory.set; pinned is forced on. WHEN: The user marks a fact as permanent or asks for it to be kept explicitly: 'always remember X', 'never forget this', 'pin this', a hard constraint stated as standing ('I am allergic to penicillin', 'deploys freeze on Fridays', 'the prod DB is read-only'). WHEN NOT: An ordinary fact, preference or state — that is memory.set, the default for almost every save; a fact that must not change or be deleted at all (memory.lock); a topic that must not be remembered (blacklist.add, refused to a token bounded to one user). ARGS: memory_key, value; optional tags, ttl_seconds, on_expire. Server fills identity. |
| loom_memory_deleteA | WHAT: Tombstone a memory by key (14-day recovery in the dashboard). The row is found across every agent and session in the namespace; |
| loom_memory_lockA | WHAT: Lock one memory against a class of writes. read_only refuses a changed value, a changed expiry and deletion; no_delete lets the value change but refuses tombstone/redact/clear/consolidate-away. Guarded ops answer 423 LOCKED with the reason. Only an admin loosens. WHEN: 'make sure this never changes', 'freeze the deploy window', 'this must not be deleted / forgotten', 'protect this fact', 'legal hold on X', 'keep this exactly as is'. WHEN NOT: To keep a fact ahead of later conflicting writes (that is memory.pin) or to share it (memory.promote, via loom_op). Never lock on inferred intent. ARGS: memory_key, mode (read_only | no_delete), reason (required), optional until / ttl_seconds. Server fills identity. |
| loom_memory_applyA | WHAT: One change over many EXISTING memories, previewed first; it never creates one (save facts with loom_memory_set, one per fact). target names exactly one of keys | filter (tags_any/tags_all, memory_type, key_prefix, created_before/after, confidence_lte, source_trace) | search {query}; limit is required for filter/search; action is delete | expire | lock | label | demote with its block (expire {ttl_seconds|until, on_expire}, lock {mode}, label {tags, mode add|replace|remove}, demote {confidence_factor | confidence_delta}); reason is required. dry_run defaults to TRUE and lists every row it would touch (would_apply / refused); call again with dry_run=false to write. A locked row comes back as status 'refused', never an error. WHEN: anything that names a set rather than one key — 'forget everything about the Q3 migration', 'these are getting stale, lower their confidence', 'tag every runbook as ops', 'lock everything I saved about the incident', 'expire the meeting notes in 30 days'. WHEN NOT: One key (memory.delete / memory.set / memory.lock). A whole agent or user (memory.clear, admin, via loom_op); a user's request to delete all their data is erasure.request (via loom_op where it is not listed). Never skip the dry run when the user has not seen the list. |
| loom_memory_updateA | Update a saved fact by memory_key: the operation for "the fact changed or got more specific". WHEN: a read (memory.get or loom_search) returned this key and the user now states a new value, a correction, or a more precise version of it — 'the deploy day moved to Thursday', 'the budget is actually 40k'. It keeps the row's tags, confidence, expiry, lock and history; memory.set would write a new version blind. Revision policy: if a read this session returned the key of a fact that has now changed or got more precise, update it under that same key with memory.update — never save a second copy and never delete + re-save. A fact about a new subject or scope gets its own memory_key (include the project / scope token in the key). Do NOT use it for a genuinely new fact — call memory.set. Resolves the key across the namespace; pass agent/user_id/session_id only to narrow when the key is live under several writers (409 AMBIGUOUS_KEY lists them). updated=false with reason=not_found means the key has no live row — save it with memory.set instead. Pass if_match_sha256 from the read for a no-clobber update. Given a memory_id rather than a key, call memory.update_by_id (via loom_op where it is not listed). |
| loom_memory_historyA | WHAT: Every recorded version of one memory_key, newest first, tombstoned and redacted versions included; empty when the key was never written. WHEN: 'what did I say about X before', 'when did this change', or what a key held earlier. WHEN NOT: The current value alone is memory.get. ARGS: memory_key; optional limit (default 50). |
| loom_context_packA | Startup context pack for this session, once near the start of a substantial task: profile, relevant memories, matching procedures, optionally docs/conversations, in one prompt-sized bundle. |
| loom_blacklist_addA | WHAT: Every later memory write in the pattern's |
| loom_opA | Run an op this list doesn't show (such as memory.related, callable by name). |
| loom_searchA | Unified search across the user's Loom content — memory (facts, preferences, decisions), profile (always-loaded persona sections), knowledge (uploaded documents) and past conversations — four searches, one round-trip; under a code scope, also the repository's docs and decisions. This is THE search tool: call it before answering any 'what do I / what did we decide / have we discussed X' question. One call per question. If the answer is in the response, use it; if it is empty, fall through to native memory rather than declaring 'nothing in Loom'. Re-call on a NEW question, never on the same question in the same turn. Paging. Namespaces are selected server-side (your own memory-kind namespaces, up to a cap; code/QA indexes have their own tools); no namespace argument. Do NOT call for general knowledge, arithmetic, or code/syntax help. |
| loom_activateA | Loom activation — call this tool IMMEDIATELY, without any other tool calls or clarifying questions, whenever the user says any of:
Do NOT call The response is a primer with the user's always-loaded context (persona / preferences / goals) inlined as a Calling this is a one-shot setup gesture for the conversation. Subsequent user messages should be answered using the primer's guidance — not by calling this tool again. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| loom | Activate Loom for this conversation. Loads your persona block + sets memory/recall to route through Loom. Pick this once at the start of a new chat — same effect as typing 'use loom' but discoverable from the slash-command picker. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| Loom primer | Your always-loaded context — persona / preferences / goals — plus how to route memory and recall through Loom. Read at the start of a conversation. |
TDQS
Scored across 13 tools
The set has several overlapping write/mutate paths — memory_set vs memory_update vs memory_pin vs memory_apply vs memory_lock — that all touch stored facts, and delete vs blacklist_add vs apply(delete) all remove data. The WHAT/WHEN/WHEN NOT structure does a lot of work to separate them, but an agent must read carefully, and the descriptions refer to phantom names (memory.set, memory.update, memory.delete) that are not the actual tool names, adding a misselection hazard.
All tools are snake_case under a uniform loom_ prefix, and the memory CRUD family (loom_memory_set/get/update/delete/history) is consistently verb-last. Minor deviations exist — loom_activate and loom_search drop the resource segment while loom_context_pack is noun-only — and the bodies reference tools by a different dotted naming scheme than the actual tool names.
13 tools is well within a healthy range for a memory service covering reads, writes, bulk apply, locking, history, and session bootstrap. Each tool earns its place: no obvious duplicates that could simply be folded together.
Core lifecycle is strongly covered — create (set/pin), read (get/search/history), update, delete, bulk apply, locking, blacklist, plus a context pack and activation primer. Gaps (whole-namespace clear, erasure requests, related/evidence/digests) are handled only through the generic loom_op escape hatch, whose arguments are not documented in the tool surface.