TermDeck exposes a local HTTP API for agents and scripts. The default server is http://127.0.0.1:8530.
Authentication is disabled by default; configure TERMDECK_ACCESS_TOKEN before direct network exposure. When
enabled, add Authorization: Bearer <token> to every request. TERMDECK_READ_ONLY=1 rejects all mutating API
calls even after authentication.
These endpoints start real persistent TermDeck terminals. A successful prompt response means the prompt was
written to the terminal and submitted; it does not mean the agent has finished processing it. Use
GET /api/sessions/{session_id}/last_turn for the minimal status/result poll.
The project header can switch between the repository root and every Git worktree discovered for that repository.
Sessions, closed sessions, terminal layout, files, search, and Git views are scoped to the selected worktree. The
root worktree always has the stable ID root; child IDs are stable across server restarts.
List the worktrees for a registered project:
curl -sS 'http://127.0.0.1:8530/api/worktrees?project=stock'Create a worktree from the current branch, or provide base_ref and an explicit branch:
curl -sS -X POST http://127.0.0.1:8530/api/worktrees \
-H 'Content-Type: application/json' \
-d '{"project":"stock","name":"review","base_ref":"main"}'TermDeck creates the branch and a free folder below <repository>-worktrees/, beside the repository itself.
Pass location to put it somewhere else — it must be an absolute path outside the repository. Select the
returned id when creating a terminal:
{"project":"stock","worktree_id":"wt-abc123","model":"codex","title":"reviewer"}Delete a worktree only after its terminals are closed and purged. Set move_to_trash to move its folder to the
configured trash directory; false leaves the files in place and detaches the Git worktree:
curl -sS -X DELETE http://127.0.0.1:8530/api/worktrees/wt-abc123 \
-H 'Content-Type: application/json' \
-d '{"project":"stock","move_to_trash":true}'POST /api/terminals/task creates one terminal, starts it immediately, submits a single prompt, and returns
the created session summary. Set origin_session to have the completed child result sent back to that session.
task_json=$(curl -sS -X POST http://127.0.0.1:8530/api/terminals/task \
-H 'Content-Type: application/json' \
-d '{
"title": "reviewer",
"cwd": "/Users/dan/workspace/stock",
"project": "stock",
"model": "codex",
"model_name": "gpt-5.6-luna xhigh",
"permission": "workspace-write",
"prompt": "Please review this terminal state and summarize the top 3 risks.",
"output_path": "/tmp/termdeck/reviewer.out",
"after": "termde",
"origin_session": "termde",
"bracketed": true,
"queue": false
}')If project is omitted and after is the unique session/group name in a single project, TermDeck infers that project
from the anchor before creating the new terminal.
For a minimal result poll, use GET /api/sessions/{session_id}/last_turn:
session_id=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["session_id"])' <<< "$task_json")
curl -sS "http://127.0.0.1:8530/api/sessions/$session_id/last_turn"Relative output_path values are resolved under cwd before writing.
Response:
{
"session_id": "abc123...",
"status": "completed",
"last_turn": {"role": "assistant", "text": "..."}
}output_path is where raw terminal bytes are appended. Set a per-project path and include that file in any monitor
process that needs deterministic logs.
model_name is passed as an explicit --model argument to Codex, Claude, or AGY.
The request is not blocking; it returns after prompt submission. Poll last_turn for status and the latest turn.
Session IDs are globally unique, so agent callers address a terminal only by /api/sessions/{session_id}. A
worktree_id is session metadata supplied in the create/task request or used as a list/layout filter; it is not
part of the agent session URL.
Set worktree_id to run the child in an existing project worktree. The older worktree: true option remains available
for automation callers that want TermDeck to create a worktree for that individual terminal. The optional
worktree_branch and worktree_base fields select the branch name and base ref; otherwise TermDeck generates a branch
under termdeck/ from the terminal title. The response includes worktree_path, worktree_branch, and the base
commit. This does not make the request blocking and it does not commit changes for the agent.
POST /api/terminals/batch creates up to 32 terminals and submits their prompts. The top-level prompt,
cwd, project, model, permission, bracketed, queue, after, and worktree values are defaults for every item.
An item can override any of them. after accepts an existing session name or group name (case-insensitive),
or the stable session:<id> / group:<id> layout token. It inserts each new terminal immediately after that
anchor. If the anchor is a member of a group, the new terminal inherits that group and is inserted immediately
after that member; when several items share the same after, their request order is preserved. Every request
creates new terminals; it is not idempotent.
For a new Codex terminal, name is also submitted as Codex's thread name after the new session is detected.
The initial prompt is sent only after that rename and the Codex composer are ready, so it is not lost during
startup. Resuming an existing Codex session does not rename the resumed thread.
curl -sS -X POST http://127.0.0.1:8530/api/terminals/batch \
-H 'Content-Type: application/json' \
-d '{
"cwd": "/Users/dan/workspace/stock",
"project": "stock",
"model": "codex",
"model_name": "gpt-5.6-luna xhigh",
"permission": "workspace-write",
"after": "existing session or group name",
"prompt": "Inspect the current task, make the requested change, and report the result.",
"terminals": [
{"name": "x"},
{"name": "y"},
{"name": "z"}
]
}'The response contains one result per requested terminal. A terminal that was created successfully remains available even if its prompt submission fails, so a partial failure does not silently kill work already started.
{
"requested": 3,
"created": 3,
"prompt_submitted": 3,
"failed": 0,
"items": [
{
"name": "x",
"session": {
"session_id": "abc123...",
"title": "x",
"project": "stock",
"agent_kind": "codex",
"agent_session_id": null,
"running": true
},
"prompt_submitted": true,
"queued": false
}
]
}The agent session ID may initially be null; TermDeck discovers the Codex or Claude session asynchronously
after the CLI creates its session file.
For callers that want individual control, use the existing session-create endpoint followed by the prompt
endpoint. It also accepts the optional after field, using the same session/group name or stable layout token
rules as the batch endpoint.
session_json=$(curl -sS -X POST http://127.0.0.1:8530/api/sessions \
-H 'Content-Type: application/json' \
-d '{
"title": "x",
"cwd": "/Users/dan/workspace/stock",
"project": "stock",
"model": "codex",
"model_name": "gpt-5.6-luna xhigh",
"permission": "workspace-write",
"after": "termde"
}')
session_id=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["session_id"])' <<< "$session_json")
curl -sS -X POST "http://127.0.0.1:8530/api/sessions/$session_id/prompt" \
-H 'Content-Type: application/json' \
-d '{
"text": "Inspect the current task, make the requested change, and report the result.",
"bracketed": true,
"queue": false
}'bracketed defaults to true and sends the prompt as one paste operation before pressing Enter. Set
queue: true for Codex to place the prompt in its queue with Tab instead of submitting it for immediate
processing. If a requested placement target is missing or ambiguous, that terminal is still created and its
prompt is still submitted; the item reports placement_error and the response increments placement_failed.
Every session created with worktree: true exposes its branch and worktree folder in the terminal list. Review the
parent-relative commits, changed files, and diff with:
curl -sS "http://127.0.0.1:8530/api/sessions/$session_id/worktree/review"Finish it with one of these actions:
curl -sS -X POST "http://127.0.0.1:8530/api/sessions/$session_id/worktree/finish" \
-H 'Content-Type: application/json' \
-d '{"action":"keep"}'keep leaves the folder and branch in place and detaches them from TermDeck cleanup. merge requires the worktree
to be clean and merges its branch into the recorded base branch, then removes the worktree and session. discard
force-removes the worktree and branch and removes the session. The finish calls are separate from prompt execution;
an agent must commit its changes before merge can proceed.
List active terminals:
curl -sS 'http://127.0.0.1:8530/api/sessions?project=stock'Delete a terminal and stop its running process:
curl -sS -X DELETE "http://127.0.0.1:8530/api/sessions/$session_id"The delete succeeds only after TermDeck has terminated that session's dtach process tree and verified that its socket was removed. A failed cleanup returns HTTP 409 and leaves the terminal session visible for inspection.
GET /api/terminals/processes is a local, read-only inventory of processes reachable from TermDeck's own
dtach sockets. It reports each socket's session/title, whether it is attached or detached, descendant PIDs,
RSS, CPU, process state, node_repl count, zombie count, and any socket with no persisted session record.
curl -sS http://127.0.0.1:8530/api/terminals/processesPOST /api/terminals/reclaim-orphans is deliberately explicit: it terminates only process trees reachable
from dtach sockets that are not present in the TermDeck session store, then verifies their socket removal. It
does not affect named/current sessions.
curl -sS -X POST http://127.0.0.1:8530/api/terminals/reclaim-orphansThe normal terminal WebSocket remains available at /ws/<session_id> for interactive input, resize events,
scrollback, and live output. The HTTP prompt endpoint is intended for automation that does not need to attach a
terminal renderer.