WebSocket protocol

A single JSON protocol powers file tree, editor, terminal, git, and chat. The UI never assumes it runs on the same machine as the server.

Full spec on GitHub →

Message framing

Three message kinds, each one JSON object per text frame:

Requests (client → server)

{ "id": 1, "command": "read_file", "args": { "path": "/home/user/a.txt" } }

Replies (server → client)

{ "id": 1, "ok": true,  "result": { ... } }
{ "id": 1, "ok": false, "error": "File already exists" }
Commands run concurrently and replies may arrive out of order — match them by id. A malformed frame gets error: "invalid request: …"; an unknown command gets error: "unknown command: …".

Events (server → client)

EventPayloadNotes
pty-outputsession_id, dataRaw terminal bytes, ANSI escapes intact.
pty-exitsession_id, codecode is null when unknown.
chat-stream-chunkid, stream, textOne line per chunk from the agent CLI.
chat-stream-doneid, error?Terminates a chat stream.

Command reference

Terminal (PTY)

CommandArgsResult
pty_spawnsessionId, shell?, cwd?, cols?, rows?{ id, pid }
pty_writesessionId, data→ null
pty_resizesessionId, cols, rows→ null
pty_killsessionId→ null

Shell / misc

CommandArgsResult
run_commandcommandcombined stdout+stderr string
get_cwd—working directory string
chat_check_installcommand (agent id)boolean

File system

CommandArgsResult
read_filepathfile text
read_file_base64pathbase64 string (images etc.)
write_filepath, content→ null
upload_filepath, content (base64)→ null
download_filepathbase64 string
read_directorypath, maxDepth?FileNode[]
list_filespathstring[] recursive relative paths
file_existspathboolean
create_filepath, content?→ null
create_directorypath→ null
rename_entryfrom, to→ null
copy_entryfrom, to→ null
delete_entrypath→ null
extract_zipzipContent (base64), destDirstring[] extracted paths
search_in_filespath, query, caseSensitive?, wholeWord?, regex?SearchMatch[]

Git

All git commands take path (the repo dir) plus command-specific args.

CommandExtra argsResult
get_git_status—GitStatus
get_git_difffileunified diff string
get_git_staged_difffileunified diff string
get_git_head_filefilefile text at HEAD
git_show_indexfilefile text from the index
git_addfileoutput string
git_stage_all—output string
git_unstagefileoutput string
git_unstage_all—output string
git_discardfileoutput string
git_discard_all—output string
git_commitmessage, amend?output string
git_undo_commit—output string
git_loglimit?GitCommitInfo[]
git_commit_diffcommitunified diff string
git_stash_list—GitStashInfo[]
git_stash—output string
git_stash_pop—output string
git_push—output string
git_fetch—output string
git_pull—output string
git_revertcommitoutput string
git_init—output string
git_branch_list—GitBranches
git_checkout_branchname, create?output string
git_mergefromRefoutput string
git_merge_abort—output string
git_resolve_conflictfile, sideoutput string

Nio CLI chat

CommandArgsResult
chat_streamcommand, args?, cwd?, apiKey?, mode?, attachments?, requestId?fires chunk/done events; → null
chat_cancelid{ cancelled, reason? }
chat_modelsagent, apiKey?{ id, label }[]
chat_stream runs the Nio CLI with the selected model and context. The frontend subscribes to events before invoking so no early chunk is missed, matches chunks by requestId, and reconciles with chat-stream-done.