Memory
How to use the Quotient SDK to read and write Memory programmatically
Overview
Quotient exposes its memories via API, making it easy to integrate with other systems and agents. For example, you can fetch Quotient's marketing-related memories inside of a coding agent to help it write better copy for your website. Or you can go in the opposite direction — you can have your AI personal assistant create memories directly in Quotient, or you can set up an integration to write to Quotient's memory from your company knowledge store.
The Memory API models your content as a path-aware filesystem. Content is stored internally as Quotient Rich Text but the SDK uses markdown as the wire format for simplicity.
All paths start with /. The SDK provides separate ls and cat methods
with unambiguous return types — no need to check what you got back.
| Endpoint | API Key | Server SDK | Client SDK |
|---|---|---|---|
| List folder | private only | memory.ls() | — |
| Read document | private only | memory.cat() | — |
| Write document | private only | memory.write() | — |
| Create folder | private only | memory.mkdir() | — |
| Delete | private only | memory.rm() | — |
| Search | private only | memory.search() | — |
import { QuotientServer } from "@quotientjs/server";
const quotient = new QuotientServer({
privateKey: process.env.QUOTIENT_PRIVATE_KEY!,
});
List Folder Contents
memory.ls(options)
GET /api/v0/memory/{path}Auth: private key only · scope:
MEMORY_READ
| Param | Type | Required | Description |
|---|---|---|---|
path | Path | Yes | Folder path (must start with /) |
deep | boolean | No | If true, returns recursive tree with nested children |
// List direct children of root
const root = await quotient.memory.ls({ path: "/" });
// root.items → [{ type: "folder", name: "projects", path: "/projects/", ... }, ...]
// List direct children of a specific folder
const projects = await quotient.memory.ls({ path: "/projects" });
// Get full recursive tree
const tree = await quotient.memory.ls({ path: "/", deep: true });
Returns: { items: MemoryFolderItem[] }
Returns 400 if path is a document. Returns 404 if path doesn't exist.
Read a Document
memory.cat(options)
GET /api/v0/memory/{path}Auth: private key only · scope:
MEMORY_READ
| Param | Type | Required | Description |
|---|---|---|---|
path | Path | Yes | Document path (must start with /) |
const doc = await quotient.memory.cat({ path: "/projects/budget" });
// doc.name → "budget"
// doc.content → "# Q1 Budget\n\nTotal: $50,000\n..."
// doc.tags → ["brand"]
// doc.pinned → false
// doc.updatedAt → "2024-01-15T10:30:00.000Z"
Returns:
| Field | Type | Description |
|---|---|---|
name | string | Document name (last path segment) |
path | string | Full document path |
content | string | Markdown content |
tags | string[] | Assigned tags |
pinned | boolean | Whether the document is pinned |
updatedAt | string | ISO timestamp |
createdAt | string | ISO timestamp |
Returns 400 if path is a folder. Returns 404 if path doesn't exist.
Write a Document
memory.write(options)
POST /api/v0/memory/{path}Auth: private key only · scope:
MEMORY_WRITE
Creates or updates a document. Parent folders are auto-created.
| Param | Type | Required | Description |
|---|---|---|---|
path | Path | Yes | Document path |
title | string | No | Document title (derived from path if omitted) |
content | string | No | Markdown content. Omit for metadata-only updates |
tags | string[] | No | Replaces all tags. Pass [] to clear |
pinned | boolean | No | Pin or unpin the document |
// Upsert — creates if missing, updates if exists
await quotient.memory.write({
path: "/projects/budget",
content: "# Q1 Budget\n\nTotal: $50,000",
});
// Write with tags and pinning
await quotient.memory.write({
path: "/brand/voice",
content: "# Brand Voice\n\nWarm, confident, and direct.",
tags: ["brand", "tone"],
pinned: true,
});
// Metadata-only update (document must exist)
await quotient.memory.write({
path: "/projects/budget",
tags: ["brand"],
});
Returns:
| Field | Type | Description |
|---|---|---|
name | string | Document name |
path | string | Full document path |
tags | string[]? | New tags (included when tags were set) |
pinned | boolean? | New pinned state (included when pinned was set) |
When content is omitted, the document must already exist — returns 404 if
the path is not a document.
Create a Folder
memory.mkdir(options)
POST /api/v0/memory/{path}Auth: private key only · scope:
MEMORY_WRITE
| Param | Type | Required | Description |
|---|---|---|---|
path | Path | Yes | Folder path |
name | string | No | Folder name (derived from path if omitted) |
const folder = await quotient.memory.mkdir({
path: "/projects",
name: "Projects",
});
mkdir is idempotent — calling it on an existing folder returns the existing
folder instead of an error.
Delete Memory
memory.rm(options)
DELETE /api/v0/memory/{path}Auth: private key only · scope:
MEMORY_WRITE
| Param | Type | Required | Description |
|---|---|---|---|
path | Path | Yes | Path to archive (auto-detects document vs folder) |
// Archive a document
await quotient.memory.rm({ path: "/projects/budget" });
// Archive a folder and all its contents
await quotient.memory.rm({ path: "/projects" });
Returns: { success: boolean }
When called on a document, archives the document. When called on a folder, archives the folder and all its descendants (cascading delete).
Search
memory.search(options)
POST /api/v0/memory/searchAuth: private key only · scope:
MEMORY_READ
Runs a vector similarity search over all memory chunk embeddings.
| Param | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural-language search query |
tags | string[] | No | Filter to documents with at least one of these tags |
const results = await quotient.memory.search({
query: "What is our brand tone?",
});
for (const chunk of results.results) {
console.log(chunk.memoryPath); // e.g. "/brand/voice"
console.log(chunk.content); // the matching chunk text
console.log(chunk.similarity); // cosine similarity score (0–1)
}
// Tag-filtered search
const brandResults = await quotient.memory.search({
query: "brand guidelines",
tags: ["brand", "tone"],
});
Returns: { results: SearchMemoryResult[] }
| Field | Type | Description |
|---|---|---|
id | string | Chunk ID |
memoryId | string | Parent document ID |
memoryPath | string | Parent document path |
content | string | Chunk text |
headingPath | string[] | Heading breadcrumb for the chunk's location |
position | number | Chunk index within the document |
similarity | number | Cosine similarity score (0–1, higher is more similar) |
Results are ordered by descending similarity. The default limit is 10 results.
Tags
Tags are flat string labels you attach to memory documents. They serve two purposes: skill scoping (agents load only memories matching their tags) and filtering (search, UI).
Platform tags
A fixed set of well-known labels:
| Tag | Category | Description |
|---|---|---|
email | Channel | Email campaign content |
blog | Channel | Blog and long-form writing |
social | Channel | Social media content |
tone | Domain | Voice and tone guidelines |
audience | Domain | Audience personas and segments |
brand | Domain | Brand identity and values |
competitors | Domain | Competitive intelligence |
products | Domain | Product information |
Referential tags
Link a memory to a specific entity using the <prefix>:<id> format:
| Format | Example | Description |
|---|---|---|
user:<cuid> | user:clx1a2b3c4d5e6f7g8h9 | Tie memory to a specific user |
await quotient.memory.write({
path: "/users/alice/preferences",
content: "Prefers formal tone. Focuses on ROI.",
tags: ["user:clx1a2b3c4d5e6f7g8h9", "audience"],
});
Tags are always replaced wholesale — there is no "add one tag" operation. To add a tag to an existing set, read the current tags, append, and write back.
const doc = await quotient.memory.cat({ path: "/brand/voice" });
await quotient.memory.write({
path: "/brand/voice",
tags: [...doc.tags, "tone"],
});
Pinning
Pinned documents are always loaded into agent context, regardless of what the agent is doing. Use pinning for critical, always-relevant content — brand voice guidelines, compliance rules, or high-priority personas.
await quotient.memory.write({ path: "/brand/voice", pinned: true });
await quotient.memory.write({ path: "/brand/voice", pinned: false });
Use pinning sparingly — every pinned document consumes context tokens on every agent invocation. Tag-based loading is more efficient for content that is only relevant in certain contexts.
Indexing and Chunking
When you write a document, Quotient automatically:
- Chunks the content by heading structure and paragraph boundaries
- Embeds each chunk using a Voyage embedding model
- Stores the embeddings for fast vector similarity queries
This happens asynchronously after the write completes — the document is
immediately readable via cat, but chunks may not be searchable for a few
seconds after a write. Re-indexing also triggers automatically whenever content
changes.