REST API Reference
The MemoryLayer server exposes a RESTful API at http://localhost:61001 by default. All endpoints accept and return JSON.
Authentication
For local development, no authentication is required. For production deployments, include an API key in the Authorization header:
Authorization: Bearer your-api-keyMany endpoints also accept an X-Session-ID header to provide session context for workspace resolution.
Memory Operations
POST /v1/memories
Store a new memory with automatic embedding and classification.
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
content | string | yes | — | Memory content to store |
workspace_id | string | no | from session or _default | Workspace override |
type | string | no | auto-classified | Cognitive type: episodic, semantic, procedural, working |
subtype | string | no | null | Domain-specific classification |
importance | float | no | 0.5 | Memory importance (0.0-1.0) |
tags | string[] | no | [] | Tags for categorization |
metadata | object | no | {} | Arbitrary metadata |
associations | string[] | no | [] | Memory IDs to associate with |
context_id | string | no | from session | Target memory context |
observer_id | string | no | null | Entity doing the observing (agent ID, user ID) |
subject_id | string | no | null | Entity this memory is about |
user_id | string | no | from auth | User scope for this memory |
Response: 201 Created
{ "memory": { "id": "mem_abc123", "content": "User prefers Python for backend development", "type": "semantic", "subtype": "preference", "importance": 0.8, "tags": ["preferences", "programming"], "created_at": "2026-01-15T10:30:00Z" }}curl example:
curl -X POST http://localhost:61001/v1/memories \ -H "Content-Type: application/json" \ -d '{ "content": "User prefers Python for backend development", "type": "semantic", "importance": 0.8, "tags": ["preferences", "programming"] }'GET /v1/memories/{memory_id}
Retrieve a single memory by ID.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Memory identifier |
Response: 200 OK
{ "memory": { "id": "mem_abc123", "content": "User prefers Python for backend development", "type": "semantic", "importance": 0.8, "tags": ["preferences", "programming"], "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" }}curl example:
curl http://localhost:61001/v1/memories/mem_abc123PUT /v1/memories/{memory_id}
Update an existing memory. Only provided fields are updated.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Memory identifier |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
content | string | no | Updated content |
type | string | no | Updated cognitive type |
subtype | string | no | Updated domain classification |
importance | float | no | Updated importance (0.0-1.0) |
tags | string[] | no | Updated tags |
metadata | object | no | Updated metadata |
pinned | boolean | no | Pin/unpin memory (pinned memories are exempt from decay) |
Response: 200 OK
{ "memory": { "id": "mem_abc123", "content": "User strongly prefers Python for backend development", "importance": 0.9, "pinned": true }}curl example:
curl -X PUT http://localhost:61001/v1/memories/mem_abc123 \ -H "Content-Type: application/json" \ -d '{ "importance": 0.9, "pinned": true }'DELETE /v1/memories/{memory_id}
Delete a memory (soft delete by default).
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Memory identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
hard | boolean | false | Permanently delete instead of archiving |
Response: 204 No Content
curl example:
# Soft delete (archive)curl -X DELETE http://localhost:61001/v1/memories/mem_abc123
# Hard delete (permanent)curl -X DELETE "http://localhost:61001/v1/memories/mem_abc123?hard=true"POST /v1/memories/recall
Search memories by semantic query. Supports multiple retrieval modes.
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | yes | — | Natural language query |
workspace_id | string | no | from session | Workspace override |
types | string[] | no | [] | Filter by cognitive types |
subtypes | string[] | no | [] | Filter by domain subtypes |
tags | string[] | no | [] | Filter by tags (AND logic) |
context_id | string | no | from session | Filter by memory context |
observer_id | string | no | null | Filter by observer entity |
subject_id | string | no | null | Filter by subject entity |
user_id | string | no | from auth | Filter by user |
mode | string | no | rag | Retrieval strategy. rag is the active mode; llm and hybrid are deprecated (use the Context Environment + RLM for LLM-driven analysis). |
tolerance | string | no | server default | Search precision |
limit | integer | no | 10 | Maximum memories to return (1-100) |
min_relevance | float | no | server default | Minimum relevance score (0.0-1.0) |
recency_weight | float | no | server default | Weight for recency boosting (0.0-1.0) |
include_associations | boolean | no | server default | Include linked memories |
traverse_depth | integer | no | server default | Multi-hop graph traversal depth (0-5) |
max_expansion | integer | no | server default | Max memories via graph expansion (1-500) |
created_after | datetime | no | null | Filter memories created after this time |
created_before | datetime | no | null | Filter memories created before this time |
context | object[] | no | [] | Recent conversation context |
rag_threshold | float | no | 0.8 | Use LLM if RAG confidence < threshold |
detail_level | string | no | server default | abstract, overview, or full |
include_archived | boolean | no | false | Include archived memories |
exclude_ids | string[] | no | [] | Memory IDs to exclude from results |
Retrieval Modes:
| Mode | Description | Status |
|---|---|---|
rag | Vector similarity search + graph traversal | Active |
llm | Query rewriting + enhanced search | Deprecated |
hybrid | RAG first, LLM if insufficient | Deprecated |
The
llmandhybridmodes are being phased out. Useragfor recall and the Context Environment with RLM when you need LLM-driven analysis over memories.
Response: 200 OK
{ "memories": [ { "id": "mem_abc123", "content": "User prefers Python for backend development", "type": "semantic", "importance": 0.8, "relevance": 0.92, "tags": ["preferences", "programming"] } ], "total_count": 1, "mode_used": "rag", "search_latency_ms": 42.5}curl example:
curl -X POST http://localhost:61001/v1/memories/recall \ -H "Content-Type: application/json" \ -H "X-Session-ID: sess_abc123" \ -d '{ "query": "What programming languages does the user prefer?", "limit": 10, "mode": "hybrid", "types": ["semantic"], "tags": ["preferences"] }'POST /v1/memories/reflect
Synthesize insights across memories using LLM reflection.
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | yes | — | What to reflect on |
workspace_id | string | no | from session | Workspace override |
detail_level | string | no | server default | Level of detail: abstract, overview, full |
include_sources | boolean | no | true | Include source memory references |
depth | integer | no | 2 | Association traversal depth (1-5) |
types | string[] | no | [] | Filter by types |
subtypes | string[] | no | [] | Filter by subtypes |
tags | string[] | no | [] | Filter by tags |
context_id | string | no | from session | Filter by memory context |
observer_id | string | no | null | Filter by observer entity |
subject_id | string | no | null | Filter by subject entity |
Response: 200 OK
{ "reflection": "Based on stored memories, the user prefers...", "source_memories": ["mem_abc123", "mem_def456"], "confidence": 0.85}curl example:
curl -X POST http://localhost:61001/v1/memories/reflect \ -H "Content-Type: application/json" \ -d '{ "query": "Summarize user technology preferences", "detail_level": "overview", "include_sources": true, "depth": 2 }'POST /v1/memories/{memory_id}/decay
Apply decay to reduce a memory’s importance over time. Pinned memories are exempt from decay.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Memory identifier |
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
decay_rate | float | no | 0.1 | Decay rate to apply (0.0-1.0) |
Response: 200 OK — returns the updated memory with decayed importance.
curl example:
curl -X POST http://localhost:61001/v1/memories/mem_abc123/decay \ -H "Content-Type: application/json" \ -d '{"decay_rate": 0.1}'POST /v1/memories/batch
Perform multiple memory operations in a single request. Supports create, update, and delete operations.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
operations | object[] | yes | List of typed batch operations |
Each operation must include an op field set to "create", "update", or "delete".
Create operation fields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
op | string | yes | — | Must be "create" |
content | string | yes | — | Memory content |
type | string | no | auto-classified | Cognitive type |
subtype | string | no | null | Domain classification |
importance | float | no | 0.5 | Importance (0.0-1.0) |
tags | string[] | no | [] | Tags |
metadata | object | no | {} | Metadata |
observer_id | string | no | null | Observer entity |
subject_id | string | no | null | Subject entity |
Update operation fields:
| Field | Type | Required | Description |
|---|---|---|---|
op | string | yes | Must be "update" |
memory_id | string | yes | Memory ID to update |
content | string | no | Updated content |
type | string | no | Updated type |
subtype | string | no | Updated subtype |
importance | float | no | Updated importance |
tags | string[] | no | Updated tags |
metadata | object | no | Updated metadata |
pinned | boolean | no | Pin/unpin memory |
Delete operation fields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
op | string | yes | — | Must be "delete" |
memory_id | string | yes | — | Memory ID to delete |
hard | boolean | no | false | Hard delete (permanent) |
Response: 200 OK
{ "total_operations": 3, "successful": 2, "failed": 1, "results": [ {"index": 0, "type": "create", "status": "success", "memory_id": "mem_new1"}, {"index": 1, "type": "create", "status": "success", "memory_id": "mem_new2"}, {"index": 2, "type": "delete", "status": "error", "error": "Memory not found: mem_old"} ]}curl example:
curl -X POST http://localhost:61001/v1/memories/batch \ -H "Content-Type: application/json" \ -d '{ "operations": [ {"op": "create", "content": "Memory 1", "importance": 0.7}, {"op": "create", "content": "Memory 2", "importance": 0.8}, {"op": "delete", "memory_id": "mem_old", "hard": false} ] }'Associations
POST /v1/memories/{memory_id}/associate
Create a typed relationship between two memories.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Source memory ID |
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
target_id | string | yes | — | Target memory ID |
relationship | string | yes | — | Relationship type (e.g., SIMILAR_TO, CAUSES, SOLVES) |
strength | float | no | 0.5 | Relationship strength (0.0-1.0) |
metadata | object | no | {} | Arbitrary metadata |
workspace_id | string | no | from session | Workspace override |
Response: 201 Created
{ "association": { "id": "assoc_xyz789", "source_id": "mem_problem_123", "target_id": "mem_solution_456", "relationship": "SOLVES", "strength": 0.9, "created_at": "2026-01-15T10:30:00Z" }}curl example:
curl -X POST http://localhost:61001/v1/memories/mem_problem_123/associate \ -H "Content-Type: application/json" \ -d '{ "target_id": "mem_solution_456", "relationship": "SOLVES", "strength": 0.9 }'GET /v1/memories/{memory_id}/associations
Get all associations for a memory.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Memory identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
relationships | string | null | Comma-separated relationship types to filter by |
direction | string | both | outgoing, incoming, or both |
Response: 200 OK
{ "associations": [ { "id": "assoc_xyz789", "source_id": "mem_problem_123", "target_id": "mem_solution_456", "relationship": "SOLVES", "strength": 0.9 } ], "total_count": 1}curl example:
# All associationscurl http://localhost:61001/v1/memories/mem_abc123/associations
# Filter by relationship type and directioncurl "http://localhost:61001/v1/memories/mem_abc123/associations?relationships=CAUSES,SOLVES&direction=outgoing"POST /v1/memories/{memory_id}/traverse
Multi-hop graph traversal starting from a specific memory.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
memory_id | string | Starting memory for traversal |
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
workspace_id | string | no | from session | Workspace override |
max_depth | integer | no | 2 | Maximum traversal depth (1-5) |
relationship_types | string[] | no | [] | Filter by relationship types (empty = all) |
direction | string | no | both | outgoing, incoming, or both |
min_strength | float | no | 0.0 | Minimum edge strength (0.0-1.0) |
Response: 200 OK
{ "paths": [ { "nodes": ["mem_a", "mem_b", "mem_c"], "edges": [ {"source": "mem_a", "target": "mem_b", "relationship": "CAUSES"}, {"source": "mem_b", "target": "mem_c", "relationship": "LEADS_TO"} ] } ], "unique_nodes": ["mem_a", "mem_b", "mem_c"], "total_paths": 1}curl example:
curl -X POST http://localhost:61001/v1/memories/mem_abc123/traverse \ -H "Content-Type: application/json" \ -d '{ "relationship_types": ["CAUSES", "LEADS_TO"], "max_depth": 3, "direction": "both", "min_strength": 0.5 }'Sessions
POST /v1/sessions
Create a new working memory session. Workspaces and contexts are auto-created if they do not exist.
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
session_id | string | no | auto-generated | Client-provided session ID |
workspace_id | string | no | _default | Workspace ID (auto-created if absent) |
ttl_seconds | integer | no | 3600 | Session TTL in seconds (60-86400) |
metadata | object | no | {} | Session metadata |
context_id | string | no | _default | Context to bind session to |
working_memory | object | no | null | Initial working memory key-value pairs |
briefing | boolean | no | false | Include briefing with relevant memories |
briefing_options | object | no | null | Briefing options: lookback_hours, detail_level, limit |
Response: 201 Created
{ "session": { "id": "sess_abc123", "workspace_id": "my-workspace", "context_id": "_default", "expires_at": "2026-01-15T11:30:00Z", "metadata": {"task": "debugging"} }, "briefing": null}curl example:
curl -X POST http://localhost:61001/v1/sessions \ -H "Content-Type: application/json" \ -d '{ "workspace_id": "my-workspace", "ttl_seconds": 3600, "metadata": {"task": "debugging"}, "briefing": true }'GET /v1/sessions
List sessions in a workspace.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace to list sessions for |
context_id | string | null | Filter by context |
include_expired | boolean | false | Include expired sessions |
Response: 200 OK
{ "sessions": [ { "id": "sess_abc123", "workspace_id": "my-workspace", "expires_at": "2026-01-15T11:30:00Z" } ], "total_count": 1}curl example:
curl "http://localhost:61001/v1/sessions?workspace_id=my-workspace&include_expired=false"GET /v1/sessions/briefing
Get a briefing of recent workspace activity and context. Includes workspace summary, recent sessions, open threads, and detected contradictions.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace to get briefing for |
lookback_minutes | integer | 60 | How far back to look for activity |
detail_level | string | abstract | Detail level for memory content |
limit | integer | 10 | Maximum items to include |
include_memories | boolean | true | Include recent memories |
include_contradictions | boolean | true | Include detected contradictions |
Response: 200 OK
{ "briefing": { "workspace_id": "my-workspace", "summary": "Workspace has 142 memories. 3 sessions active.", "recent_memories": [], "contradictions": [] }}curl example:
curl "http://localhost:61001/v1/sessions/briefing?workspace_id=my-workspace&lookback_minutes=120"GET /v1/sessions/{session_id}
Retrieve a session by ID.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
session_id | string | Session identifier |
Response: 200 OK
{ "session": { "id": "sess_abc123", "workspace_id": "my-workspace", "expires_at": "2026-01-15T11:30:00Z", "metadata": {"task": "debugging"} }}curl example:
curl http://localhost:61001/v1/sessions/sess_abc123DELETE /v1/sessions/{session_id}
Delete a session and all its context data.
Response: 204 No Content
curl example:
curl -X DELETE http://localhost:61001/v1/sessions/sess_abc123POST /v1/sessions/{session_id}/memory
Store a key-value pair in session working memory.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
session_id | string | Session identifier |
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
key | string | yes | — | Working memory key |
value | any | yes | — | Working memory value (JSON-serializable) |
ttl_seconds | integer | no | null | Optional TTL override for this entry |
Response: 201 Created
{ "key": "current_task", "value": {"description": "Debugging auth", "file": "auth.py"}, "ttl_seconds": null, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z"}curl example:
curl -X POST http://localhost:61001/v1/sessions/sess_abc123/memory \ -H "Content-Type: application/json" \ -d '{ "key": "current_task", "value": {"description": "Debugging auth", "file": "auth.py"} }'GET /v1/sessions/{session_id}/memory
Retrieve working memory from a session. Returns a single entry if key is specified, or all entries otherwise.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
session_id | string | Session identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
key | string | null | Specific key to retrieve (returns all if omitted) |
Response: 200 OK
{ "current_task": {"description": "Debugging auth", "file": "auth.py"}, "findings": ["Issue in token validation"]}curl example:
# Get all working memorycurl http://localhost:61001/v1/sessions/sess_abc123/memory
# Get specific keycurl "http://localhost:61001/v1/sessions/sess_abc123/memory?key=current_task"POST /v1/sessions/{session_id}/commit
Commit session working memory to long-term storage. Working memories are persisted via write-behind as they are written during the session, so this operation is lightweight.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
session_id | string | Session identifier |
Request Body (optional):
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
min_importance | float | no | 0.5 | Minimum importance threshold (0.0-1.0) |
deduplicate | boolean | no | true | Enable deduplication of extracted memories |
categories | string[] | no | null | Category names to commit (null for all) |
max_memories | integer | no | 50 | Maximum memories to extract (1-500) |
Response: 200 OK
{ "session_id": "sess_abc123", "memories_extracted": 5, "memories_deduplicated": 1, "memories_created": 4, "breakdown": {"task": 2, "findings": 2}, "extraction_time_ms": 150}curl example:
curl -X POST http://localhost:61001/v1/sessions/sess_abc123/commit \ -H "Content-Type: application/json" \ -d '{ "min_importance": 0.5, "deduplicate": true, "max_memories": 50 }'POST /v1/sessions/{session_id}/touch
Extend session TTL using sliding window. Resets the session’s expires_at to now + TTL.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
session_id | string | Session identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
extend_seconds | integer | server default | Seconds to extend TTL (60-86400) |
Response: 200 OK
{ "expires_at": "2026-01-15T12:30:00Z"}curl example:
# Extend with default TTLcurl -X POST http://localhost:61001/v1/sessions/sess_abc123/touch
# Extend by 2 hourscurl -X POST "http://localhost:61001/v1/sessions/sess_abc123/touch?extend_seconds=7200"Workspaces
POST /v1/workspaces
Create a new workspace. Workspaces provide memory isolation.
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | — | Workspace name |
settings | object | no | {} | Workspace-level settings |
Response: 201 Created
{ "workspace": { "id": "ws_a1b2c3d4e5f6g7h8", "name": "My Project", "settings": {}, "created_at": "2026-01-15T10:30:00Z" }}curl example:
curl -X POST http://localhost:61001/v1/workspaces \ -H "Content-Type: application/json" \ -d '{"name": "My Project", "settings": {}}'GET /v1/workspaces
List all workspaces.
Response: 200 OK
{ "workspaces": [ {"id": "ws_abc123", "name": "Project Alpha"}, {"id": "_default", "name": "Default"} ]}curl example:
curl http://localhost:61001/v1/workspacesGET /v1/workspaces/{workspace_id}
Get workspace details.
Response: 200 OK
{ "workspace": { "id": "ws_abc123", "name": "Project Alpha", "settings": {}, "created_at": "2026-01-15T10:30:00Z" }}curl example:
curl http://localhost:61001/v1/workspaces/ws_abc123PUT /v1/workspaces/{workspace_id}
Update workspace name or settings.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | Updated workspace name |
settings | object | no | Updated settings |
Response: 200 OK — returns the updated workspace.
curl example:
curl -X PUT http://localhost:61001/v1/workspaces/ws_abc123 \ -H "Content-Type: application/json" \ -d '{"name": "Project Alpha v2"}'DELETE /v1/workspaces/{workspace_id}
Delete a workspace and all associated data.
Response: 204 No Content
curl example:
curl -X DELETE http://localhost:61001/v1/workspaces/ws_abc123GET /v1/workspaces/{workspace_id}/schema
Get workspace schema including available relationship types and memory subtypes.
Response: 200 OK
{ "relationship_types": ["SIMILAR_TO", "CAUSES", "SOLVES", "LEADS_TO", "PART_OF"], "memory_subtypes": ["preference", "fact", "opinion", "goal", "plan"], "can_customize": false}curl example:
curl http://localhost:61001/v1/workspaces/ws_abc123/schemaGET /v1/workspaces/{workspace_id}/export
Export workspace memories and associations as streaming NDJSON.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
offset | integer | 0 | Skip first N memories |
limit | integer | 0 | Max memories to export (0 = unlimited) |
include_associations | boolean | true | Include memory associations |
Response: 200 OK with Content-Type: application/x-ndjson
The stream contains lines of JSON objects with these types:
| Line type | Description |
|---|---|
header | Export metadata (version, workspace, counts) |
memory | Individual memory with index |
association | Individual association |
footer | Summary counts |
curl example:
# Export all memories to filecurl http://localhost:61001/v1/workspaces/ws_abc123/export -o export.ndjson
# Export first 100 memories without associationscurl "http://localhost:61001/v1/workspaces/ws_abc123/export?limit=100&include_associations=false"POST /v1/workspaces/{workspace_id}/import
Import memories and associations from JSON or NDJSON export. Supports both application/json and application/x-ndjson content types. Duplicate memories (by content hash) are automatically skipped.
Request Body (JSON format):
{ "data": { "version": "1.0", "workspace_id": "source-workspace", "exported_at": "2026-01-15T10:30:00Z", "memories": [ {"id": "mem_1", "content": "...", "content_hash": "...", "type": "semantic"} ], "associations": [ {"source_id": "mem_1", "target_id": "mem_2", "relationship_type": "SIMILAR_TO", "strength": 0.8} ] }}Response: 200 OK
{ "imported": 10, "skipped_duplicates": 2, "errors": 0, "details": ["Imported 5 associations"]}curl example:
# Import from NDJSON filecurl -X POST http://localhost:61001/v1/workspaces/ws_abc123/import \ -H "Content-Type: application/x-ndjson" \ --data-binary @export.ndjson
# Import from JSONcurl -X POST http://localhost:61001/v1/workspaces/ws_abc123/import \ -H "Content-Type: application/json" \ -d @import.jsonContradictions
GET /v1/workspaces/{workspace_id}/contradictions
List unresolved contradictions in a workspace.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
workspace_id | string | Workspace identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 10 | Maximum contradictions to return |
Response: 200 OK
{ "contradictions": [ { "id": "ctr_abc123", "workspace_id": "my-workspace", "memory_a_id": "mem_1", "memory_b_id": "mem_2", "contradiction_type": "value_conflict", "confidence": 0.85, "detection_method": "semantic", "detected_at": "2026-01-15T10:30:00Z", "resolved_at": null, "resolution": null } ], "count": 1}curl example:
curl "http://localhost:61001/v1/workspaces/my-workspace/contradictions?limit=20"POST /v1/contradictions/{contradiction_id}/resolve
Resolve a contradiction with a chosen strategy.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
contradiction_id | string | Contradiction identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace override |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
resolution | string | yes | Strategy: keep_a, keep_b, keep_both, or merge |
merged_content | string | when merge | Merged content (required when resolution is merge) |
Response: 200 OK — returns the resolved contradiction.
curl example:
# Keep one memorycurl -X POST http://localhost:61001/v1/contradictions/ctr_abc123/resolve \ -H "Content-Type: application/json" \ -d '{"resolution": "keep_a"}'
# Merge conflicting memoriescurl -X POST http://localhost:61001/v1/contradictions/ctr_abc123/resolve \ -H "Content-Type: application/json" \ -d '{"resolution": "merge", "merged_content": "User prefers Python 3.11+ for backend work"}'POST /v1/workspaces/{workspace_id}/contradictions/scan
Trigger a workspace-wide scan for contradictions among stored memories.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
workspace_id | string | Workspace identifier |
Request Body (optional):
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
batch_size | integer | no | server default | Memories to process per batch (1-500) |
Response: 200 OK
{ "workspace_id": "my-workspace", "contradictions_found": 2, "contradictions": [ { "id": "ctr_new1", "memory_a_id": "mem_1", "memory_b_id": "mem_5", "contradiction_type": "negation", "confidence": 0.92 } ]}curl example:
curl -X POST http://localhost:61001/v1/workspaces/my-workspace/contradictions/scan \ -H "Content-Type: application/json" \ -d '{"batch_size": 100}'Entities
POST /v1/entities/{entity_id}/derive
Trigger inference derivation for an entity. Analyzes all memories about the entity and derives higher-order insights (patterns, preferences, tendencies) stored as INFERENCE-subtype memories.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_id | string | Entity identifier (agent ID, user ID, etc.) |
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
workspace_id | string | no | from session | Workspace override |
observer_id | string | no | null | Optional observer perspective filter |
force | boolean | no | false | Force re-derivation even if recent insights exist |
Response: 200 OK
{ "subject_id": "user_123", "workspace_id": "my-workspace", "insights_created": 3, "insights_updated": 1, "source_memory_count": 25, "insights": []}curl example:
curl -X POST http://localhost:61001/v1/entities/user_123/derive \ -H "Content-Type: application/json" \ -d '{"force": true}'GET /v1/entities/{entity_id}/card
Get a cached entity profile card — a synthesized view combining reflection and derived insights. Results are cached and lazily recalculated.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_id | string | Entity identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace override |
force_refresh | boolean | false | Trigger immediate recalculation |
Response: 200 OK
{ "entity_id": "user_123", "workspace_id": "my-workspace", "reflection": "This user is a senior Python developer who...", "insights": [], "source_memories": ["mem_1", "mem_2", "mem_3"], "confidence": 0.85, "cached": true, "generated_at": "2026-01-15T10:30:00Z"}curl example:
# Get cached cardcurl "http://localhost:61001/v1/entities/user_123/card?workspace_id=my-workspace"
# Force refreshcurl "http://localhost:61001/v1/entities/user_123/card?force_refresh=true"GET /v1/entities/{entity_id}/insights
Get derived insights for an entity. Returns existing INFERENCE-subtype memories without triggering new derivation.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_id | string | Entity identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace override |
observer_id | string | null | Filter by observer perspective |
limit | integer | 20 | Maximum insights to return |
Response: 200 OK
{ "entity_id": "user_123", "workspace_id": "my-workspace", "insights": [], "total_count": 0}curl example:
curl "http://localhost:61001/v1/entities/user_123/insights?workspace_id=my-workspace&limit=10"Chat Threads
POST /v1/threads
Create a new chat thread for conversation history storage.
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
thread_id | string | no | auto-generated | Client-provided thread ID |
workspace_id | string | no | from session | Workspace override |
user_id | string | no | null | User scope for this thread |
context_id | string | no | _default | Context within workspace |
observer_id | string | no | null | Observer entity ID (typically the AI agent) |
subject_id | string | no | null | Subject entity ID (typically the human user) |
title | string | no | null | Optional display title |
metadata | object | no | {} | Arbitrary metadata |
expires_at | datetime | no | null | Optional expiration (null = permanent) |
Response: 201 Created
{ "thread": { "thread_id": "thread_abc123", "workspace_id": "my-workspace", "title": "Debugging session", "message_count": 0, "created_at": "2026-01-15T10:30:00Z" }}curl example:
curl -X POST http://localhost:61001/v1/threads \ -H "Content-Type: application/json" \ -d '{ "workspace_id": "my-workspace", "title": "Debugging session", "observer_id": "agent_1", "subject_id": "user_123" }'GET /v1/threads
List chat threads, optionally filtered by workspace and user.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
user_id | string | null | User filter |
limit | integer | 50 | Max threads to return (1-200) |
offset | integer | 0 | Pagination offset |
Response: 200 OK
{ "threads": [ { "thread_id": "thread_abc123", "title": "Debugging session", "message_count": 12 } ], "total_count": 1}curl example:
curl "http://localhost:61001/v1/threads?workspace_id=my-workspace&limit=20"GET /v1/threads/{thread_id}
Get thread metadata by ID.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
Response: 200 OK — returns the thread object.
curl example:
curl "http://localhost:61001/v1/threads/thread_abc123?workspace_id=my-workspace"PUT /v1/threads/{thread_id}
Update a thread (e.g., rename).
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | no | Updated display title |
metadata | object | no | Updated metadata |
Response: 200 OK — returns the updated thread.
curl example:
curl -X PUT "http://localhost:61001/v1/threads/thread_abc123?workspace_id=my-workspace" \ -H "Content-Type: application/json" \ -d '{"title": "Auth debugging session"}'GET /v1/threads/{thread_id}/full
Get thread with all messages inlined (paginated).
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
limit | integer | 100 | Max messages to return (1-1000) |
offset | integer | 0 | Message pagination offset |
order | string | asc | Message order: asc or desc |
Response: 200 OK
{ "thread": { "thread_id": "thread_abc123", "title": "Debugging session" }, "messages": [ { "message_id": "msg_1", "role": "user", "content": "Help me debug this auth issue", "index": 0 } ], "total_messages": 12}curl example:
curl "http://localhost:61001/v1/threads/thread_abc123/full?limit=50&order=asc"DELETE /v1/threads/{thread_id}
Delete a thread and all its messages.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
Response: 204 No Content
curl example:
curl -X DELETE "http://localhost:61001/v1/threads/thread_abc123?workspace_id=my-workspace"POST /v1/threads/{thread_id}/messages
Append messages to a chat thread.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
messages | object[] | yes | Messages to append (minimum 1) |
Each message object:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
role | string | yes | — | Message role: user, assistant, system, tool |
content | any | yes | — | Message content (string or structured content blocks) |
metadata | object | no | {} | Arbitrary metadata |
Response: 201 Created
{ "messages": [ { "message_id": "msg_new1", "role": "user", "content": "What caused the auth failure?", "index": 12 } ], "thread_id": "thread_abc123", "new_message_count": 13}curl example:
curl -X POST "http://localhost:61001/v1/threads/thread_abc123/messages?workspace_id=my-workspace" \ -H "Content-Type: application/json" \ -d '{ "messages": [ {"role": "user", "content": "What caused the auth failure?"}, {"role": "assistant", "content": "The token was expired."} ] }'GET /v1/threads/{thread_id}/messages
Get messages from a chat thread with pagination.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
limit | integer | 100 | Max messages to return (1-1000) |
offset | integer | 0 | Pagination offset |
after_index | integer | null | Get messages after this index |
order | string | asc | Message order: asc or desc |
Response: 200 OK
{ "messages": [], "thread_id": "thread_abc123", "total_count": 12}curl example:
# Get latest messagescurl "http://localhost:61001/v1/threads/thread_abc123/messages?order=desc&limit=10"
# Get messages after index 5curl "http://localhost:61001/v1/threads/thread_abc123/messages?after_index=5"DELETE /v1/threads/{thread_id}/messages/{message_id}
Delete a single message from a thread without deleting the thread itself.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
thread_id | string | Thread to delete from |
message_id | string | Message to delete |
Response: 204 No Content
POST /v1/threads/{thread_id}/decompose
Trigger on-demand memory decomposition for unprocessed messages in a thread. Extracts memories from conversation content.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
workspace_id | string | from auth context | Workspace filter |
Response: 200 OK
{ "thread_id": "thread_abc123", "workspace_id": "my-workspace", "messages_processed": 8, "memories_created": 5, "from_index": 4, "to_index": 12}curl example:
curl -X POST "http://localhost:61001/v1/threads/thread_abc123/decompose?workspace_id=my-workspace"Context Environment
All context endpoints require an X-Session-ID header to identify the session sandbox. The context environment provides a server-side Python sandbox for programmatic memory analysis.
POST /v1/context/execute
Execute Python code in the session sandbox. State persists across calls within the same session.
Headers: X-Session-ID (required)
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
code | string | yes | — | Python code to execute |
result_var | string | no | null | Store expression result in this variable |
return_result | boolean | no | true | Include result value in response |
max_return_chars | integer | no | 10000 | Maximum chars for result serialization (100-100000) |
Response: 200 OK
{ "output": "", "result": "4.2", "error": null, "variables_changed": ["result", "total_importance"]}curl example:
curl -X POST http://localhost:61001/v1/context/execute \ -H "Content-Type: application/json" \ -H "X-Session-ID: sess_abc123" \ -d '{ "code": "result = sum(x[\"importance\"] for x in memories)", "result_var": "total_importance", "return_result": true }'POST /v1/context/inspect
Inspect sandbox variables. Omit variable for an overview of all variables.
Headers: X-Session-ID (required)
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
variable | string | null | Specific variable to inspect (omit for overview) |
preview_chars | integer | 200 | Characters to include in value previews |
Response (specific variable): 200 OK
{ "variable": "memories", "type": "list", "preview": "[{'id': 'mem_abc', 'content': 'User prefers...'}]", "size_bytes": 4096}Response (all variables): 200 OK
{ "variable_count": 3, "variables": {"memories": "list (50 items)", "summary": "str", "total": "float"}, "total_size_bytes": 8192}curl example:
# Overview of all variablescurl -X POST http://localhost:61001/v1/context/inspect \ -H "X-Session-ID: sess_abc123"
# Inspect specific variablecurl -X POST "http://localhost:61001/v1/context/inspect?variable=memories&preview_chars=500" \ -H "X-Session-ID: sess_abc123"POST /v1/context/load
Load memories into the sandbox via semantic search.
Headers: X-Session-ID (required)
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
var | string | yes | — | Variable name to store results in |
query | string | yes | — | Memory recall query |
limit | integer | no | 50 | Maximum memories to recall (1-500) |
types | string[] | no | null | Filter by memory types |
tags | string[] | no | null | Filter by tags |
min_relevance | float | no | null | Minimum relevance score (0.0-1.0) |
include_embeddings | boolean | no | false | Include embedding vectors |
Response: 200 OK
{ "count": 12, "variable": "auth_memories", "query": "authentication patterns", "total_available": 25}curl example:
curl -X POST http://localhost:61001/v1/context/load \ -H "Content-Type: application/json" \ -H "X-Session-ID: sess_abc123" \ -d '{ "var": "auth_memories", "query": "authentication patterns", "limit": 50, "types": ["semantic", "procedural"] }'POST /v1/context/inject
Inject a value directly into the sandbox.
Headers: X-Session-ID (required)
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
key | string | yes | — | Variable name |
value | any | yes | — | Value to inject (JSON-serializable) |
parse_json | boolean | no | false | Parse value string as JSON |
Response: 200 OK
{ "variable": "config", "type": "dict", "preview": "{'threshold': 0.7, 'max_items': 100}"}curl example:
curl -X POST http://localhost:61001/v1/context/inject \ -H "Content-Type: application/json" \ -H "X-Session-ID: sess_abc123" \ -d '{ "key": "config", "value": "{\"threshold\": 0.7, \"max_items\": 100}", "parse_json": true }'POST /v1/context/query
Query the server-side LLM with sandbox variables as context.
Headers: X-Session-ID (required)
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
prompt | string | yes | — | Prompt for the LLM |
variables | string[] | no | [] | Variable names to include as context |
max_context_chars | integer | no | null | Maximum chars for variable context (100-500000) |
result_var | string | no | null | Store LLM response in this variable |
Response: 200 OK
{ "response": "Based on the error memories, there are three common patterns...", "variables_used": ["error_memories"], "result_var": "analysis"}curl example:
curl -X POST http://localhost:61001/v1/context/query \ -H "Content-Type: application/json" \ -H "X-Session-ID: sess_abc123" \ -d '{ "prompt": "What are the common error patterns in this data?", "variables": ["error_memories"], "result_var": "analysis" }'POST /v1/context/rlm
Run a Recursive Language Model reasoning loop. The server iteratively generates code, executes it, evaluates results, and continues until the goal is achieved or max iterations are reached.
Headers: X-Session-ID (required)
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
goal | string | yes | — | Natural language description of the goal |
memory_query | string | no | null | Optional memory query to load initial data |
memory_limit | integer | no | 100 | Maximum memories to load (1-500) |
max_iterations | integer | no | 10 | Maximum reasoning iterations (1-50) |
variables | string[] | no | null | Variable names to include in context |
result_var | string | no | null | Store final result in this variable |
detail_level | string | no | standard | Detail level: minimal, standard, verbose |
Response: 200 OK
{ "result": "Analysis found 3 recurring error patterns...", "iterations": 4, "goal_achieved": true, "trace": [ { "iteration": 1, "generated_code": "...", "exec_output": "...", "variables_changed": ["grouped_errors"], "evaluation": "CONTINUE", "action": "continue" } ]}curl example:
curl -X POST http://localhost:61001/v1/context/rlm \ -H "Content-Type: application/json" \ -H "X-Session-ID: sess_abc123" \ -d '{ "goal": "Identify the most common error patterns and their resolutions", "memory_query": "errors and fixes", "memory_limit": 100, "max_iterations": 10, "result_var": "findings" }'GET /v1/context/status
Get sandbox status for the current session.
Headers: X-Session-ID (required)
Response: 200 OK
{ "exists": true, "variable_count": 5, "variables": ["memories", "summary", "config"], "total_size_bytes": 16384, "memory_limit_bytes": 268435456, "metadata": { "created_at": "2026-01-15T10:30:00Z", "exec_count": 12, "total_operations": 20, "last_exec_at": "2026-01-15T10:45:00Z" }}curl example:
curl http://localhost:61001/v1/context/status \ -H "X-Session-ID: sess_abc123"POST /v1/context/checkpoint
Checkpoint sandbox state for persistence. Fires persistence hooks for enterprise deployments.
Headers: X-Session-ID (required)
Response: 204 No Content
curl example:
curl -X POST http://localhost:61001/v1/context/checkpoint \ -H "X-Session-ID: sess_abc123"DELETE /v1/context/cleanup
Remove session sandbox and free resources.
Headers: X-Session-ID (required)
Response: 204 No Content
curl example:
curl -X DELETE http://localhost:61001/v1/context/cleanup \ -H "X-Session-ID: sess_abc123"Skills
Skills are named bundles (a SKILL.md manifest + arbitrary files) that LLM agents can list, fetch, and execute against. Resolution follows the 4-tier scope precedence (user > workspace > tenant > global) described in Skills & MCP Server Registry. Routes are mounted under /v1/skills.
| Endpoint | Purpose |
|---|---|
POST /v1/skills | Create a skill (manifest + initial files in one request) |
GET /v1/skills | List skills visible to the caller; ?include_shadowed=true to keep losers; `?scope=user |
POST /v1/skills/resolve | Resolve a name (or list of names) to precedence-winning skills |
GET /v1/skills/{skill_id} | Get one skill (metadata) |
GET /v1/skills/{skill_id}/manifest | Get just the SKILL.md content |
GET /v1/skills/{skill_id}/files | List all files in the bundle |
GET /v1/skills/{skill_id}/bundle | Stream the full bundle as a single payload |
GET /v1/skills/{skill_id}/files/{file_path:path} | Fetch a single file by path |
PUT /v1/skills/{skill_id} | Update metadata (manifest, scope, etc.) |
PUT /v1/skills/{skill_id}/files/{file_path:path} | Upsert one file (idempotent) |
DELETE /v1/skills/{skill_id} | Delete a skill |
POST /v1/skills/{skill_id}/sync | Two-way sync against a client-provided manifest+files snapshot (used by memorylayer skills sync / watch) |
Skill records carry id, name, version, workspace_id, user_id (when LOCAL/USER-scoped), source_mode (server / mirrored / filesystem), manifest, description, created_at, updated_at. The MCP server exposes skills_list, skills_get, skills_get_file, skills_search (cc profile) and skills_save (full profile) on top of these endpoints.
MCP Server Registry
Workspace-scoped registry of MCP server entries (the same shape as .mcp.json / Claude Code’s ~/.claude.json). Resolution uses the 4-tier scope precedence LOCAL > PROJECT > USER > GLOBAL. Routes are mounted under /v1/mcp-servers.
| Endpoint | Purpose |
|---|---|
POST /v1/mcp-servers | Create an entry |
GET /v1/mcp-servers | List entries (?include_shadowed, ?scope); pulls precedence winners by default |
POST /v1/mcp-servers/resolve | Resolve names; returns the winning entry per name including decrypted env (if authorized) |
POST /v1/mcp-servers/import | Bulk import from a Claude Code or .mcp.json blob |
GET /v1/mcp-servers/export | Export the workspace’s entries to .mcp.json shape (?reveal_secrets=true to include decrypted env values) |
GET /v1/mcp-servers/{server_id} | Get one entry |
PUT /v1/mcp-servers/{server_id} | Update an entry |
DELETE /v1/mcp-servers/{server_id} | Delete an entry |
POST /v1/mcp-servers/{server_id}/sync | Two-way sync against a client-provided snapshot |
Entries carry id, name, transport (stdio / http / sse / streamable-http), command, args, env (encrypted at rest), headers, workspace_id, user_id, source_mode, enabled. The MCP server exposes mcp_servers_list/get/save/delete/import in the full profile.
Documents
Document ingestion (upload, parse, derive memories, page-level retrieval). All endpoints live under /v1/documents.
| Endpoint | Purpose |
|---|---|
POST /v1/documents | Upload a document via multipart/form-data. Form fields: file (the binary), target_context_id, importance, tags, metadata, extraction_options, retain_original |
GET /v1/documents | List documents; supports status, document_type, limit, offset query params |
GET /v1/documents/jobs | List ingestion jobs; ?status filter, paginated |
GET /v1/documents/jobs/{job_id} | Get a single ingestion job with progress + error info |
POST /v1/documents/jobs/{job_id}/cancel | Cancel a running ingestion job |
POST /v1/documents/search | ColPali MaxSim page search (see Document Ingestion -> Search Document Pages) |
GET /v1/documents/{document_id} | Get a single document with status, page count, derived memory IDs |
GET /v1/documents/{document_id}/memories | Get the memories extracted from a document |
GET /v1/documents/{document_id}/pages | List pages (page_no, transcript, transcript_model) |
GET /v1/documents/{document_id}/pages/{page_id} | Get a single page |
POST /v1/documents/{document_id}/reprocess | Re-run extraction with optional new extraction_options (creates a new ingestion job) |
DELETE /v1/documents/{document_id} | Delete a document; ?delete_memories=true to cascade to derived memories |
Page search request body (POST /v1/documents/search):
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | yes | — | Natural-language search query |
limit | integer | no | 10 | Max results (1-100) |
doc_ids | string[] | no | — | Restrict search to specific document IDs |
Returns PageSearchResponse with pages: DocumentPageResponse[] (each carrying a relevance_score), total_count, and the original query. The OSS SQLite backend scores in Python after a filtered fetch; the Enterprise PostgreSQL backend pushes MaxSim into the database. Returns 501 if the active storage backend does not implement search_pages_by_maxsim.
Data Providers
Registry / metadata surface for external ingestion sources. The OSS server only ships the local connector type and POST /v1/data-providers/{provider_id}/sync is a no-op there — see Data Providers and the enterprise connector pack for the full picture. Routes live under /v1/data-providers.
| Endpoint | Purpose |
|---|---|
POST /v1/data-providers | Create a provider record (name, provider_type, connection_args, encrypted_args, schedule, metadata) |
GET /v1/data-providers | List providers in the workspace; ?limit, ?offset |
GET /v1/data-providers/{provider_id} | Get one provider (encrypted_args is never returned in the response) |
PUT /v1/data-providers/{provider_id} | Update fields (partial — only provided fields are touched) |
DELETE /v1/data-providers/{provider_id} | Delete the provider (does not affect previously-ingested documents) |
POST /v1/data-providers/{provider_id}/sync | Trigger a one-off sync. OSS: no-op, returns empty list. Enterprise: invokes the connector to discover and queue new/updated documents |
Knowledgebase
Knowledgebase generation, article browsing, and graph community export. Endpoints under /v1/knowledgebase.
| Endpoint | Purpose |
|---|---|
POST /v1/knowledgebase/generate | Trigger knowledgebase generation for the workspace (sync or async); body accepts context_id, since, force, etc. |
GET /v1/knowledgebase | Get the workspace knowledgebase index / metadata |
GET /v1/knowledgebase/articles | List articles (paginated) |
GET /v1/knowledgebase/articles/{article_id:path} | Get an article by path (path-style IDs supported) |
GET /v1/knowledgebase/export | Export the workspace knowledgebase as JSON |
GET /v1/knowledgebase/graph | Get the knowledgebase graph (supports include_rpg=true to merge in RPG nodes; see Repository Planning Graph) |
GET /v1/knowledgebase/graph/communities/{community_id} | Drill into a specific graph community (cluster of related memories) |
Knowledgebase articles are LLM-synthesized topic summaries assembled from clusters of related memories.
Graph Analysis
Workspace-wide graph analysis primitives. Endpoints under /v1/graph.
| Endpoint | Purpose |
|---|---|
GET /v1/graph/snapshot | Materialized workspace graph snapshot (nodes + edges). Supports context_id, include_rpg, node_types, relationship_types |
GET /v1/graph/communities | Detected communities (Louvain / Leiden); ?algorithm, ?resolution, ?min_size |
GET /v1/graph/centrality | Per-node centrality scores (betweenness, degree, eigenvector, pagerank) |
GET /v1/graph/bridges | Bridge nodes / edges (high-betweenness connectors between communities) |
GET /v1/graph/stats | Aggregate stats: node/edge counts, density, average degree, connected components |
POST /v1/graph/analyze | Run a composite analysis pass; body controls which subreports to include and applies include_rpg, filters, etc. |
The include_rpg query/body flag pulls Repository Planning Graph nodes into the snapshot when a Forge-equipped deployment has populated them.
Audit
Audit log surfacing. The audit service is OSS-pluggable; in the OSS default no audit events are emitted, so these endpoints return empty results unless a custom audit plugin is configured (enterprise ships a backed implementation). Routes live under /v1/audit.
| Endpoint | Purpose |
|---|---|
GET /v1/audit/events | List audit events; supports workspace_id, actor_id, resource_type, action, since, until, limit, offset |
GET /v1/audit/events/summary | Aggregated counts grouped by resource_type / action / actor_id over a time window |
Each event record carries id, tenant_id, workspace_id, actor_id, resource_type, resource_id, action, metadata, created_at.
Tokens
API token issuance and revocation. Routes live under /v1/tokens. In the OSS server the tokens plugin ships disabled by default (is_enabled=False); when enabled, it proxies to the Aether gRPC token service rather than minting tokens locally. See Server -> Aether Transport for the rationale and Administration -> API Keys for the enterprise-facing semantics.
| Endpoint | Purpose |
|---|---|
GET /v1/tokens | List tokens visible to the caller (paginated) |
POST /v1/tokens | Create a new token (name, principal_type, workspace_patterns, scopes, expires_in_days); returns the secret once at creation time |
GET /v1/tokens/{token_id} | Get token metadata (never returns the secret) |
DELETE /v1/tokens/{token_id} | Delete a token (hard remove) |
POST /v1/tokens/{token_id}/revoke | Revoke without deleting (audit-preserving) |
Calls return 503 Service Unavailable when the plugin is disabled and no Aether connection is configured.
Health
GET /health
Health check endpoint.
Response: 200 OK
curl example:
curl http://localhost:61001/healthGET /health/ready
Readiness check with service status.
Response: 200 OK
curl example:
curl http://localhost:61001/health/ready