8.5 KiB
Runtime API (HTTP/SSE)
DeepSeek TUI can expose a local runtime API for external clients:
deepseek serve --http --host 127.0.0.1 --port 7878 --workers 2
Defaults:
- bind:
127.0.0.1:7878 - workers:
2(clamped to1..8)
Implementation note:
- The current production runtime lives in
crates/tui(runtime_api.rs,runtime_threads.rs,task_manager.rs). - Workspace crate extraction is in progress, but external behavior should be read from the
crates/tuiimplementation today.
Security Model (Local-First)
- The server is designed for trusted local use.
- There is no built-in auth, user isolation, or TLS termination.
- Do not expose this API directly to untrusted networks.
- If remote access is required, place it behind your own authenticated reverse proxy/VPN.
Runtime Data Model
The runtime uses a durable Thread/Turn/Item lifecycle.
ThreadRecordid,created_at,updated_atmodel,workspace,modetask_id(optional durable task link)coherence_state:healthy|getting_crowded|refreshing_context|verifying_recent_work|resetting_plansystem_prompt(optional text)latest_turn_id,latest_response_bookmark,archived
TurnRecordid,thread_idstatus:queued|in_progress|completed|failed|interrupted|canceled- timestamps, duration, usage, error summary
TurnItemRecordid,turn_idkind:user_message|agent_message|tool_call|file_change|command_execution|context_compaction|status|error- lifecycle
status:queued|in_progress|completed|failed|interrupted|canceled metadata(optional tool result metadata; used for task checklist/gate/artifact updates)
The event log is append-only with global monotonic seq for replay/resume.
Session resume note:
- Saved session
system_promptcurrently round-trips as plain text. StructuredSystemPrompt::Blocksmetadata is not preserved when resuming into runtime threads.
Restart note:
- If the process restarts while a turn or item is
queuedorin_progress, the recovered record is markedinterruptedwith an"Interrupted by process restart"error instead of remaining stuck in a live state.
Approval note:
auto_approveapplies to the runtime approval bridge and the engine tool context. When enabled for a thread/turn/task, approval-required tools are auto-approved in the non-interactive runtime path, shell safety checks run in auto-approved mode, and spawned subagents inherit that effective setting for their own tool context.- If omitted when creating a thread or starting
/v1/stream,auto_approvedefaults tofalse.
Endpoints
Health and Session
GET /healthGET /v1/sessions?limit=50&search=<substring>GET /v1/sessions/{id}DELETE /v1/sessions/{id}POST /v1/sessions/{id}/resume-threadGET /v1/workspace/statusGET /v1/skillsGET /v1/apps/mcp/serversGET /v1/apps/mcp/tools?server=<optional>
Resume session request body (all fields optional):
{
"model": "deepseek-v4-pro",
"mode": "agent"
}
Resume session response:
{
"thread_id": "thr_1234abcd",
"session_id": "sess_5678efgh",
"message_count": 24,
"summary": "Resumed session 'Refactor plan' (24 messages) into thread thr_1234abcd"
}
Compatibility Stream (Single Turn)
POST /v1/stream
Backwards-compatible one-shot SSE wrapper. Internally creates an archived runtime thread+turn.
Request body:
{
"prompt": "Summarize recent commits",
"model": "deepseek-v4-pro",
"mode": "agent",
"workspace": ".",
"allow_shell": false,
"trust_mode": false,
"auto_approve": true
}
Typical SSE events:
turn.startedmessage.deltatool.startedtool.progresstool.completedapproval.requiredsandbox.deniedstatuserrorturn.completeddone
Thread Lifecycle
POST /v1/threadsGET /v1/threads?limit=50&include_archived=falseGET /v1/threads/summary?limit=50&search=<optional>&include_archived=falseGET /v1/threads/{id}PATCH /v1/threads/{id}(currently supports{ "archived": true|false })POST /v1/threads/{id}/resumePOST /v1/threads/{id}/fork
Create thread request example:
{
"model": "deepseek-v4-pro",
"workspace": ".",
"mode": "agent",
"allow_shell": false,
"trust_mode": false,
"auto_approve": true,
"archived": false,
"task_id": "task_1234abcd"
}
Turn Lifecycle
POST /v1/threads/{id}/turnsPOST /v1/threads/{id}/turns/{turn_id}/steerPOST /v1/threads/{id}/turns/{turn_id}/interruptPOST /v1/threads/{id}/compact
Notes:
- Only one active turn is allowed per thread (
409 Conflicton overlap). interruptreturns quickly and marksturn.interrupt_requested.- Terminal turn status becomes
interruptedonly after cleanup completes. - Manual compaction is exposed as a turn with
context_compactionitem lifecycle events. - Archiving/unarchiving threads updates persisted thread state and emits
thread.updated.
Replayable Events
GET /v1/threads/{id}/events?since_seq=<u64>
Returns SSE replay backlog, then live events for that thread.
SSE payload shape:
{
"seq": 42,
"timestamp": "2026-02-11T20:18:49.123Z",
"thread_id": "thr_1234abcd",
"turn_id": "turn_5678efgh",
"item_id": "item_90ab12cd",
"event": "item.delta",
"payload": {
"delta": "partial output",
"kind": "agent_message"
}
}
Common event names:
thread.startedthread.forkedturn.startedturn.lifecycleturn.steeredturn.interrupt_requestedturn.completeditem.starteditem.deltaitem.completeditem.faileditem.interruptedapproval.requiredsandbox.deniedcoherence.state
Compaction visibility:
- auto compaction emits
item.started/item.completedwith item kindcontext_compactionandauto=true - manual compaction emits the same with
auto=false
Coherence visibility:
coherence.stateis a machine-readable session-health signal derived from existing capacity and compaction events. The payload includesstate,label,description,reason, and the updatedthread.- Normal clients should show the
labelordescription, not internal capacity scores or formulas.
Background Tasks
GET /v1/tasksPOST /v1/tasksGET /v1/tasks/{id}POST /v1/tasks/{id}/cancel
Tasks execute through the same runtime thread/turn pipeline and include:
- linked
thread_id/turn_id - runtime event count
- timeline + tool summaries + artifact references
- subordinate checklist state from
checklist_*/ legacytodo_*tools - structured verification gates from
task_gate_run/ completedtask_shell_wait - PR attempt metadata and patch artifacts
- guarded GitHub write events
Durable tasks are the model-visible work object. Checklist/todo state is progress inside the active task/thread, not a parallel task system.
Task-aware model-visible tools:
task_create,task_list,task_read,task_canceltask_gate_runtask_shell_start,task_shell_waitpr_attempt_record,pr_attempt_list,pr_attempt_read,pr_attempt_preflightgithub_issue_context,github_pr_context,github_comment,github_close_issue
Automations
GET /v1/automationsPOST /v1/automationsGET /v1/automations/{id}PATCH /v1/automations/{id}DELETE /v1/automations/{id}POST /v1/automations/{id}/runPOST /v1/automations/{id}/pausePOST /v1/automations/{id}/resumeGET /v1/automations/{id}/runs?limit=20
RRULE support is intentionally constrained to:
- hourly:
FREQ=HOURLY;INTERVAL=<hours>[;BYDAY=MO,TU,...] - weekly:
FREQ=WEEKLY;BYDAY=...;BYHOUR=<0-23>;BYMINUTE=<0-59>
Automations are persisted under ~/.deepseek/automations (override with DEEPSEEK_AUTOMATIONS_DIR).
Each run is executed as a normal background task and links to task/thread/turn ids.
The same automation manager is exposed to the model through automation_*
tools. Create/update/delete/run operations require approval; automation_run
and scheduled runs enqueue ordinary durable tasks rather than using a separate
execution path.
Persistence
Runtime store (default under task data root):
runtime/threads/*.jsonruntime/turns/*.jsonruntime/items/*.jsonruntime/events/{thread_id}.jsonlruntime/state.json(monotonic sequence)
Task store:
- default
~/.deepseek/tasks(override withDEEPSEEK_TASKS_DIR)
Both runtime and task state are restart-aware.
Queued or in-progress runtime turns reload as interrupted; task execution performs its own recovery on top of the same persisted thread/turn store.