Skip to content

Commit e7a7601

Browse files
committed
update docs for temrinal
1 parent c3c11e1 commit e7a7601

2 files changed

Lines changed: 82 additions & 20 deletions

File tree

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
---
22
title: "Terminal"
3-
description: "Read messages from stdin, write responses to stdout"
3+
description: "A full chat TUI for developing and testing agents locally"
44
---
55

66
```ts
77
import { terminal } from "spectrum-ts/providers/terminal";
88
```
99

10-
The terminal provider reads from `stdin` and writes to `stdout`. Each line of input becomes a message; text content sent into the terminal space is printed to the console.
10+
The terminal provider gives your agent a real chat interface in the terminal — multiple conversations in a sidebar, typing indicators, reactions, threaded replies, file attachments, and inline image rendering — all wired through the same Spectrum APIs you'd use against iMessage or WhatsApp Business.
1111

12-
```ts
13-
terminal.config();
14-
```
12+
<Frame>
13+
<img src="https://framerusercontent.com/images/AMLYOPHgKunMxQPxUzQUFUTkvHM.png?width=2400&height=1260" alt="Terminal UI showing a chat sidebar with multiple conversations, message thread, and typing indicator" />
14+
</Frame>
15+
16+
It's a drop-in test harness: write your agent against the unified `app.messages` stream, and develop everything end-to-end without provisioning a phone number or pairing a device.
1517

16-
No credentials, no config. Useful for local development, integration tests, and REPL-style bots.
18+
## How it works
1719

18-
## Example
20+
`terminal.config()` spawns the standalone [tuichat](https://github.com/photon-hq/tuichat) binary as a subprocess and drives it over JSON-RPC. The binary auto-downloads from GitHub Releases the first time you run it. In a TTY it boots the rich UI; in a non-TTY context (CI, piped input) it falls back to a synchronous readline loop, so the same agent code works for scripted integration tests.
1921

2022
```ts
2123
import { Spectrum } from "spectrum-ts";
@@ -27,25 +29,86 @@ const app = await Spectrum({
2729

2830
for await (const [space, message] of app.messages) {
2931
if (message.content.type === "text") {
30-
await space.send(`You said: ${message.content.text}`);
32+
await space.send(`echo: ${message.content.text}`);
3133
}
3234
}
3335
```
3436

35-
Each line you type is a message; each reply prints to the same terminal.
37+
No credentials, no config — just import and run.
3638

37-
## Behaviour
39+
## What you get
3840

39-
| Feature | Behaviour |
41+
Input and output are decoupled, so you can type while the agent is responding and the agent can push messages whenever it wants.
42+
43+
| Feature | How |
4044
|---|---|
41-
| `space.send(text)` | Prints to `stdout`. |
42-
| `space.send(attachment)` | No-op — the terminal can't render files. |
43-
| `space.startTyping` / `stopTyping` | No-op. |
44-
| `message.react` / `reply` | No-op (provider declares no `reactToMessage` / `replyToMessage` actions). |
45-
| `terminal(app).space(...)` | Always resolves to a single space with `id: "terminal"`. |
45+
| Multiple chats | `Ctrl+N` opens a new chat, `Ctrl+J` / `Ctrl+K` switch between them. Each chat is its own Spectrum space. |
46+
| Reactions | Press `r` on a message to react. Arrives in your code as a `reaction` content message. |
47+
| Replies | Press `e` to reply inline. Arrives with a `replyTo: { messageId }` extra on the message. |
48+
| File attachments | Drag-and-drop into the terminal — messages arrive with name, MIME type, and buffer. |
49+
| Inline images | Rendered with the Kitty graphics protocol when supported, with a half-block fallback. |
50+
| Typing indicators | `space.startTyping()` / `space.stopTyping()` show a live indicator. |
51+
| Console capture | `console.log` / `info` / `warn` / `error` / `debug` from your agent are forwarded into a pinned `__system__` chat instead of garbling the UI. |
52+
53+
## Config
54+
55+
```ts
56+
terminal.config({
57+
commands: [
58+
{ name: "/clear", description: "Clear conversation memory" },
59+
{ name: "/whoami", description: "Print sender details" },
60+
],
61+
});
62+
```
63+
64+
| Option | Type | Default | Description |
65+
|---|---|---|---|
66+
| `commands` | `{ name: string; description?: string }[]` | `[]` | Slash commands surfaced in the TUI's command picker. Names must match `/^\/[A-Za-z0-9_-]+$/`. |
67+
68+
Slash commands arrive as regular text messages with the command string as the content — handle them in your `for await` loop the same way you'd handle any text.
69+
70+
## Working with multiple spaces
71+
72+
By default the TUI starts on `chat-1`; new chats opened with `Ctrl+N` get `chat-2`, `chat-3`, and so on. To open a named space programmatically, pass an `id`:
73+
74+
```ts
75+
import { terminal } from "spectrum-ts/providers/terminal";
76+
77+
const t = terminal(app);
78+
const debug = await t.space({ id: "debug" });
79+
await debug.send("agent online");
80+
```
81+
82+
Calling `space()` ensures the chat exists in the sidebar — useful for kicking off a conversation before any user input.
83+
84+
## Reactions and replies
85+
86+
Reactions ride the same `app.messages` stream as text — they arrive as a `reaction` content message:
87+
88+
```ts
89+
for await (const [space, message] of app.messages) {
90+
if (message.content.type === "reaction") {
91+
console.log(`${message.sender.id} reacted ${message.content.emoji}`);
92+
continue;
93+
}
94+
if (message.content.type === "text") {
95+
await message.react("👀");
96+
await space.send(`echo: ${message.content.text}`);
97+
}
98+
}
99+
```
100+
101+
Threaded replies arrive as a normal message with a `replyTo` field:
102+
103+
```ts
104+
const replyTo = (message as { replyTo?: { messageId: string } }).replyTo;
105+
if (replyTo) {
106+
await message.reply(`acknowledged your reply to ${replyTo.messageId}`);
107+
}
108+
```
46109

47110
## When to use it
48111

49-
- **Iterating on bot logic** without hitting a real messaging platform.
50-
- **Integration tests** — drive a `for await` loop with scripted stdin input and assert on stdout.
51-
- **CLI tools** that want the same handler shape as a multi-platform deployment.
112+
- **Iterating on agent logic** — every Spectrum API works exactly as it would in production, so behavior you build here ships unchanged.
113+
- **Integration tests** — pipe stdin in non-TTY mode and assert on stdout; no TUI dependency for CI.
114+
- **CLI tools** same handler shape as any multi-platform deployment, with reactions and replies as first-class events.

docs.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
"pages": [
5858
"best-practices/architecture",
5959
"best-practices/inbound-pipeline",
60-
"best-practices/outbound-pacing",
6160
"best-practices/recovery-and-state"
6261
]
6362
}

0 commit comments

Comments
 (0)