CLI
The CLI channel turns your terminal into a Sona client. Two modes:
- REPL (default) — interactive prompt with JLine: arrow-history, slash commands, streaming token render.
- JSON — newline-delimited JSON on stdin/stdout, suitable for pipelines, e2e smoke tests, and shell automation.
The terminal has no pairing handshake — this machine is the authority. Telegram (and other messengers) still go through pairing when you add them.
REPL mode
sona chatThis starts an in-process gateway from your config and opens a JLine prompt; it does not connect to a running Sona daemon. The prompt shows the active workspace, and the reply streams in as it arrives:
default > what time is it in istanbul?
The current time in Istanbul is 03:14 UTC+3 (assuming standard time).
default > /exit
Goodbye.Built-in slash commands, handled by the REPL itself:
| Command | Effect |
|---|---|
/exit, /quit | Close the REPL and stop its in-process gateway. |
/clear | ANSI clear-screen. Arrow-key history is kept. |
/help | List the REPL commands. |
/workspace [name] | List the workspaces, or switch to one. |
/skill list | List the registered skills. |
/cost | Token usage and estimated spend for this REPL run. |
Any other line that starts with / is matched against the gateway's skill registry, and a matching skill runs in the REPL; with no match the REPL prints Unknown command. Try /help. Everything else goes straight to the workspace Agent. It does not take the gateway's message path, so the REPL does not use pairing, profile or memory prompt context, or saved sessions.
Workspace selection
By default sona chat uses the default workspace. To pick a specific one:
sona chat --workspace personalIf the workspace name doesn't match, the REPL prints Unknown workspace '<name>', falling back to default. and continues in the default workspace (or the first workspace by name when there is no default). --workspace only affects the REPL; in JSON mode the gateway picks the workspace by channel, as it does for every other channel.
Streaming
REPL mode prints each chunk of the LLM reply as it arrives and ends the turn with a newline. Tool calls appear as inline lines while the turn runs. The REPL renders the chunks itself; it does not go through a channel adapter.
The framework's StreamingChannelAdapter path applies to JSON mode only: the gateway forwards the reply through CliChannel.sendChunk(UnifiedChunk.text(...)) and closes it with one UnifiedChunk.done(...). See How It Works for the SPI surface.
JSON mode
sona chat --jsonJSON mode also starts an in-process gateway, but unlike the REPL it registers the framework's CliChannel with it, so every line takes the gateway's message path. The wire format is newline-delimited JSON in both directions. Useful for piping into Sona from another program, recording golden transcripts in tests, or driving Sona from a script without an interactive terminal.
Input
One JSON object per line, each with at least a text field:
{"text": "hi"}
{"text": "what time is it in istanbul?"}Other fields on the object are reserved for future use; today they're ignored.
Output
Streaming responses come back as a sequence of chunk records, terminated by a done: true envelope:
{"type":"chunk","content":"Hello","done":false}
{"type":"chunk","content":" ","done":false}
{"type":"chunk","content":"world","done":false}
{"type":"chunk","content":"","done":true}Pipeline-friendly consumers can stream the body by concatenating content fields until done: true; one-shot consumers can buffer until done then read the response in one go.
Errors come back as a single error record:
{"type":"error","message":"invalid JSON: Unexpected character (' ')..."}Sona writes one record per inbound message; a single sona chat --json invocation can handle multiple turns in the same conversation by keeping the process open and piping more text lines in.
Example: shell pipeline
printf '%s\n' \
'{"text":"hi"}' \
'{"text":"summarise the TnsAI framework in one paragraph"}' \
| sona chat --json \
| jq -r 'select(.type=="chunk") | .content' \
| tr -d '\n'This streams two turns through Sona, extracts the content chunks, and strips chunk-boundary newlines so you get the assistant's reply as flowing text.
Sessions
Only JSON mode saves session history. sona chat --json goes through the gateway as (channelId=cli, senderId=<your-username>), so later --json runs in the same workspace load that saved history into their session while the file is still on disk. That history is not replayed into the Agent's LLM memory; see How It Works. The gateway does add the sleep-time MEMORY.md and USER.md summaries for your scoped ID to each turn's prompt. The interactive REPL calls the Agent directly and saves no session history.
Session files are named by the URL-safe Base64 of the workspace and scoped ID, so there is no readable per-user filename. To start over, stop the daemon first (sona stop), because a running daemon saves its open sessions again after the next turn. Then remove the saved sessions (this clears every session on the machine, and it does not clear the sleep-time summaries under ~/.sona/memory/):
rm ~/.sona/sessions/*.jsonA /new slash command is tracked as a future improvement.
When to use which mode
| Use case | Mode |
|---|---|
| Quick interactive question | REPL |
| Pair-programming with Sona, multi-turn | REPL |
Shell pipeline / xargs over a CSV | JSON |
| E2E test that asserts response shape | JSON |
| Recording a golden transcript for a regression suite | JSON |
| Driving Sona from another program (Python script, Node, …) | JSON |
JSON mode never prints prompts, banners, ANSI colour, or anything other than JSON records — safe to pipe.
Comparison to Telegram
| Telegram | CLI | |
|---|---|---|
| Auth | Pairing code + owner approval | Local user (no handshake) |
| Streaming | No (the reply is sent once the turn completes) | Yes (REPL renders chunks itself) / Yes (JSON, per-chunk records) |
| Media | Photos, documents, voice (inbound) | No |
| Threads | Yes (per-chat threading) | REPL: no saved session. JSON: one session per workspace and lowercased user.name |
| Use case | Phone / off-machine | Local dev, CI smoke tests, scripts |
| Latency | Network round-trip via Telegram servers | Direct stdin/stdout |
The two adapters are independent. You can run both at the same time — they're separate sessions even for "the same" person.