All endpoints require JWT authentication via Authorization: Bearer <token> header or nerve_token cookie.
Login with password, receive JWT.
Request: { "password": "..." }
Response: { "token": "eyJ..." }Verify current authentication.
Response: { "authenticated": true }List all sessions, ordered by most recently updated.
Response: { "sessions": [{ "id": "main", "title": "Main", "source": "system", "updated_at": "..." }] }Create a new session.
Request: { "title": "My Session" }
Response: { "id": "a1b2c3d4", "title": "My Session", "source": "web" }Get session details.
Get messages for a session.
Response: { "messages": [{ "id": 1, "role": "user", "content": "...", "channel": "web", "created_at": "..." }] }Delete a session (cannot delete "main"). Disconnects any active SDK client before deletion.
Session status with lifecycle info.
Response: {
"session_id": "a1b2c3d4",
"status": "active",
"is_running": true,
"sdk_session_id": "8fbba4a4-...",
"connected_at": "2026-02-27T12:00:00+00:00",
"parent_session_id": null,
"message_count": 42,
"total_cost_usd": 0.0
}Fork a session, optionally from a specific message point.
Request: { "source_session_id": "main", "at_message_id": "msg-42", "title": "My Fork" }
Response: { "id": "fork-a1b2c3d4", "title": "My Fork", "source": "web", "status": "created", "parent_session_id": "main" }Resume a stopped or idle session (must have a stored sdk_session_id).
Response: { "id": "a1b2c3d4", "status": "created", "sdk_session_id": "..." }Archive a session (soft delete, cannot archive "main"). Disconnects any active SDK client.
Response: { "archived": true }Get session lifecycle event log (newest first).
Response: {
"events": [
{ "id": 3, "session_id": "abc", "event_type": "idle", "details": { "resumable": true }, "created_at": "..." },
{ "id": 2, "session_id": "abc", "event_type": "started", "details": { "sdk_session_id": "..." }, "created_at": "..." },
{ "id": 1, "session_id": "abc", "event_type": "created", "details": { "source": "web" }, "created_at": "..." }
]
}List files modified during a session with diff stats. Reads from session_file_snapshots table and compares against current file content on disk.
Response: {
"files": [
{ "path": "/home/user/project/foo.py", "short_path": "project/foo.py", "status": "modified", "stats": { "additions": 15, "deletions": 3 }, "created_at": "2026-03-04T07:00:00Z" }
],
"summary": { "total_files": 1, "total_additions": 15, "total_deletions": 3 }
}Compute a unified diff for a single file against its session baseline snapshot. Returns structured hunks with line numbers for GitHub PR-style rendering.
Response: {
"path": "/home/user/project/foo.py",
"short_path": "project/foo.py",
"status": "modified",
"binary": false,
"stats": { "additions": 15, "deletions": 3 },
"hunks": [
{
"old_start": 10, "old_count": 5, "new_start": 10, "new_count": 7, "header": "class Foo:",
"lines": [
{ "type": "context", "content": " def bar(self):", "old_line": 10, "new_line": 10 },
{ "type": "deletion", "content": " return None", "old_line": 11 },
{ "type": "addition", "content": " return 42", "new_line": 11 }
]
}
],
"truncated": false
}Send a message and get the complete response (non-streaming).
Request: { "message": "Hello", "session_id": "main" }
Response: { "response": "Hi there!", "session_id": "main" }For streaming, use the WebSocket endpoint.
List tasks with optional status filter. Valid statuses: pending, in_progress, done, deferred, or empty (all non-done).
Full-text search on task titles and content (FTS5). Optional status filter.
Response: { "tasks": [{ "id": "2026-03-01-fix-bug", "title": "Fix bug", "status": "pending", ... }] }Create a task.
Request: { "title": "Fix bug", "content": "Details...", "deadline": "2026-03-01" }Get task details including full markdown file content.
Response: { "id": "2026-03-01-fix-bug", "title": "Fix bug", "status": "pending", "content": "# Fix bug\n\n...", ... }Update a task. All fields are optional. content replaces the full markdown file; title and deadline are re-synced to SQLite.
Request: { "status": "done", "note": "Fixed in PR #123" }
Request: { "content": "# Updated Title\n\n**Deadline:** 2026-03-15\n\nNew details..." }List all skills with aggregated usage statistics.
Response: {
"skills": [{
"id": "my-skill", "name": "my-skill", "description": "Query database...",
"version": "1.0.0", "enabled": true, "total_invocations": 5, "success_count": 5,
"avg_duration_ms": 12, "last_used": "2026-03-06T21:00:00"
}]
}Get full skill content, metadata, references, and usage stats.
Create a new skill.
Request: { "name": "code-review", "description": "This skill should be used when...", "content": "## Steps\n..." }
Response: { "id": "code-review", "name": "code-review", "created": true }Update a skill's SKILL.md content (full raw file including frontmatter).
Request: { "content": "---\nname: code-review\ndescription: ...\n---\n\n# Instructions\n..." }
Response: { "id": "code-review", "name": "code-review", "updated": true }Delete a skill (removes directory and DB record).
Enable or disable a skill.
Request: { "enabled": false }
Response: { "id": "code-review", "enabled": false }Get usage history and aggregate stats for a skill.
Aggregate usage stats across all skills.
Re-scan the workspace/skills/ directory and sync to DB. Discovers new skills, removes deleted ones, preserves enabled state.
List all MCP servers with aggregated usage statistics.
Response: {
"servers": [{
"name": "nerve", "type": "sdk", "enabled": true, "tool_count": 34,
"total_invocations": 127, "success_count": 125, "avg_duration_ms": null,
"last_used": "2026-03-14T19:00:00", "first_seen_at": "...", "last_seen_at": "..."
}]
}Get server detail including per-tool breakdown and recent usage.
Response: {
"name": "nerve", "type": "sdk", ...,
"tools": [{ "tool_name": "task_list", "invocations": 42, "success_count": 42, "avg_duration_ms": null, "last_used": "..." }],
"recent_usage": [{ "id": 1, "server_name": "nerve", "tool_name": "task_list", "session_id": "abc", "success": true, "created_at": "..." }]
}Paginated usage history for a server.
Re-read MCP server config from YAML files and refresh the in-memory cache. New sessions will use updated config.
Response: { "reloaded": 2, "servers": [...] }List markdown files in workspace.
Read a memory file.
Write a memory file.
Request: { "content": "# Updated content..." }Get memU categories, items, and indexed resources.
Response: {
"available": true,
"categories": [{ "id": "...", "name": "preferences", "description": "...", "summary": "..." }],
"items": [{ "id": "...", "memory_type": "profile", "summary": "User works at Acme Corp", "resource_id": "...", "created_at": "...", "happened_at": "..." }],
"resources": [{ "id": "...", "url": "/path/to/file.md", "modality": "document", "caption": "...", "created_at": "..." }],
"category_items": { "category_id": ["item_id_1", "item_id_2"] }
}Create a new category.
Request: { "name": "travel", "description": "Travel plans and logistics" }
Response: { "name": "travel", "created": true }Update a category's summary or description. Re-embeds the category after update.
Request: { "summary": "Updated summary text", "description": "New description" }
Response: { "id": "...", "updated": true }Update a memory item's content, type, or category assignments.
Request: { "content": "New text", "memory_type": "knowledge", "categories": ["work"] }
Response: { "id": "...", "updated": true }Delete a memory item.
Response: { "id": "...", "deleted": true }memU service health metrics and operation stats.
Response: {
"initialized_at": "...", "service_available": true,
"operations": { "recall": { "call_count": 5, "avg_duration_s": 0.8, "error_count": 0 }, ... },
"in_flight": [],
"database": { "total_items": 2924, "total_categories": 24, "db_size_mb": 132.97, "type_distribution": { "profile": 671, ... } }
}Paginated audit log of memU mutations.
Response: {
"logs": [{ "id": 1, "timestamp": "...", "action": "item_deleted", "target_type": "item", "target_id": "abc123", "source": "agent_tool", "details": {} }],
"offset": 0, "limit": 100
}System health and status, including task/FTS index health.
Response: {
"system": { "hostname": "...", "memory_mb": 65.2, "disk_free_gb": 180.5 },
"tasks": { "total": 92, "active": 16, "done": 76, "fts_indexed": 92, "fts_ok": true },
"sync": { "github": { "cursor": "...", "last_run": "...", "records_fetched": 3, "records_processed": 3, "error": null } },
"recent_cron_logs": [...]
}Get cron job execution logs.
No auth required.
Response: { "status": "ok", "version": "0.1.0" }Connect to ws[s]://host:port/ws?token=<jwt>.
// Send a chat message
{ type: "message", content: "Hello", session_id: "main" }
// Stop the running agent
{ type: "stop", session_id: "main" }
// Switch active session
{ type: "switch_session", session_id: "abc123" }
// Fork a session
{ type: "fork", session_id: "main", at_message_id: "msg-42", title: "My Fork" }
// Resume a stopped/idle session
{ type: "resume", session_id: "abc123" }
// Keep-alive
{ type: "ping" }// Streaming token (parent_tool_use_id set when from a sub-agent)
{ type: "token", session_id: "main", content: "Hello", parent_tool_use_id?: "toolu_parent" }
// Extended thinking
{ type: "thinking", session_id: "main", content: "Let me check...", parent_tool_use_id?: "toolu_parent" }
// Tool call started
{ type: "tool_use", session_id: "main", tool: "Read", input: { file_path: "..." }, tool_use_id: "toolu_...", parent_tool_use_id?: "toolu_parent" }
// Tool call result
{ type: "tool_result", session_id: "main", tool_use_id: "toolu_...", result: "...", is_error: false, parent_tool_use_id?: "toolu_parent" }
// Sub-agent started (Task tool invoked)
{ type: "subagent_start", session_id: "main", tool_use_id: "toolu_...", subagent_type: "Explore", description: "find auth", model?: "haiku" }
// Sub-agent completed
{ type: "subagent_complete", session_id: "main", tool_use_id: "toolu_...", duration_ms: 12345, is_error: false }
// Agent turn complete (includes context usage and boundary)
{ type: "done", session_id: "main", usage: { input_tokens: 1234, output_tokens: 567, cache_read_input_tokens: 890, cache_creation_input_tokens: 0 }, max_context_tokens: 1048576, context_boundary: "2026-02-25T10:00:00+00:00" }
// Agent stopped by user
{ type: "stopped", session_id: "main" }
// Error occurred
{ type: "error", session_id: "main", error: "..." }
// Session switch confirmed (includes running state, lifecycle status, buffered events for reconnect)
{ type: "session_status", session_id: "abc123", is_running: true, status: "active", buffered_events: [...] }
{ type: "session_switched", session_id: "abc123" }
// Session title updated (AI-generated)
{ type: "session_updated", session_id: "abc123", title: "Italy Vacation Planning" }
// Session forked
{ type: "session_forked", source_id: "main", fork_id: "fork-a1b2c3d4", title: "My Fork" }
// Session resumed
{ type: "session_resumed", session_id: "abc123" }
// Session archived
{ type: "session_archived", session_id: "abc123" }
// Plan file updated (Write/Edit to .claude/plans/)
{ type: "plan_update", session_id: "main", content: "# Plan\n..." }
// File modified by agent (Edit/Write/NotebookEdit succeeded)
{ type: "file_changed", session_id: "main", path: "/home/user/project/foo.py", operation: "edit", tool_use_id: "toolu_..." }
// Interactive tool waiting for user input (AskUserQuestion, ExitPlanMode, EnterPlanMode)
{ type: "interaction", session_id: "main", interaction_id: "uuid", interaction_type: "question" | "plan_exit" | "plan_enter", tool_name: "AskUserQuestion", tool_input: { ... } }
// Keep-alive response
{ type: "pong" }