Events and the socket
A turn is a stream of events exactly as the olix core emitted them. Each carries protocol (olix.codeui/1), type, session_id, request_id (the turn id), seq and ts. The last event of a turn is always task_complete, unless the core goes away, in which case an error event says so; the API never invents a completion.
A turn can also emit open_in_editor, answer_verification, auto_verify, plan_ready, inference_progress, compaction, memory_used and jobs. They are passed through unchanged. Clients must ignore event types they do not know.
Server-Sent Events
On POST /v1/turns each event is one SSE message: event: <type> and data: <json>. The turn id is also in the X-Olix-Turn header.
curl -sN http://127.0.0.1:8780/v1/turns \
-H "Authorization: Bearer $OLIX_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "Say hello in five words.", "cwd": "/tmp/olix-demo/project"}'Show the real output (20 lines)
event: accepted
data: {"protocol":"olix.codeui/1","type":"accepted","request_id":"t_abd196b48cf83e93","session_id":"20261106132214-54f2e5"}
event: memory_used
data: {"fact_ids":[],"style":["length"],"ms":0.3,"protocol":"olix.codeui/1","type":"memory_used","session_id":"20261106132214-54f2e5","request_id":"t_abd196b48cf83e93","seq":0,"ts":1793971334.525,"epoch":"cdca17e5-d15b-4dee-b565-34a7f275e474","session_seq":1}
event: assistant_start
data: {"protocol":"olix.codeui/1","type":"assistant_start","session_id":"20261106132214-54f2e5","request_id":"t_abd196b48cf83e93","seq":1,"ts":1793971334.537,"epoch":"cdca17e5-d15b-4dee-b565-34a7f275e474","session_seq":2}
event: assistant_delta
data: {"text":"stand-in reply to: Say hello in five words.","protocol":"olix.codeui/1","type":"assistant_delta","session_id":"20261106132214-54f2e5","request_id":"t_abd196b48cf83e93","seq":2,"ts":1793971334.537,"epoch":"cdca17e5-d15b-4dee-b565-34a7f275e474","session_seq":3}
event: assistant_end
data: {"text":"stand-in reply to: Say hello in five words.","protocol":"olix.codeui/1","type":"assistant_end","session_id":"20261106132214-54f2e5","request_id":"t_abd196b48cf83e93","seq":3,"ts":1793971334.537,"epoch":"cdca17e5-d15b-4dee-b565-34a7f275e474","session_seq":4}
event: usage
data: {"prompt_tokens":5,"cached_tokens":0,"output_tokens":1,"tok_s":0,"context_pct":0,"ttft_ms":1,"pass_id":"call_mw507ouf2","model":"olx-1","kind":"chat","protocol":"olix.codeui/1","type":"usage","session_id":"20261106132214-54f2e5","request_id":"t_abd196b48cf83e93","seq":4,"ts":1793971334.537,"epoch":"cdca17e5-d15b-4dee-b565-34a7f275e474","session_seq":5}
event: task_complete
data: {"outcome":"answered","text":"stand-in reply to: Say hello in five words.","result":{"state":"completed","answer":"stand-in reply to: Say hello in five words.","summary":"stand-in reply to: Say hello in five words."},"protocol":"olix.codeui/1","type":"task_complete","session_id":"20261106132214-54f2e5","request_id":"t_abd196b48cf83e93","seq":5,"ts":1793971334.549,"epoch":"cdca17e5-d15b-4dee-b565-34a7f275e474","session_seq":6}Event types
accepted
The turn started.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | "accepted" | yes | |
request_id | string | yes | |
session_id | string | yes |
steered
The session already had a turn running; the text was queued into it.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | "steered" | yes | |
request_id | string | yes | |
session_id | string | yes | |
turn_request_id | string | yes |
alive
Heartbeat every 10 s while a turn runs.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. |
assistant_start
A reply is starting.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. |
assistant_delta
A piece of reply text.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
text | string | yes |
thinking_delta
A piece of the model's reasoning, when the model emits one.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
text | string | yes |
assistant_end
The reply is complete; text is the full reply.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
text | string | yes |
commentary
A work note written before tool calls. Never the answer.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
text | string | yes |
tool_begin
The model named a tool and is still writing its arguments.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
id | string | yes | |
tool | string | yes | |
label | string | yes | |
detail | string | ||
target | string |
tool_start
A tool call started.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
id | string | yes | |
tool | string | yes | |
label | string | yes | |
detail | string | ||
target | string |
tool_output
Streamed output of a running tool.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
id | string | yes | |
text | string | yes | |
tool | string |
tool_complete
A tool call finished; ok says whether it worked and summary is what it reported.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
id | string | yes | |
tool | string | yes | |
label | string | ||
ok | boolean | yes | |
summary | string | yes |
file_change
A file in the project changed.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
path | string | yes | |
diff | string |
todos
The turn's task list changed.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
items | array | yes |
question
The turn is waiting. Read-only information for an API client: an approval card goes to the owner. The client may only deny (answer) or wait.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
question_id | string | yes | |
input_type | choice | text | picker | ||
question | string | yes | |
options | array | yes | |
tool | string | ||
args | object | ||
risk | read | mutate | consequential | ||
hint | string |
question_resolved
An open question was answered or denied (by the owner, by this client's deny, or by the wait running out); stop showing it.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
question_id | string | yes |
usage
Token counts and speed of a model pass.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
prompt_tokens | integer | yes | |
cached_tokens | integer | ||
output_tokens | integer | yes | |
tok_s | number | ||
context_pct | number | ||
model | string |
warning
Something the owner or developer should know.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
text | string | yes |
brain
The model answering the rest of the turn changed, and why.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
model | string | yes | |
name | string | yes | |
why | string | yes | |
escalated | boolean | yes |
receipts
Sources behind the final answer.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
items | array | yes | |
unsourced | boolean | yes |
task_complete
The turn is over. outcome is one of done, answered, blocked, failed, aborted. Always the last event.
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | string | yes | |
session_id | string | yes | |
request_id | string | yes | |
seq | integer (0..) | Counts events within the turn, from 0. | |
ts | number | yes | |
epoch | string | Identifies this core run; it changes if the core restarts. | |
session_seq | integer | Position of the event in the session's replay buffer. | |
outcome | done | answered | blocked | failed | aborted | yes | |
text | string | yes | |
result | object | A structured form of the outcome (state, answer, summary), when the core provides one. |
info
Reply to a socket command (sessions, history_*, status, ...).
| field | type | required | meaning |
|---|---|---|---|
protocol | "olix.codeui/1" | yes | |
type | "info" | yes | |
command | string | yes | |
request_id | string | ||
result | any |
error
A request failed. code is one of the error codes; the stream or socket stays usable unless code is unauthorized.
| field | type | required | meaning |
|---|---|---|---|
type | "error" | yes | |
code | string | yes | |
message | string | yes | |
request_id | string |
The NDJSON socket
The same API as NDJSON on a mode-0600 unix socket, for local tools that prefer it. The first line must be {"type":"auth","token":"..."}; then each line is one of the client messages below and replies are NDJSON events carrying the same request_id. Socket path: ~/.olx/api/api.sock. The gateway must be running.
Messages the socket accepts:
authinputinterruptanswersessionshistory_listhistory_gethistory_searchstatussettings_schemaworkspace_changes
The events of a turn carry the request_id you sent with the input (letters, digits, . _ -, up to 64). Replies to commands are info messages with the same request_id; failures are error messages. Anything outside this list gets bad_request: the socket is not a door to the rest of the core.
auth
| field | type | required | meaning |
|---|---|---|---|
type | "auth" | yes | |
token | string (max 200 chars) | yes | |
request_id | string (max 128 chars) |
interrupt
| field | type | required | meaning |
|---|---|---|---|
type | "interrupt" | yes | |
request_id | string (max 128 chars) | yes |
answer
| field | type | required | meaning |
|---|---|---|---|
type | "answer" | yes | |
request_id | string (max 128 chars) | yes | The turn's request_id. |
question_id | string (max 200 chars) | yes | |
decision | "deny" | yes | |
reason | string (max 500 chars) |
Example
import json, os, socket, sys
s = socket.socket(socket.AF_UNIX); s.connect(sys.argv[1]); f = s.makefile("rw")
def send(o): f.write(json.dumps(o) + "\n"); f.flush()
send({"type": "auth", "token": os.environ["OLIX_API_TOKEN"]}); print(f.readline().strip())
send({"type": "input", "text": "Say hello in five words.", "cwd": sys.argv[2], "request_id": "r1"})
for line in f:
ev = json.loads(line)
if ev["type"] in ("accepted", "assistant_end", "task_complete"): print(line.strip())
if ev["type"] == "task_complete": break
{"protocol":"olix.codeui/1","type":"info","command":"auth","result":{"app":"sample-app","scopes":["chat","models"]}}
{"protocol":"olix.codeui/1","type":"accepted","request_id":"r1","session_id":"20261106132216-883a92"}
{"text":"stand-in reply to: Say hello in five words.","protocol":"olix.codeui/1","type":"assistant_end","session_id":"20261106132216-883a92","request_id":"r1","seq":3,"ts":1793971336.587,"epoch":"c2d867b0-1dd2-4891-a4e2-3f5b281f25e0","session_seq":4}
{"outcome":"answered","text":"stand-in reply to: Say hello in five words.","result":{"state":"completed","answer":"stand-in reply to: Say hello in five words.","summary":"stand-in reply to: Say hello in five words."},"protocol":"olix.codeui/1","type":"task_complete","session_id":"20261106132216-883a92","request_id":"r1","seq":5,"ts":1793971336.641,"epoch":"c2d867b0-1dd2-4891-a4e2-3f5b281f25e0","session_seq":6}