HTTP API 文档:所有端点的请求/响应格式。服务默认监听
127.0.0.1:4318。
Base URL: http://localhost:4318
All endpoints accept and return JSON. Set Content-Type: application/json for POST requests.
Workflow observation endpoints use a dedicated append-only store under data/workflow-observations. They do not write into the regular memory index or durable memory categories.
GET /v1/health
Returns server status.
Response:
{
"status": "ok",
"version": "1.0.0",
"totalMemories": 1247,
"timestamp": "2026-03-15T10:00:00.000Z"
}POST /v1/recall
Semantic search across scoped memories. Best for quick, conversational lookups when the caller already knows the active scope or session.
主动回忆:用关键词搜索相关记忆,返回按相关度排序的结果。默认需要显式
scope、sessionId,或环境里的默认 scope;只有allScopes=true才会跨 scope 搜索。
Request:
{
"query": "Docker bot debugging",
"scope": "project:docker-bot",
"limit": 5,
"minScore": 0.5
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | yes | — | Search query (2-3 key nouns work best) |
scope |
string | no | — | Explicit shared scope for the search |
sessionId |
string | no | — | Session identifier used to infer session:{id} scope |
allScopes |
boolean | no | false |
Explicitly allow cross-scope search |
limit |
number | no | 5 | Max results (1-20) |
minScore |
number | no | 0 | Minimum relevance score (0-1). 0 = no filter |
category |
string | no | — | Filter: profile, preferences, entities, events, cases, patterns |
profile |
string | no | "default" |
Retrieval profile: default, writing, debug, fact-check |
Response:
{
"results": [
{
"id": "a1b2c3d4",
"text": "Docker bot crash troubleshooting: check logs first with docker logs...",
"category": "cases",
"tier": "core",
"source": "cc",
"scope": "cc:a1b2c3d4",
"score": 0.87,
"date": "2026-03-04",
"boundary": {
"layer": "evidence",
"authority": "transcript-ingest",
"conflictPolicy": "append-only",
"originalCategory": "cases"
},
"canonicalKey": null,
"promotedFrom": null
}
],
"query": "Docker bot debugging",
"profile": "default",
"totalMemories": 1247
}POST /v1/auto-recall
Compose startup continuity context and then run a focused scoped search in one call. Best for agent frameworks that want a single "recall at task start" hook without exposing extra MCP tools.
自动回忆:先做
resume_context式的连续性恢复,再在同一 scope 下补一轮 focused search。适合 agent SDK / HTTP 集成在每次任务开始时直接调用。
Request:
{
"message": "RecallNest continuity",
"scope": "project:recallnest",
"limit": 3,
"limitPerSection": 3,
"includeLatestCheckpoint": true,
"profile": "default"
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
message |
string | yes | — | Raw user message or task-start query |
task |
string | no | message |
Optional broader task hint for resume composition |
scope |
string | no | — | Explicit shared scope |
sessionId |
string | no | — | Session identifier used to recover the latest checkpoint and infer scope |
allScopes |
boolean | no | false |
Explicitly allow cross-scope focused search |
limit |
number | no | 5 | Max focused search results (1-20) |
limitPerSection |
number | no | 3 | Max items per resume section (1-6) |
includeLatestCheckpoint |
boolean | no | true |
Whether to include the latest checkpoint in the resume payload |
category |
string | no | — | Optional focused search category filter |
profile |
string | no | "default" |
Retrieval profile: default, writing, debug, fact-check |
Response:
{
"mode": "resume+search",
"query": "RecallNest continuity",
"profile": "default",
"resolvedScope": "project:recallnest",
"searchSkippedReason": null,
"resume": {
"summary": "Loaded 3 stable context item(s), 2 pattern(s), and 1 case(s). Latest checkpoint from codex-2026-03-16-001 on 2026-03-16: Implement startup continuity for fresh windows.",
"resolvedScope": "project:recallnest",
"stableContext": [
"Entity: RecallNest continuity revolves around three primitives."
],
"relevantPatterns": [
"At task start, run search_memory before coding."
],
"recentCases": [
"Case: RecallNest scope fallback cleanup"
],
"latestCheckpoint": {
"sessionId": "codex-2026-03-16-001",
"resolvedScope": "project:recallnest",
"summary": "Implement startup continuity for fresh windows",
"updatedAt": "2026-03-16T05:00:00.000Z"
},
"generatedAt": "2026-03-16T05:10:00.000Z"
},
"results": [
{
"id": "a1b2c3d4",
"text": "RecallNest continuity revolves around three primitives: store_memory, checkpoint_session, resume_context.",
"category": "entities",
"scope": "project:recallnest",
"score": 0.91
}
],
"count": 1
}If no explicit or inferred scope is available, mode becomes resume-only, results is empty, and searchSkippedReason explains why focused search was skipped.
POST /v1/store
Store a new durable memory entry.
存入长期记忆:适合 profile、preferences、entities、cases、patterns 这类跨窗口仍然有价值的信息。
Request:
{
"text": "User prefers code changes to be committed and pushed immediately",
"category": "preferences",
"source": "agent",
"tags": ["workflow", "git"],
"importance": 0.85
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
text |
string | yes | — | Memory content |
category |
string | no | "events" |
One of: profile, preferences, entities, events, cases, patterns |
source |
string | no | "manual" |
One of: manual, agent, api |
scope |
string | yes | — | Required explicit scope such as project:recallnest or session:abc123 |
importance |
number | no | 0.7 | Importance score (0-1), affects decay and ranking |
tags |
string[] | no | [] |
Optional tags, max 8 items |
canonicalKey |
string | no | derived from content | Optional stable key for dedupe/update semantics |
Response:
{
"id": "e5f6g7h8-...",
"stored": true,
"disposition": "stored",
"storedAt": "2026-03-16T02:10:00.000Z",
"category": "preferences",
"scope": "memory:agent",
"canonicalKey": "preferences:user-prefers-code-changes-to-be-committed-and-pushed-immediately"
}If the same canonicalKey is already occupied by a different durable category, RecallNest returns disposition = "conflict" plus a conflictId instead of silently creating a second durable owner.
For slot-aware preferences, RecallNest now derives structured keys instead of collapsing everything into a broader same-topic key. Examples:
- atomic brand-item preference:
我喜欢吃麦当劳的麦辣鸡翅->preferences:brand-item:麦当劳:麦辣鸡翅 - reply-style preference:
User prefers concise, direct replies.->preferences:reply-style:concise:direct - tool-choice preference:
Uses Bun over Node.->preferences:tool-choice:bun:over:node
POST /v1/capture
Store multiple structured memories in one request.
批量结构化写入:适合上层 agent 一次性提炼多条 durable memory 后统一写入。
Request:
{
"scope": "agent:codex",
"source": "agent",
"defaultImportance": 0.7,
"memories": [
{
"text": "RecallNest is the shared memory layer for Claude Code, Codex, and Gemini CLI",
"category": "entities"
},
{
"text": "Use search_memory at task start",
"category": "patterns",
"importance": 0.9,
"tags": ["workflow", "memory"]
}
]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
scope |
string | no | — | Default scope applied to items that do not specify one |
source |
string | no | "agent" |
Default source for items that do not specify one |
defaultImportance |
number | no | 0.7 | Default importance for items that do not specify one |
memories |
array | yes | — | 1-20 structured memory items |
Each memory item supports:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
text |
string | yes | — | Memory content |
category |
string | no | "events" |
Durable memory category |
importance |
number | no | envelope default | Optional per-item override |
scope |
string | no | envelope scope | Optional per-item override; every stored memory still needs a scope via the envelope or item override |
source |
string | no | envelope source | Optional per-item override |
tags |
string[] | no | [] |
Optional tags |
canonicalKey |
string | no | derived from content | Optional stable key for dedupe/update semantics |
Response:
{
"stored": 2,
"memories": [
{
"id": "a1b2c3d4-...",
"text": "RecallNest is the shared memory layer for Claude Code, Codex, and Gemini CLI",
"category": "entities",
"scope": "agent:codex",
"source": "agent",
"storedAt": "2026-03-16T02:11:00.000Z",
"disposition": "stored",
"canonicalKey": "entities:recallnest-is-the-shared-memory-layer-for-claude-code-codex-and-gemini-cli"
}
]
}Each item may also carry disposition = "conflict" and a conflictId when batch input reuses an existing canonicalKey under a different durable category.
POST /v1/pattern
Store a reusable workflow as durable patterns memory.
专门写 workflow pattern:适合把“什么时候用、怎么做、做完得到什么”这种可复用流程沉淀成高质量
patterns记忆。
Request:
{
"title": "Cross-window continuity handoff",
"trigger": "When opening a fresh terminal window for the same project",
"steps": [
"Call resume_context before coding",
"Review stable context and latest checkpoint",
"Save checkpoint_session before leaving the window"
],
"outcome": "The next window recovers decisions and next actions faster",
"tools": ["resume_context", "checkpoint_session"],
"importance": 0.9,
"source": "agent",
"tags": ["continuity", "handoff"]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
title |
string | yes | — | Short workflow title |
trigger |
string | yes | — | When this workflow should be used |
steps |
string[] | yes | — | Ordered workflow steps, 1-8 items |
outcome |
string | no | — | Optional expected outcome |
tools |
string[] | no | [] |
Optional tools, commands, or interfaces involved |
importance |
number | no | 0.82 | Importance score (0-1) |
scope |
string | yes | — | Required explicit scope such as project:recallnest or session:abc123 |
source |
string | no | "agent" |
One of: manual, agent, api |
tags |
string[] | no | [] |
Optional tags; workflow and pattern are auto-added |
canonicalKey |
string | no | derived from title | Optional stable key for dedupe/update semantics |
Response:
{
"id": "f0e1d2c3-...",
"stored": true,
"category": "patterns",
"title": "Cross-window continuity handoff",
"scope": "memory:agent",
"tags": ["continuity", "handoff", "workflow", "pattern"],
"storedAt": "2026-03-16T08:10:00.000Z"
}POST /v1/case
Store a reusable problem-solution case as durable cases memory.
专门写 problem-solution case:适合把“遇到什么问题、怎么解决、最后效果怎样”这种可复用经验沉淀成高质量
cases记忆。
Request:
{
"title": "RecallNest sparse startup context cleanup",
"problem": "resume_context was returning noisy transcript fragments instead of a clean project handoff",
"context": "This happened in a fresh RecallNest window after continuity setup was already in place",
"solutionSteps": [
"Filter low-signal transcript fragments from stable recall",
"Backfill stable context from checkpoint focus, summary, and decisions",
"Use a lightweight task focus fallback only when no checkpoint-backed context is available"
],
"outcome": "Fresh windows now recover cleaner RecallNest continuity context",
"tools": ["resume_context", "checkpoint_session"],
"importance": 0.9,
"source": "agent",
"tags": ["continuity", "startup-context"]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
title |
string | yes | — | Short case title |
problem |
string | yes | — | What problem happened |
context |
string | no | — | Optional context or preconditions |
solutionSteps |
string[] | yes | — | Ordered solution steps, 1-8 items |
outcome |
string | no | — | Optional result or resolution |
tools |
string[] | no | [] |
Optional tools, commands, or interfaces involved |
importance |
number | no | 0.84 | Importance score (0-1) |
scope |
string | yes | — | Required explicit scope such as project:recallnest or session:abc123 |
source |
string | no | "agent" |
One of: manual, agent, api |
tags |
string[] | no | [] |
Optional tags; case and solution are auto-added |
canonicalKey |
string | no | derived from title | Optional stable key for dedupe/update semantics |
POST /v1/promote
Promote an evidence memory into durable memory.
显式升级:把 transcript / import evidence 中的高价值片段升级成 durable memory,而不是让 raw ingest 直接冒充长期事实。
Request:
{
"memoryId": "12345678-1234-1234-1234-123456789abc",
"text": "User prefers concise, direct replies.",
"category": "preferences",
"canonicalKey": "user-reply-style",
"tags": ["writing"]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
memoryId |
string | yes | — | Evidence memory ID or unique prefix |
text |
string | no | source text | Optional cleaned durable text |
category |
string | no | inferred from source | Target durable category |
importance |
number | no | 0.78 | Importance score (0-1) |
scope |
string | yes | — | Required explicit target scope such as project:recallnest or session:abc123 |
source |
string | no | "agent" |
Promotion source label |
tags |
string[] | no | [] |
Optional tags |
canonicalKey |
string | no | derived from text | Optional stable key for dedupe/update semantics |
Response:
{
"id": "c0ffee00-...",
"stored": true,
"disposition": "promoted",
"category": "preferences",
"scope": "memory:agent",
"sourceMemoryId": "12345678-1234-1234-1234-123456789abc",
"sourceCategory": "events",
"storedAt": "2026-03-16T02:20:00.000Z",
"canonicalKey": "user-reply-style"
}When a promotion would overwrite an existing durable memory with the same canonicalKey, RecallNest now creates an open conflict candidate instead of silently applying latest-wins.
The same slot-aware key inference also applies during promotion when category = "preferences" and the text resolves to a supported preference slot such as an atomic brand-item preference, a reply-style preference, or a tool-choice preference.
If the promotion resolves to the same preference slot as the existing durable owner, RecallNest now collapses it onto that owner instead of opening a conflict. This currently applies to slot-aware brand-item keys such as preferences:brand-item:麦当劳:麦辣鸡翅, reply-style keys such as preferences:reply-style:concise:direct, and tool-choice keys such as preferences:tool-choice:bun:over:node.
{
"id": "baddcafe-...",
"stored": false,
"disposition": "conflict",
"category": "preferences",
"scope": "memory:agent",
"sourceMemoryId": "12345678-1234-1234-1234-123456789abc",
"sourceCategory": "events",
"storedAt": "2026-03-16T02:20:00.000Z",
"canonicalKey": "user-reply-style",
"conflictId": "4f71a1f1-..."
}Notes:
disposition = "promoted"means a new durable memory was writtendisposition = "deduped"means the durable text already existed under the samecanonicalKeydisposition = "conflict"means RecallNest kept the existing durable memory and opened a review item
GET /v1/conflicts
GET /v1/conflicts?status=open&canonicalKey=user-reply-style&limit=10
GET /v1/conflicts?attention=stale&limit=10
GET /v1/conflicts?groupBy=cluster&attention=resolved&limit=10
GET /v1/conflicts?conflictId=4f71a1f1-...
List recent conflict candidates or fetch a single conflict record.
List response:
{
"groupBy": "record",
"conflicts": [
{
"conflictId": "4f71a1f1-...",
"status": "open",
"reason": "promotion_conflicts_with_existing_durable",
"canonicalKey": "user-reply-style",
"category": "preferences",
"reopenCount": 1,
"lastReopenedAt": "2026-03-16T05:20:00.000Z",
"lifecycle": {
"attention": "aging",
"openAgeDays": 1,
"reopenCount": 1,
"isOpen": true,
"needsAttention": false
},
"advice": {
"suggestedResolution": "keep_existing",
"confidence": "medium",
"similarity": 0.84,
"clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
"clusterLabel": "preferences / user-reply-style",
"reasons": [
"Existing durable text already looks like the tighter rewrite."
]
},
"existing": {
"memoryId": "baddcafe-...",
"text": "User prefers concise, direct replies."
},
"incoming": {
"sourceMemoryId": "12345678-1234-1234-1234-123456789abc",
"text": "User prefers colloquial writing that stays grounded and non-salesy."
}
}
],
"count": 1
}Cluster response:
{
"groupBy": "cluster",
"clusters": [
{
"clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
"clusterLabel": "preferences / user-reply-style",
"canonicalKey": "user-reply-style",
"category": "preferences",
"reason": "promotion_conflicts_with_existing_durable",
"totalCount": 3,
"openCount": 1,
"latestUpdatedAt": "2026-03-16T05:20:00.000Z",
"latestConflictId": "4f71a1f1-...",
"attentionCounts": {
"fresh": 0,
"aging": 1,
"stale": 0,
"escalated": 0,
"resolved": 2
},
"suggestedResolution": "keep_existing",
"confidence": "medium"
}
],
"count": 1
}Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Optional raw status filter: open, accepted-incoming, kept-existing |
attention |
string | Optional lifecycle filter: fresh, aging, stale, escalated, resolved |
groupBy |
string | Optional output mode: record (default) or cluster |
canonicalKey |
string | Optional canonical key filter |
limit |
number | Max results, default 20 |
conflictId |
string | Fetch a single conflict by full ID or unique prefix |
advice.mergeSuggestion is optional. It appears only when RecallNest can derive a conservative merged wording suggestion for manual_review conflicts.
Single conflict response:
{
"conflict": {
"conflictId": "4f71a1f1-...",
"status": "open",
"canonicalKey": "user-reply-style",
"category": "preferences",
"lifecycle": {
"attention": "aging",
"openAgeDays": 1,
"reopenCount": 1,
"isOpen": true,
"needsAttention": false
},
"advice": {
"suggestedResolution": "keep_existing",
"confidence": "medium",
"similarity": 0.84,
"clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
"clusterLabel": "preferences / user-reply-style",
"reasons": [
"Existing durable text already looks like the tighter rewrite."
]
}
}
}POST /v1/conflicts/resolve
Resolve an open conflict candidate by keeping the existing durable memory, accepting the incoming promoted text, or merging the two into a conservative durable rewrite.
Request:
{
"conflictId": "4f71a1f1-...",
"resolution": "accept_incoming",
"notes": "Incoming wording is cleaner."
}| Field | Type | Required | Description |
|---|---|---|---|
conflictId |
string | yes | Conflict candidate ID |
resolution |
string | yes | accept_incoming, keep_existing, or merge |
mergedText |
string | no | Optional merged durable wording when resolution=merge; otherwise RecallNest uses advice.mergeSuggestion when available |
notes |
string | no | Optional operator notes |
Response:
{
"conflictId": "4f71a1f1-...",
"status": "accepted-incoming",
"updatedAt": "2026-03-16T05:00:00.000Z",
"resolvedAt": "2026-03-16T05:00:00.000Z",
"updatedMemoryId": "baddcafe-..."
}If you keep the existing durable memory, updatedMemoryId is omitted and the conflict status becomes kept-existing.
If you resolve with merge, the conflict status becomes merged and updatedMemoryId points to the rewritten durable memory that kept the same canonical owner.
GET /v1/conflicts/audit
GET /v1/conflicts/audit?limit=100&top=5
GET /v1/conflicts/audit?canonicalKey=user-reply-style
Generate a terminal-friendly audit summary so stale or escalated clusters can be reviewed first.
Response:
{
"totalConflicts": 7,
"totalClusters": 3,
"openConflicts": 4,
"openClusters": 2,
"attentionCounts": {
"fresh": 1,
"aging": 1,
"stale": 1,
"escalated": 1,
"resolved": 3
},
"priorityClusters": [
{
"clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
"clusterLabel": "preferences / user-reply-style",
"canonicalKey": "user-reply-style",
"category": "preferences",
"reason": "promotion_conflicts_with_existing_durable",
"totalCount": 4,
"openCount": 2,
"latestUpdatedAt": "2026-03-16T05:20:00.000Z",
"latestConflictId": "4f71a1f1-...",
"attention": "escalated",
"suggestedResolution": "keep_existing",
"confidence": "medium"
}
],
"suggestedActions": [
"Resolve 1 escalated cluster(s) first."
]
}Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Optional raw status filter: open, accepted-incoming, kept-existing |
canonicalKey |
string | Optional canonical key filter |
limit |
number | Max records to scan, default 100 |
top |
number | Max priority clusters to return, default 5 |
POST /v1/conflicts/escalate
Preview or apply escalation metadata for stale / escalated open conflicts.
Request:
{
"attention": "stale",
"limit": 100,
"top": 10,
"apply": false,
"notes": "nightly escalation audit"
}| Field | Type | Required | Description |
|---|---|---|---|
attention |
string | no | stale or escalated, default stale |
canonicalKey |
string | no | Optional canonical key filter |
limit |
number | no | Max open conflicts to scan, default 100 |
top |
number | no | Max eligible conflicts to include, default 10 |
apply |
boolean | no | When false, preview only. When true, writes escalation metadata |
notes |
string | no | Optional operator note stored on escalated conflicts |
Response:
{
"apply": false,
"scanned": 12,
"eligible": 2,
"escalated": 0,
"skipped": 0,
"items": [
{
"conflictId": "4f71a1f1-...",
"canonicalKey": "user-reply-style",
"attention": "stale",
"openAgeDays": 4,
"reopenCount": 1,
"escalationCount": 0,
"suggestedResolution": "manual_review",
"confidence": "high",
"action": "pending",
"clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences"
}
]
}POST /v1/checkpoint
Store a session checkpoint outside the durable memory index.
保存当前工作状态:适合跨窗口延续任务,但不应该混入长期 durable memory。
Request:
{
"sessionId": "codex-2026-03-16-001",
"scope": "agent:codex",
"summary": "Implement session checkpoint storage",
"decisions": ["Keep checkpoints out of LanceDB"],
"openLoops": ["Need resume_context next"],
"nextActions": ["Add checkpoint MCP tool"],
"entities": ["RecallNest", "Codex"],
"files": ["src/session-store.ts"]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
sessionId |
string | yes | — | Current session identifier |
scope |
string | no | session:{sessionId} |
Optional shared scope |
summary |
string | yes | — | Compact summary of the current work state |
task |
string | no | — | Optional task label |
decisions |
string[] | no | [] |
Key decisions already made |
openLoops |
string[] | no | [] |
Unresolved questions or pending items |
nextActions |
string[] | no | [] |
Next actions to take |
entities |
string[] | no | [] |
Relevant projects, tools, or people |
files |
string[] | no | [] |
Relevant files or paths |
updatedAt |
string | no | now() |
Optional ISO timestamp override |
RecallNest sanitizes repo-state text such as git status, modified-file lists, and untracked-file notes out of saved checkpoint content. Verify volatile repo state locally in the next window instead of relying on checkpoint text.
Managed MCP / HTTP checkpoint calls now also append a dedicated workflow observation automatically: normal saves record success, while repo-state sanitization records corrected with signal repo-state-sanitized.
Response:
{
"sessionId": "codex-2026-03-16-001",
"scope": "agent:codex",
"summary": "Implement session checkpoint storage",
"decisions": ["Keep checkpoints out of LanceDB"],
"openLoops": ["Need resume_context next"],
"nextActions": ["Add checkpoint MCP tool"],
"entities": ["RecallNest", "Codex"],
"files": ["src/session-store.ts"],
"updatedAt": "2026-03-16T09:30:00.000Z"
}POST /v1/resume
Compose startup context for a fresh window by combining stable durable memory, relevant patterns and cases, plus the latest checkpoint for a session or scope.
为新窗口编排上下文:返回的是组合后的连续性上下文,不是原始检索结果堆积。
Managed MCP / HTTP resume calls now also append a dedicated resume_context workflow observation with source managed; this stays in the workflow observation store and does not enter durable recall.
Request:
{
"task": "Implement startup continuity for fresh windows",
"scope": "agent:codex",
"sessionId": "codex-2026-03-16-001",
"limitPerSection": 3,
"includeLatestCheckpoint": true,
"profile": "default"
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
task |
string | no | — | Optional current task or question to bias recall |
scope |
string | no | — | Optional shared scope for project or terminal continuity |
sessionId |
string | no | — | Optional session identifier used to recover the latest checkpoint |
limitPerSection |
number | no | 3 | Max items returned per section (1-6) |
includeLatestCheckpoint |
boolean | no | true |
Whether to include the latest checkpoint summary |
profile |
string | no | "default" |
Retrieval profile: default, writing, debug, fact-check |
Response:
{
"summary": "Loaded 3 stable context item(s), 2 pattern(s), and 1 case(s). Latest checkpoint from codex-2026-03-16-001 on 2026-03-16: Implement startup continuity for fresh windows.",
"resolvedScope": "agent:codex",
"stableContext": [
"Profile: User builds local-first memory systems.",
"Preference: User prefers concise technical replies.",
"Entity: RecallNest is shared across Claude Code, Codex, and Gemini CLI."
],
"relevantPatterns": [
"At task start, run search_memory before coding."
],
"recentCases": [
"Keep session state in a checkpoint store instead of the durable index."
],
"latestCheckpoint": {
"sessionId": "codex-2026-03-16-001",
"resolvedScope": "agent:codex",
"summary": "Implement startup continuity for fresh windows",
"updatedAt": "2026-03-16T05:00:00.000Z"
},
"generatedAt": "2026-03-16T05:10:00.000Z",
"profile": "default"
}Use resolvedScope as the default scope for follow-up search_memory, brief_memory, pin_memory, and similar recall calls when the client did not already provide a stricter shared scope.
GET /v1/checkpoint/latest
Fetch the latest checkpoint for a given sessionId or scope.
获取最新 checkpoint:适合调试当前工作状态是否已写入,也可以和
POST /v1/resume配合使用。
Query params:
| Param | Required | Description |
|---|---|---|
sessionId |
no | Filter by session ID |
scope |
no | Filter by shared scope |
Response:
{
"checkpoint": {
"sessionId": "codex-2026-03-16-001",
"summary": "Implement session checkpoint storage",
"updatedAt": "2026-03-16T03:20:00.000Z",
"checkpointId": "b1c2d3e4-...",
"resolvedScope": "agent:codex"
}
}If nothing matches:
{
"checkpoint": null
}POST /v1/workflow-observe
Store one append-only workflow observation outside durable memory.
记录 workflow observation:适合追踪
resume_context、checkpoint_session等 primitive 是成功、失败、被纠正,还是被漏掉。
Request:
{
"workflowId": "resume_context",
"outcome": "missed",
"summary": "Fresh window skipped continuity recovery before repo exploration.",
"scope": "project:recallnest",
"source": "smoke",
"signal": "missed-startup-trigger",
"task": "headless continuity smoke",
"tags": ["continuity"],
"tools": ["resume_context"]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
workflowId |
string | yes | — | Workflow primitive id such as resume_context |
outcome |
string | no | "success" |
One of: success, failure, corrected, missed |
summary |
string | yes | — | Short description of what happened |
scope |
string | no | "global" |
Optional scope such as project:recallnest |
source |
string | no | "manual" |
Source label such as agent, managed, smoke, eval, manual |
signal |
string | no | — | Optional failure/correction signal tag |
task |
string | no | — | Optional related task |
tags |
string[] | no | [] |
Optional tags |
tools |
string[] | no | [] |
Optional tools involved |
recordedAt |
string | no | now() |
Optional ISO timestamp override |
Response:
{
"observationId": "resume_context-missed-2026-03-17T03-00-00-000Z",
"workflowId": "resume_context",
"outcome": "missed",
"summary": "Fresh window skipped continuity recovery before repo exploration.",
"scope": "project:recallnest",
"resolvedScope": "project:recallnest",
"source": "smoke",
"signal": "missed-startup-trigger",
"task": "headless continuity smoke",
"tags": ["continuity"],
"tools": ["resume_context"],
"recordedAt": "2026-03-17T03:00:00.000Z"
}GET /v1/workflow-health
GET /v1/workflow-health?workflowId=resume_context&scope=project:recallnest
Inspect one workflow primitive or return a dashboard of degraded workflows.
查看 workflow 健康度:支持单个 workflow 的 7 天 / 30 天汇总,也支持全局 dashboard。
Query params:
| Param | Required | Description |
|---|---|---|
workflowId |
no | Optional workflow primitive id |
scope |
no | Optional scope filter |
limit |
no | Dashboard max rows, default 10 |
Workflow response:
{
"workflowId": "resume_context",
"scope": "project:recallnest",
"status": "watch",
"summary": "3 observations in the last 30d, success rate 33.3%, 2 issue observations.",
"latestObservationAt": "2026-03-17T03:00:00.000Z",
"windows": [
{
"days": 7,
"total": 2,
"successes": 1,
"failures": 0,
"corrected": 1,
"missed": 0,
"issueCount": 1,
"successRate": 0.5,
"issueRate": 0.5,
"latestAt": "2026-03-17T03:00:00.000Z",
"topSignals": [
{ "signal": "user-correction", "count": 1 }
]
}
]
}Dashboard response:
{
"dashboard": [
{
"workflowId": "checkpoint_session",
"scope": "project:recallnest",
"status": "critical",
"total": 1,
"issueCount": 1,
"successRate": 0,
"latestObservationAt": "2026-03-17T04:00:00.000Z",
"summary": "1 observations in the last 30d, success rate 0.0%, 1 issue observations."
}
]
}GET /v1/workflow-evidence?workflowId=checkpoint_session&scope=project:recallnest&limit=5
Build an evidence pack for one workflow primitive from recent issue observations.
生成 workflow evidence pack:把最近问题 observation、top signals 和修复建议打包出来,方便做规则、prompt、测试收口。
Query params:
| Param | Required | Description |
|---|---|---|
workflowId |
yes | Workflow primitive id |
scope |
no | Optional scope filter |
limit |
no | Max recent issue observations, default 5 |
Response:
{
"workflowId": "checkpoint_session",
"scope": "project:recallnest",
"generatedAt": "2026-03-17T10:10:00.000Z",
"summary": "1 issue observations in the last 30d for checkpoint_session.",
"topSignals": [
{ "signal": "repo-state-contamination", "count": 1 }
],
"recentIssues": [
{
"observationId": "checkpoint_session-failure-2026-03-17T04-00-00-000Z",
"outcome": "failure",
"summary": "Checkpoint still carried repo-state text before the product-side guard landed.",
"signal": "repo-state-contamination",
"recordedAt": "2026-03-17T04:00:00.000Z",
"task": "headless continuity smoke"
}
],
"suggestions": [
"Keep volatile repo-state text out of saved checkpoints and handoff summaries unless this window verified it."
]
}POST /v1/search
Advanced search with full metadata, retrieval path details, and scope filtering.
高级搜索:返回完整元数据、检索路径、重要度等详情。
Request:
{
"query": "API authentication patterns",
"limit": 5,
"category": "patterns",
"profile": "fact-check"
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | yes | — | Search query |
limit |
number | no | 5 | Max results (1-20) |
category |
string | no | — | Filter: profile, preferences, entities, events, cases, patterns |
profile |
string | no | "default" |
Retrieval profile: default, writing, debug, fact-check |
scope |
string | no | — | Filter by source scope (e.g. cc, codex, api:my-agent) |
minScore |
number | no | 0 | Minimum relevance score (0-1) |
Response:
{
"results": [
{
"id": "a1b2c3d4-...",
"text": "Authentication pattern: use JWT with...",
"category": "patterns",
"scope": "cc:abc12345",
"score": 0.82,
"importance": 0.8,
"timestamp": 1741219200000,
"date": "2026-03-06",
"metadata": { "source": "cc", "tier": "working", "file": "..." },
"boundary": {
"layer": "durable",
"authority": "structured-memory",
"conflictPolicy": "latest-wins",
"originalCategory": "patterns"
},
"canonicalKey": "patterns:cross-window-continuity-handoff",
"promotedFrom": null,
"sources": { "vector": { "score": 0.85, "rank": 1 }, "bm25": { "score": 0.7, "rank": 3 } }
}
],
"query": "API authentication patterns",
"profile": "fact-check",
"count": 1
}Derived provenance fields:
| Field | Type | Description |
|---|---|---|
boundary |
object | null | Parsed boundary metadata: layer, authority, conflictPolicy, and optional originalCategory / downgradedFrom |
canonicalKey |
string | null | Stable dedupe/update key if the memory has one |
promotedFrom |
object | null | Present when a durable memory was explicitly promoted from evidence; includes source memoryId, scope, category, source, and source boundary |
provenanceHistory |
array | Observed evidence trail for the durable memory. Falls back to [promotedFrom] when no explicit history has been materialized yet |
provenanceHistoryCount |
number | Total provenance-history observations tracked for the durable memory |
GET /v1/stats
Memory index statistics.
Response:
{
"totalMemories": 35176,
"byScope": {
"cc:abc12345": 773,
"memory": 974,
"codex:019ccbe4": 277
},
"byCategory": {
"fact": 31582,
"events": 1546,
"cases": 1337,
"entities": 455,
"patterns": 156,
"preferences": 65,
"profile": 26
}
}Note:
byScopeshows raw scope keys. UsebyCategoryfor the 6-category distribution.
POST /v1/consolidate
This endpoint is planned for Phase 3 (self-evolution). See docs/self-evolution.md for the design.
GET /v1/gaps
This endpoint is planned for Phase 3 (self-evolution). See docs/self-evolution.md for the design.
All endpoints return errors in this format:
{
"error": "Description of what went wrong"
}| HTTP Status | Meaning |
|---|---|
| 400 | Bad request (missing required fields, invalid values) |
| 404 | Endpoint not found |
| 500 | Internal server error |
| 503 | Service unavailable (health check failed) |
# Health check
curl http://localhost:4318/v1/health
# Recall
curl -X POST http://localhost:4318/v1/recall \
-H "Content-Type: application/json" \
-d '{"query": "Docker debugging", "limit": 3}'
# Store
curl -X POST http://localhost:4318/v1/store \
-H "Content-Type: application/json" \
-d '{"text": "Test memory entry", "category": "events"}'
# Advanced search with category filter
curl -X POST http://localhost:4318/v1/search \
-H "Content-Type: application/json" \
-d '{"query": "debugging", "category": "cases", "profile": "debug"}'
# Stats
curl http://localhost:4318/v1/stats