@robota-sdk/agent-cli 3.0.0-beta.82 → 3.0.0-beta.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2546 -0
- package/README.md +225 -1128
- package/dist/node/bin.js +33 -2
- package/dist/node/bounded-output-D3cgiOrh-C5ywb_Yg.js +2 -0
- package/dist/node/bounded-output-D3cgiOrh-C5ywb_Yg.js.map +1 -0
- package/dist/node/bounded-output-D3cgiOrh-kO7zrx1P.js +2 -0
- package/dist/node/cli-core-BloQpWhd.js +2891 -0
- package/dist/node/{command-executor-DV-H2oD6-BfKoGoFw.js → command-executor-BdE1zg3q-BGQmze1E.js} +1 -1
- package/dist/node/{command-executor-DV-H2oD6-OKy8pwYH.js → command-executor-BdE1zg3q-Br7z38P6.js} +2 -2
- package/dist/node/{command-executor-DV-H2oD6-OKy8pwYH.js.map → command-executor-BdE1zg3q-Br7z38P6.js.map} +1 -1
- package/dist/node/headless.js +2 -2
- package/dist/node/index.d.ts +358 -109
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +452 -328
- package/dist/node/index.js.map +1 -1
- package/dist/node/node-A7RJeEyA.js +14 -0
- package/dist/node/node-A7RJeEyA.js.map +1 -0
- package/dist/node/node-B_3rSS2i.js +67 -0
- package/dist/node/node-BhEYLQDQ.js +67 -0
- package/dist/node/node-BhEYLQDQ.js.map +1 -0
- package/dist/node/{node-bJ0lEuNF.js → node-C4_FOvnk.js} +2 -2
- package/dist/node/{node-bJ0lEuNF.js.map → node-C4_FOvnk.js.map} +1 -1
- package/dist/node/node-CCe6GM9V.js +14 -0
- package/dist/node/{node-2-nrieFn.js → node-DENLEmMT.js} +2 -2
- package/dist/node/{node-2-nrieFn.js.map → node-DENLEmMT.js.map} +1 -1
- package/dist/node/{node-cmTHiSYe.js → node-D_fk2mK2.js} +1 -1
- package/dist/web/assets/PretendardVariable.subset.0-BHUkWNFR.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.1-C-__qv6_.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.10-DzSWztS8.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.11-CqVmlKJn.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.12-BHuZSgT0.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.13-C42mj_j2.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.14-Bl512uUX.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.15-D04iXIE3.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.16-BQUnS2GX.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.17-BfZSA-Xc.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.18-CwAxMC3C.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.19-CJu4Zcdo.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.2-dCZkyKLw.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.20-Ig1-z3n5.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.21-yKPEdLXC.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.22-CSqxKoOs.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.23-DK80wi0t.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.24-CmkE8Q8D.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.25-CsoWBIZB.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.26-Sozl8dw8.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.27-CT6nuW9L.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.28-CpO0Y96p.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.29-D6hjrUWm.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.3-Dqw33sf4.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.30-CWDM1c0J.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.31-CdmyZ5mm.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.32-CGnFWD2i.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.33--0OT__YQ.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.34-CaCS33Md.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.35-DWFYRGLp.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.36-Dn5IBRQB.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.37-BD6FyOtY.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.38-D4hu443z.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.39-B_7wfth9.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.4-Bvh2YGoc.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.40-BDaOfdUe.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.41-BUACvzZC.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.42-Dp-5mnyL.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.43-DHdpry7N.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.44-qHopVhdd.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.45-BniyRFfm.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.46-BMRq7xC-.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.47-B-cWO2pw.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.48-Ct-fWrPO.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.49-BblQVys9.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.5-K_MNGNCe.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.50-C8IyFH7L.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.51-Bxd0gTAs.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.52-CNgqKOOJ.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.53-BSRnyb-u.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.54-Dt2-cQkx.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.55-jFgflYjX.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.56-BwZdvJZQ.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.57-BwFDg-Fs.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.58-DlucQts_.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.59-CMkWjhdo.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.6-Bxhohlcm.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.60-CeHezjjf.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.61-PUuTnod4.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.62-DGSAWCfb.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.63-B35xsm4O.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.64-CTbrgYF9.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.65-B66rjuyf.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.66-C3HqaDeY.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.67-BmuXdlDy.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.68-DS9B48d0.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.69-YT16ymcp.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.7-E2HaA55t.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.70-BUXiAGMT.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.71-DuPZj8us.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.72-pYYGrEQR.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.73-DMrK970F.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.74-D4tQnymK.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.75-CxKdrRNf.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.76-DhPm2b_q.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.77-DwaxqOC8.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.78-DhqRbBzT.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.79-XpoyPP38.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.8-CRbJhhyA.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.80-DsV9Qp_h.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.81-BZzF9Hb3.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.82-BgAHe30u.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.83-DF-zBLLe.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.84-Brb8EsYQ.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.85-Byo_x2hf.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.86-XG7lTN_6.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.87-Lzui2vbK.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.88-CqX6JSgh.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.89-DOzqWPpX.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.9-Btb3bmS6.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.90-BF7RiZjm.woff2 +0 -0
- package/dist/web/assets/PretendardVariable.subset.91-Csm0YNoH.woff2 +0 -0
- package/dist/web/assets/index-DSLs7oij.js +309 -0
- package/dist/web/assets/index-OqCBtMJ2.css +1 -0
- package/dist/web/index.html +6 -4
- package/package.json +43 -47
- package/dist/node/bounded-output-DpjpS98g-DFgAppgl.js +0 -2
- package/dist/node/bounded-output-DpjpS98g-DFgAppgl.js.map +0 -1
- package/dist/node/bounded-output-DpjpS98g-DoRuRGhV.js +0 -2
- package/dist/node/bounded-output-DpjpS98g-yPybHprY.cjs +0 -1
- package/dist/node/cli-core-DWG6gqoq.js +0 -2798
- package/dist/node/command-executor-DV-H2oD6-BAvcn7Tf.cjs +0 -1
- package/dist/node/http-executor-cWzI2svn-Nn7UFLl8.cjs +0 -1
- package/dist/node/index.cjs +0 -2796
- package/dist/node/index.d.cts +0 -3445
- package/dist/node/index.d.cts.map +0 -1
- package/dist/node/node-Bs1jlR4B.js +0 -67
- package/dist/node/node-CFTax5Wl.cjs +0 -1
- package/dist/node/node-CQqDd5KI.js +0 -14
- package/dist/node/node-CQqDd5KI.js.map +0 -1
- package/dist/node/node-D8uo8Kzf.cjs +0 -13
- package/dist/node/node-DE_LpiDk.cjs +0 -66
- package/dist/node/node-Du_7g6qW.js +0 -14
- package/dist/node/node-OBnZskvR.cjs +0 -1
- package/dist/node/node-hHzxDyjn.js +0 -67
- package/dist/node/node-hHzxDyjn.js.map +0 -1
- package/dist/node/rolldown-runtime-DK3Fl9T5-BIInC43l.cjs +0 -1
- package/dist/node/verdict-decoder-Dk_w2NG9-DNTeVdQ8.cjs +0 -1
- package/dist/web/assets/index-8_Slbxe7.css +0 -1
- package/dist/web/assets/index-Cgu5C1kn.js +0 -77
package/README.md
CHANGED
|
@@ -1,1243 +1,340 @@
|
|
|
1
1
|
**Language:** [English](README.md) | [한국어](docs/README-KO.md)
|
|
2
2
|
|
|
3
|
-
> **Beta software** — currently `3.0.0-beta`. APIs and behavior may change before stable release.
|
|
4
|
-
> Please [report issues](https://github.com/woojubb/robota/issues) to help us improve.
|
|
5
|
-
|
|
6
3
|
# @robota-sdk/agent-cli
|
|
7
4
|
|
|
8
|
-
AI coding assistant
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
| | Robota | Claude Code | Aider |
|
|
13
|
-
| ------------------------------------------------- | :----: | :---------: | :---: |
|
|
14
|
-
| Multi-provider (Anthropic, OpenAI, Gemini, Qwen…) | ✅ | ❌ | ✅ |
|
|
15
|
-
| Embed SDK in your own app | ✅ | ❌ | ❌ |
|
|
16
|
-
| Local models (LM Studio, Ollama via OpenAI API) | ✅ | ❌ | ✅ |
|
|
17
|
-
| Open source (AGPL-3.0) | ✅ | partial | ✅ |
|
|
18
|
-
| Claude Code config compatible (CLAUDE.md, modes) | ✅ | — | ❌ |
|
|
19
|
-
|
|
20
|
-
## Embed in Your App
|
|
5
|
+
`robota` is an AI coding assistant for the terminal, and the reference app of Robota — a collection
|
|
6
|
+
of TypeScript libraries for building AI agents. It reads your project, edits files and runs commands
|
|
7
|
+
under a permission system you control, and works with Anthropic, OpenAI, Gemini, DeepSeek, Qwen and
|
|
8
|
+
local OpenAI-compatible models.
|
|
21
9
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
The CLI is assembled from the same packages you can use in your own app: `@robota-sdk/agent-framework`
|
|
11
|
+
for the session, `@robota-sdk/agent-ui-terminal` for the terminal UI, and one package per model
|
|
12
|
+
provider. To build your own agent rather than use this one, start with the
|
|
13
|
+
[SDK guide](../../content/guide/sdk.md).
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
provider: createAnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY }),
|
|
29
|
-
// projectAccess: hostWorkspaceDecision,
|
|
30
|
-
});
|
|
31
|
-
const session = runtime.createSession({ permissionMode: 'bypassPermissions' });
|
|
32
|
-
|
|
33
|
-
// submit() is event-driven and resolves to void — drive output via listeners
|
|
34
|
-
session.on('text_delta', (delta) => process.stdout.write(delta));
|
|
35
|
-
session.on('complete', (result) => console.log(result.response));
|
|
36
|
-
|
|
37
|
-
await session.submit('Explain this codebase');
|
|
38
|
-
```
|
|
15
|
+
> **Beta.** Behavior may change before the stable release. Please
|
|
16
|
+
> [report issues](https://github.com/woojubb/robota/issues).
|
|
39
17
|
|
|
40
|
-
|
|
41
|
-
`TWorkspaceProjectAccess` decision the runtime is observably Restricted and does not load project
|
|
42
|
-
context, settings, memory, sessions, or logs. Embedders establish that decision through the
|
|
43
|
-
framework `WorkspaceTrustService`; a path, boolean, or generic filesystem cannot substitute for it.
|
|
44
|
-
Trusted composition is rejected when `cwd` resolves outside that authority's frozen workspace root.
|
|
45
|
-
|
|
46
|
-
## Prerequisites
|
|
47
|
-
|
|
48
|
-
Node.js **22 or higher** is required. The TUI renderer ([ink 7.x](https://github.com/vadimdemedes/ink)) requires Node.js 22+.
|
|
18
|
+

|
|
49
19
|
|
|
50
|
-
|
|
51
|
-
node --version # Must output v22.x.x or higher
|
|
52
|
-
```
|
|
20
|
+
## Install
|
|
53
21
|
|
|
54
|
-
|
|
22
|
+
Requires Node.js 22.12.0 or later.
|
|
55
23
|
|
|
56
24
|
```bash
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# Volta
|
|
61
|
-
volta install node@22
|
|
25
|
+
npm install -g @robota-sdk/agent-cli # installs the `robota` command
|
|
26
|
+
npx @robota-sdk/agent-cli # or run it once without installing
|
|
62
27
|
```
|
|
63
28
|
|
|
64
|
-
|
|
29
|
+
On macOS, Korean and other CJK input methods can crash inside Terminal.app; use a terminal such as
|
|
30
|
+
[iTerm2](https://iterm2.com/) instead.
|
|
65
31
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Recorded from the real CLI with `pnpm --filter @robota-sdk/agent-cli demo:record`. The tools run for
|
|
69
|
-
real; the model turns are replayed from a recorded session log so the recording needs no API key —
|
|
70
|
-
see [docs/DEMO-SCRIPT.md](./docs/DEMO-SCRIPT.md).
|
|
32
|
+
## First run
|
|
71
33
|
|
|
72
|
-
|
|
34
|
+
Run `robota` inside a Git repository. It first asks whether to trust the folder: only a trusted
|
|
35
|
+
workspace can load the project's own settings, hooks, skills, plugins and MCP servers. Answer no and
|
|
36
|
+
the session starts **Restricted**, with your user settings and the built-in tools only. The first
|
|
37
|
+
time, it then walks you through choosing a provider and filling in its fields (model, base URL, API
|
|
38
|
+
key), and saves the profile to `~/.robota/settings.json`.
|
|
73
39
|
|
|
74
40
|
```bash
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Install globally for persistent use
|
|
79
|
-
npm install -g @robota-sdk/agent-cli
|
|
41
|
+
cd my-project
|
|
42
|
+
robota
|
|
80
43
|
```
|
|
81
44
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
45
|
+
To set up without prompts (for example on a server), create the profile and trust the workspace
|
|
46
|
+
with flags. The profile stores a reference to the environment variable, not the key itself, and the
|
|
47
|
+
variable must be set when you run the command:
|
|
85
48
|
|
|
86
49
|
```bash
|
|
87
|
-
|
|
88
|
-
robota
|
|
89
|
-
|
|
50
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
51
|
+
robota --configure-provider anthropic --type anthropic --model claude-sonnet-4-6 \
|
|
52
|
+
--api-key-env ANTHROPIC_API_KEY --set-current
|
|
53
|
+
robota trust --yes
|
|
90
54
|
```
|
|
91
55
|
|
|
92
|
-
|
|
56
|
+
`robota init` writes a starter `AGENTS.md` and `.robota/settings.json` for the current project.
|
|
57
|
+
`robota --configure` reruns the interactive provider setup, and `robota --reset` deletes
|
|
58
|
+
`~/.robota/settings.json`.
|
|
93
59
|
|
|
94
|
-
|
|
95
|
-
| ------------------- | -------------------------------------------------------- | --------- |
|
|
96
|
-
| `ANTHROPIC_API_KEY` | Anthropic API key | Anthropic |
|
|
97
|
-
| `OPENAI_API_KEY` | OpenAI API key | OpenAI |
|
|
98
|
-
| `GEMINI_API_KEY` | Google Gemini API key | Gemini |
|
|
99
|
-
| `DEEPSEEK_API_KEY` | DeepSeek API key | DeepSeek |
|
|
100
|
-
| `DASHSCOPE_API_KEY` | Alibaba Cloud Model Studio key | Qwen |
|
|
101
|
-
| `BRAVE_API_KEY` | Brave Search API key (optional — enables WebSearch tool) | WebSearch |
|
|
60
|
+
## What you can do
|
|
102
61
|
|
|
103
|
-
|
|
62
|
+
### Work in the terminal UI
|
|
104
63
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
64
|
+
`robota` starts an interactive session. Type a request, or `/` to open the command menu (`/help`
|
|
65
|
+
lists every command). `Esc` stops the current response, `Ctrl+R` searches the prompts you have typed
|
|
66
|
+
before, and every key can be rebound in `~/.robota/keybindings.json` (see the
|
|
67
|
+
[keybindings guide](../../content/guide/keybindings.md)).
|
|
108
68
|
|
|
109
|
-
|
|
69
|
+
The agent works with file and shell tools (`Read`, `Write`, `Edit`, `Glob`, `Grep`, `Bash`),
|
|
70
|
+
`WebFetch`, `WebSearch` (needs a `BRAVE_API_KEY`) and `AskUserQuestion`, and can hand work to
|
|
71
|
+
subagents and background tasks. Your project's `AGENTS.md` and `CLAUDE.md` are loaded as context
|
|
72
|
+
in a trusted workspace, and `@path` in a prompt attaches a project file.
|
|
110
73
|
|
|
111
74
|
```bash
|
|
112
|
-
#
|
|
113
|
-
|
|
75
|
+
robota # new session
|
|
76
|
+
robota --permission-mode acceptEdits
|
|
77
|
+
robota --screen-reader # plain-text mode for screen readers
|
|
114
78
|
```
|
|
115
79
|
|
|
116
|
-
|
|
117
|
-
copies the web monitor (`agent-cli-web/dist`) into `dist/web`. To see the published tarball, run
|
|
118
|
-
`pnpm --filter @robota-sdk/agent-cli pack`.
|
|
119
|
-
|
|
120
|
-
Standalone Bun binaries are written to `dist-bun` (`pnpm --filter @robota-sdk/agent-cli build:bun`) and
|
|
121
|
-
`dist-bun-headless` (`build:bun:headless`). Native dependencies make these builds exact-host: each
|
|
122
|
-
supported Linux x64/arm64, macOS x64/arm64, or Windows x64 binary must be compiled on its matching host,
|
|
123
|
-
and a mismatched target is refused.
|
|
80
|
+
### Run one prompt from a script
|
|
124
81
|
|
|
125
|
-
|
|
82
|
+
Print mode (`-p`) runs a single prompt without the terminal UI and exits. With no prompt argument it
|
|
83
|
+
reads the prompt from piped stdin.
|
|
126
84
|
|
|
127
85
|
```bash
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# Production mode (requires build)
|
|
135
|
-
pnpm start
|
|
136
|
-
|
|
137
|
-
# With arguments
|
|
138
|
-
pnpm dev -- --version
|
|
139
|
-
pnpm dev -- --permission-mode plan
|
|
140
|
-
pnpm dev -- -p "List all TypeScript files in src/"
|
|
86
|
+
robota -p "List the TypeScript files in src/"
|
|
87
|
+
robota -p "Summarize this repository" --output-format json # one JSON object: result, session_id
|
|
88
|
+
cat task.md | robota -p # prompt from stdin
|
|
89
|
+
robota -p "Review this diff" --bare # without AGENTS.md, CLAUDE.md or plugins
|
|
90
|
+
robota --goal "make the failing tests pass" # work toward a goal over several turns
|
|
141
91
|
```
|
|
142
92
|
|
|
143
|
-
|
|
93
|
+
`--output-format` is `text` (default), `json` or `stream-json`. `--json-schema` asks for JSON matching
|
|
94
|
+
a schema, and `--system-prompt` / `--append-system-prompt` change the system prompt for the run. The
|
|
95
|
+
exit code is `0` on success and `1` on an error; `-p` exits `3` when no usable provider is
|
|
96
|
+
configured, and a `--goal` run that stops without reaching its goal exits `2`. In a Git repository
|
|
97
|
+
you have not trusted, print mode, `--goal`, `--serve`, `robota mcp serve`, `robota daemon start` and
|
|
98
|
+
`robota session start` refuse to start; with `--safe-mode` the first four run Restricted instead, and
|
|
99
|
+
`robota daemon start --restricted-workspace` starts the daemon Restricted.
|
|
144
100
|
|
|
145
|
-
|
|
146
|
-
robota # Interactive REPL (default mode)
|
|
147
|
-
robota "prompt" # REPL with initial prompt
|
|
148
|
-
robota -p "prompt" # Print mode (one-shot, exit after response)
|
|
149
|
-
robota -c # Continue last session
|
|
150
|
-
robota -r <session-id> # Resume session by ID
|
|
151
|
-
robota --language <lang> # Response language (ko, en, ja, zh)
|
|
152
|
-
robota --permission-mode <mode> # plan | default | acceptEdits | bypassPermissions
|
|
153
|
-
robota --max-turns <n> # Limit agentic turns per interaction
|
|
154
|
-
robota --goal "<objective>" # Pursue an autonomous goal headlessly until satisfied or a bound
|
|
155
|
-
robota --goal-max-iterations <n> # Per-goal turn budget (default 25)
|
|
156
|
-
robota --output-format <fmt> # text | json | stream-json (print mode)
|
|
157
|
-
robota --effort <level> # auto | none | minimal | low | medium | high | xhigh | max
|
|
158
|
-
robota --system-prompt <text> # Replace system prompt (print mode)
|
|
159
|
-
robota --append-system-prompt <text> # Append to system prompt (print mode)
|
|
160
|
-
robota --model claude-sonnet-4-6 # Override provider model for this session
|
|
161
|
-
robota --allowed-tools "Bash,Read" # Whitelist specific tools
|
|
162
|
-
robota --denied-tools "Bash,Write" # Blacklist specific tools (denied > allowed)
|
|
163
|
-
robota --screen-reader # Screen-reader mode: no chrome, no motion, numbered menus, role labels
|
|
164
|
-
robota --no-screen-reader # Force it off for this run, whatever the env or settings say
|
|
165
|
-
# Pacing (ms): ROBOTA_SCREEN_READER_STARTUP_QUIET_MS=900 ROBOTA_SCREEN_READER_PREPARK_MS=50 (0 disables either)
|
|
166
|
-
robota --serve # Run as a headless runtime host over a loopback WS sidecar (used by the desktop GUI)
|
|
167
|
-
robota mcp serve # Serve one session to a local MCP client over stdio
|
|
168
|
-
robota mcp serve --http-token-file /absolute/private/path/mcp-token --http-port 8765
|
|
169
|
-
# Serve Streamable HTTP on 127.0.0.1; the token file must not exist
|
|
170
|
-
robota mcp serve --http-public-url https://agents.example.com/robota/mcp --oauth-issuer https://auth.example.com \
|
|
171
|
-
--oauth-scopes mcp:use --oauth-allowed-subjects alice@example.com
|
|
172
|
-
# Serve remote HTTP behind a proxy, admitting OAuth access tokens
|
|
173
|
-
robota trust status # Inspect canonical workspace trust
|
|
174
|
-
robota trust --yes # Grant trust for the current Git workspace
|
|
175
|
-
robota trust revoke --yes # Revoke the current workspace grant
|
|
176
|
-
robota usage # Show the last 7 days of personal usage from local session history
|
|
177
|
-
robota usage --period 30d # Show complete buckets for the last 30 calendar days
|
|
178
|
-
robota usage --timezone UTC --format json # Emit the versioned JSON projection
|
|
179
|
-
robota usage export --endpoint http://127.0.0.1:4318 # Send stored-usage Gauges to a loopback OTLP collector
|
|
180
|
-
robota usage export --signal traces --endpoint http://127.0.0.1:4318 # Send recorded prompt/provider/tool spans
|
|
181
|
-
robota usage export --signal logs --endpoint http://127.0.0.1:4318 # Send content-free completion events
|
|
182
|
-
robota --safe-mode # Every customization off, to rule one out
|
|
183
|
-
robota --reset # Delete user settings and exit
|
|
184
|
-
robota --check-update # Check npm for a newer CLI version and exit
|
|
185
|
-
robota --disable-update-check # Skip interactive startup update check for this run
|
|
186
|
-
robota --version # Show version
|
|
187
|
-
robota --reduced-motion # Suppress animation for this run (colour is unaffected)
|
|
188
|
-
robota --no-reduced-motion # Allow animation, overriding a persisted reducedMotion
|
|
189
|
-
```
|
|
101
|
+
### Keep sessions, run them in the background, share a daemon
|
|
190
102
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
`robota usage` reads local user and trusted-project session stores without starting a provider or
|
|
194
|
-
requiring network access. It reports sessions, started turns, tokens, cost confidence, model/provider/
|
|
195
|
-
surface/source breakdowns, privacy-safe activity counts, and coverage diagnostics. The project copy
|
|
196
|
-
wins when the same session ID exists in both stores. Stored prompts, responses, paths, and tool
|
|
197
|
-
payloads are never printed.
|
|
198
|
-
|
|
199
|
-
Use `--period 7d` (the default) or `--period 30d`, choose an IANA timezone with `--timezone`, and use
|
|
200
|
-
`--format json` for the external `schemaVersion: 1` projection. An empty store produces an empty
|
|
201
|
-
report; a supplied store set containing no readable records exits with an error instead of silently
|
|
202
|
-
reporting zero usage.
|
|
203
|
-
|
|
204
|
-
`robota usage export` is a separate, explicit, one-shot network action over OTLP/HTTP JSON to a
|
|
205
|
-
loopback collector (`127.0.0.1` or `[::1]`) only. The default `metrics` signal sends a current
|
|
206
|
-
**Gauge snapshot** of stored session/turn counts, tokens, estimated known USD cost, and unknown-cost
|
|
207
|
-
counts to `/v1/metrics`. Repeated exports are snapshots, not new usage to add together. Select
|
|
208
|
-
`--signal traces` to send recorded prompt-root, provider-call, and tool spans to `/v1/traces`, or
|
|
209
|
-
`--signal logs` to send recorded content-free completion events to `/v1/logs`. Repeating a logs export
|
|
210
|
-
can resend the same events; a collector may retain duplicates. These signals use stored records;
|
|
211
|
-
they are not live tracing, and legacy records may lack span/event coverage. No signal
|
|
212
|
-
exports prompt or tool bodies, credentials, or a remote destination. An unreadable stored session,
|
|
213
|
-
collector rejection, or network error fails the command without reporting success.
|
|
214
|
-
|
|
215
|
-
Live prompt telemetry is a separate, opt-in Node CLI feature (interactive, print, serve, and MCP serve). Set
|
|
216
|
-
`ROBOTA_TELEMETRY_ENABLED=1`, `ROBOTA_TELEMETRY_TRACES=otlp`,
|
|
217
|
-
`ROBOTA_TELEMETRY_OTLP_PROTOCOL=http/protobuf`, and
|
|
218
|
-
`ROBOTA_TELEMETRY_OTLP_ENDPOINT=https://collector.example` to send content-free prompt/provider/tool
|
|
219
|
-
spans to the base URL's `/v1/traces`. `ROBOTA_TELEMETRY_OTLP_TRACES_ENDPOINT` overrides the base with
|
|
220
|
-
an exact traces URL. Select `ROBOTA_TELEMETRY_METRICS=otlp` independently to send per-invoked-call
|
|
221
|
-
delta counts, complete-usage token totals and price-table-estimated USD cost, plus observed prompt and
|
|
222
|
-
tool-completion counts, to `/v1/metrics`;
|
|
223
|
-
`ROBOTA_TELEMETRY_OTLP_METRICS_ENDPOINT` overrides that destination. Missing usage or prices are
|
|
224
|
-
counted separately, never treated as zero cost. A truncated provider-event batch reports omissions
|
|
225
|
-
and does not claim a complete usage/cost total. Metric datapoints omit session, turn, provider and
|
|
226
|
-
model labels by default; set `ROBOTA_TELEMETRY_METRIC_ATTRIBUTES` to a comma list drawn from
|
|
227
|
-
`session`, `provider` and `model` (canonical lower case, no duplicates) to add them, and only when
|
|
228
|
-
metrics export over `otlp` or `console` — the setting is refused otherwise, and startup is refused
|
|
229
|
-
for any token that is not exactly one of the three. `session` adds `robota.session.id` (the same key
|
|
230
|
-
the trace spans use) to every metric datapoint of the batch. `provider`/`model` add
|
|
231
|
-
`robota.provider.id`/`robota.model.id` only to provider-derived metrics (calls, tokens, cost, and the
|
|
232
|
-
unpriced/usage-unavailable counts), splitting them into one datapoint per distinct id (or pair); a
|
|
233
|
-
call with no id gets its own datapoint without that attribute. In `--serve`/`robota mcp serve`, how
|
|
234
|
-
many distinct session ids appear is set by the connecting clients, not by the CLI; provider and model
|
|
235
|
-
values come from whatever the host's provider configuration reports, not from a fixed catalog. Select
|
|
236
|
-
`ROBOTA_TELEMETRY_LOGS=otlp` independently for content-free
|
|
237
|
-
prompt/provider/tool completion events, plus a tool's own permission decision (allowed, denied, or
|
|
238
|
-
hook-blocked), at `/v1/logs`; `ROBOTA_TELEMETRY_OTLP_LOGS_ENDPOINT`
|
|
239
|
-
overrides that destination. Tool spans and logs carry a validated opaque call ID when available, and an
|
|
240
|
-
invoked provider-call span and its completion log carry the provider's own request ID the same way when
|
|
241
|
-
the adapter attested one; metric datapoints never use either as a label, though a permission-decision
|
|
242
|
-
count by decision value is still reported on `/v1/metrics`. A permission decision has no duration of
|
|
243
|
-
its own and never produces a trace span. Only confirmed invocations produce provider-completion events;
|
|
244
|
-
omitted child counts remain visible on the prompt event. Plain HTTP is allowed only for loopback; URL credentials and query parameters
|
|
245
|
-
are rejected. Export is bounded, best-effort, and does not delay or fail a turn; delivery failures
|
|
246
|
-
produce a content-free stderr warning. These switches do not enable content capture,
|
|
247
|
-
additional event kinds, or replay of stored traces. Ambient `OTEL_*` values alone do not enable them.
|
|
248
|
-
|
|
249
|
-
Prompt, response and tool content is a separate opt-in on top of `ROBOTA_TELEMETRY_LOGS=otlp`.
|
|
250
|
-
`ROBOTA_TELEMETRY_LOG_USER_PROMPTS=1` sends what you typed (never the expanded model input, such as
|
|
251
|
-
`@file` contents), and `ROBOTA_TELEMETRY_LOG_ASSISTANT_RESPONSES=1` sends the assistant's final answer
|
|
252
|
-
for the turn. `ROBOTA_TELEMETRY_LOG_TOOL_ARGUMENTS=1` sends the arguments of the turn's tool calls,
|
|
253
|
-
allowed or denied, and `ROBOTA_TELEMETRY_LOG_TOOL_OUTPUT=1` sends the output of its allowed calls
|
|
254
|
-
(empty for a tool that crashed). Tool arguments carry whatever the model passed: a `Write` or `Edit`
|
|
255
|
-
call's arguments are the file content it writes. Each setting accepts exactly `0` or `1`.
|
|
256
|
-
`ROBOTA_TELEMETRY_LOG_CONTENT_MAX_BYTES` bounds each item (an integer from 256 to 16384, default 2048)
|
|
257
|
-
and is refused unless one of them is `1`. Content is captured only in the interactive terminal and
|
|
258
|
-
only for turns you type yourself, the same turns prompt history records: goal and loop wakeups, peer
|
|
259
|
-
and external messages, remote co-drivers, subagents and background work are never captured, and
|
|
260
|
-
tool content covers only the calls that turn made itself — never a subagent's, a forked skill's or
|
|
261
|
-
background work's, even through a tool they share. A hook-blocked call, an unknown tool, or a call
|
|
262
|
-
stopped before its tool ran sends nothing. Print (`-p`, `--goal`), `--serve` and
|
|
263
|
-
`robota mcp serve` refuse to start with a content setting at `1` rather than ignore it. It goes only to OTLP log records (`robota.content.captured`, joined to the prompt's trace and
|
|
264
|
-
root span, with `robota.content.kind`, `robota.content.truncated`, `robota.content.original_bytes` and,
|
|
265
|
-
for an interrupted turn's response, `robota.content.partial`) — never to spans, metrics or console
|
|
266
|
-
output, so a content setting with `ROBOTA_TELEMETRY_LOGS=console` is refused. A tool item is joined to
|
|
267
|
-
the call's tool span when the trace kept one (else the root span) and adds `robota.tool.call_id`,
|
|
268
|
-
`robota.tool.name` and `robota.tool.outcome` (`success`, `failure` or `denied`). Arguments are
|
|
269
|
-
rendered with values under secret-looking keys (`password`, `apiKey`, `accessTokens`, …) masked
|
|
270
|
-
whole, and binary or base64 payloads replaced by their size. It is sent to the logs
|
|
271
|
-
destination with its headers but in its own requests and queue: a content failure never delays or
|
|
272
|
-
drops the content-free logs, and is reported on stderr like any other delivery failure. One turn's
|
|
273
|
-
content is bounded in item count and total size, with room kept for the prompt and response, and is
|
|
274
|
-
sent as a few requests of bounded size; what does not fit is dropped and counted by kind in a
|
|
275
|
-
content-free `robota.content.omitted` record, sent last. When a request fails, the rest of that turn's
|
|
276
|
-
content and every queued turn are dropped, so that count is lost too. Queued content can hold about
|
|
277
|
-
12 MB in the worst case. Before sending, the CLI masks known credential shapes (vendor API keys, AWS keys, private-key blocks,
|
|
278
|
-
JWTs, GitHub, Stripe, npm and GitLab tokens, bearer tokens, URL and `-u user:pass` credentials,
|
|
279
|
-
`*_KEY`/`*_TOKEN`/`*_SECRET`/`*_PASSWORD=` values, JSON values whose name looks secret, and
|
|
280
|
-
`Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie` and `X-…-Token`/`-Key`/`-Secret`/`-Auth`
|
|
281
|
-
header lines, including indented ones and the `> ` lines `curl -v` prints), the literal secrets it knows of (settings keys and
|
|
282
|
-
`env` values, every resolved provider key including one switched to mid-session, and collector header
|
|
283
|
-
values), your workspace path (`<workspace>`, also inside `file://` URLs) and home directory (`~`),
|
|
284
|
-
control characters, and a partial token left at the size cut. This
|
|
285
|
-
masking is best effort: anything it does not recognise as a secret is sent as written — file
|
|
286
|
-
contents, command output and a response that repeats them included. If the secrets cannot be
|
|
287
|
-
read, that request carries no content at all.
|
|
288
|
-
|
|
289
|
-
Static collector headers (for example an `Authorization` token) use
|
|
290
|
-
`ROBOTA_TELEMETRY_OTLP_HEADERS` for the generic endpoint and `ROBOTA_TELEMETRY_OTLP_TRACES_HEADERS`,
|
|
291
|
-
`ROBOTA_TELEMETRY_OTLP_METRICS_HEADERS` or `ROBOTA_TELEMETRY_OTLP_LOGS_HEADERS` for one signal, in
|
|
292
|
-
OpenTelemetry's `name=value,name2=value2` form with percent-encoded values
|
|
293
|
-
(`Authorization=Bearer%20abc123`). Headers are scoped to their destination: a signal that uses
|
|
294
|
-
`ROBOTA_TELEMETRY_OTLP_ENDPOINT` sends the generic headers merged with its own, its own winning on the
|
|
295
|
-
same name, while a signal with its own `ROBOTA_TELEMETRY_OTLP_<SIGNAL>_ENDPOINT` sends only its own
|
|
296
|
-
headers. Unlike OpenTelemetry, generic headers are never sent to a per-signal endpoint. Startup is
|
|
297
|
-
refused for malformed entries, empty names or values, duplicate names, reserved transport,
|
|
298
|
-
content-negotiation, proxy, `sec-` or trace-propagation names, control characters other than tab, non-ASCII characters,
|
|
299
|
-
oversized settings, headers no OTLP signal would send, and a per-signal endpoint without its own
|
|
300
|
-
headers while another signal sends the generic ones. Header helpers and refresh are not supported.
|
|
301
|
-
Console output, logs and resource attributes never contain headers, and errors name only the setting
|
|
302
|
-
and entry position. The CLI removes every `ROBOTA_TELEMETRY_*` setting from its environment at
|
|
303
|
-
startup, so shells, hooks, subagents and other child processes do not inherit them; the only
|
|
304
|
-
handover is the supervised runtime that `session start` or `session view` launches, which receives
|
|
305
|
-
them in its spawn environment. While telemetry is enabled, any other `ROBOTA_TELEMETRY_*` setting
|
|
306
|
-
(for example client certificates, a locked destination or other content capture) stops startup with an
|
|
307
|
-
error that names the setting but never prints its value, rather than exporting without it.
|
|
308
|
-
Each signal also accepts `console` instead of `otlp` to write a content-free JSON diagnostic to stderr;
|
|
309
|
-
console needs neither an endpoint nor a protocol and never includes collector credentials. Signals
|
|
310
|
-
remain independent, and the Robota enable switch is still required.
|
|
311
|
-
All enabled signals use the same per-process `service.instance.id` and the CLI's version and
|
|
312
|
-
presentation mode as resource attributes. Ambient `OTEL_SERVICE_NAME` and other `OTEL_*` values
|
|
313
|
-
cannot replace these fields.
|
|
314
|
-
|
|
315
|
-
Trace context propagation is a further opt-in. `ROBOTA_TELEMETRY_PROPAGATE_TO` is a comma list of
|
|
316
|
-
exact origins (`https://api.anthropic.com,https://gateway.example.com:8443`) that may receive a
|
|
317
|
-
W3C `traceparent` on provider requests: `00-<prompt trace id>-<provider-call span id>-01`, where the
|
|
318
|
-
span ID is the one the exported `robota.provider_call` span carries. The same list covers MCP servers
|
|
319
|
-
reached over Streamable HTTP: a tool call to a server whose URL has a listed origin carries
|
|
320
|
-
`00-<prompt trace id>-<tool span id>-01`, where the span ID is the one the exported tool span
|
|
321
|
-
carries. Only the `tools/call` request and its cancellation carry it — never initialization,
|
|
322
|
-
listing, list refreshes, notifications or the server's event stream — and stdio MCP servers receive
|
|
323
|
-
nothing. It needs
|
|
324
|
-
`ROBOTA_TELEMETRY_ENABLED=1` and `ROBOTA_TELEMETRY_TRACES=otlp` or `console`, and is inert while
|
|
325
|
-
telemetry is off. Each entry must be exactly its own origin: `https`, or `http` only on loopback, with no
|
|
326
|
-
path, trailing slash, query, credentials, wildcard or spelled-out default port; a scheme, port or
|
|
327
|
-
subdomain difference is a different origin and gets nothing. An internationalized host must be listed
|
|
328
|
-
in its punycode (`xn--`) form, and an origin with a trailing dot never matches; both fail closed
|
|
329
|
-
(refused at startup or sent nothing). Malformed, duplicate or too many entries
|
|
330
|
-
stop startup with an error that names only the setting and entry position. `tracestate` and `baggage`
|
|
331
|
-
are never sent, the collector's origin is never trusted implicitly, and collector headers are never
|
|
332
|
-
reused for provider requests. The Anthropic and OpenAI (Responses and Chat Completions) adapters
|
|
333
|
-
propagate to their client's effective base URL, as do the OpenAI-compatible DeepSeek, Qwen (both its
|
|
334
|
-
Chat Completions and Responses surfaces), and Gemma adapters, and Gemini propagates to
|
|
335
|
-
`https://generativelanguage.googleapis.com` only — not with `GOOGLE_GEMINI_BASE_URL`,
|
|
336
|
-
`GOOGLE_VERTEX_BASE_URL` or Vertex mode. Nothing is sent through a provider executor. When
|
|
337
|
-
propagation is configured but the round's provider cannot propagate — an executor, or a client
|
|
338
|
-
whose base URL cannot be read — the CLI writes one stderr line per provider naming only that
|
|
339
|
-
provider. Only a prompt's own provider calls carry it: subagents, workers and background
|
|
340
|
-
tasks do not inherit it.
|
|
341
|
-
|
|
342
|
-
Listing a vendor's origin lets that vendor link its own request logs to your trace ID. A redirect
|
|
343
|
-
followed by the SDK carries the header to the redirect target. A provider call whose span was omitted or
|
|
344
|
-
dropped from export still sent its `traceparent`, so the vendor's parent span may be missing from your
|
|
345
|
-
trace; `robota.omitted.provider_count` on the prompt span shows when that happened. Ambient
|
|
346
|
-
`TRACEPARENT` and `OTEL_*` values are never adopted.
|
|
347
|
-
|
|
348
|
-
`ROBOTA_TELEMETRY_PROPAGATE_TO_SUBPROCESSES` hands the prompt's trace to child processes through the
|
|
349
|
-
`TRACEPARENT` environment variable. It is a comma list drawn from exactly `shell` and `hooks`, each at
|
|
350
|
-
most once; it needs the same `ROBOTA_TELEMETRY_ENABLED=1` and exported traces, is inert while
|
|
351
|
-
telemetry is off, works with or without `ROBOTA_TELEMETRY_PROPAGATE_TO`, and a malformed entry stops
|
|
352
|
-
startup naming only the setting and entry position. With `shell`, each foreground `Bash`/`Shell`
|
|
353
|
-
command runs with `00-<prompt trace id>-<tool span id>-01`, where the span ID is the one that call's
|
|
354
|
-
exported tool span carries. With `hooks`, command hooks fired during a prompt — `UserPromptSubmit`,
|
|
355
|
-
`PreToolUse`, `PostToolUse`, `PermissionDecision`, the model-call hooks, `Stop`, `StopFailure` and
|
|
356
|
-
the `PreCompact` and `PostCompact` of an automatic compaction — run with `00-<prompt trace id>-<prompt span id>-01`, so
|
|
357
|
-
their spans sit beside the provider and tool spans; a hook fired outside a prompt (`SessionStart`,
|
|
358
|
-
`SessionEnd`, both hooks of `/compact`, background tasks, subagent worktrees) gets nothing. The value
|
|
359
|
-
is only ever in the child's environment, never in a hook's stdin JSON. A `TRACEPARENT` that a hook
|
|
360
|
-
group's own `env` sets wins, and the child then sees its environment unchanged; otherwise the ambient
|
|
361
|
-
`TRACESTATE` is removed, because it belonged to a different parent. The `!` shell passthrough,
|
|
362
|
-
background, managed and scheduled shells, the monitor UI launcher, a sandboxed shell, stdio MCP
|
|
363
|
-
servers, and HTTP, prompt and agent hooks never receive it. Robota never modifies its own process
|
|
364
|
-
environment, so while the setting is off every child sees exactly the ambient `TRACEPARENT` and
|
|
365
|
-
`TRACESTATE` it would have seen anyway.
|
|
366
|
-
|
|
367
|
-
Upgrading: an origin already listed for a provider now also sends `traceparent` to an MCP HTTP server
|
|
368
|
-
at that exact origin. Remove the origin, or move the MCP server to a different origin, if that server
|
|
369
|
-
should not link its logs to your trace.
|
|
370
|
-
|
|
371
|
-
### Doctor
|
|
372
|
-
|
|
373
|
-
`robota doctor` (aliases: `checkup`, `diagnose`) diagnoses configuration and runtime readiness
|
|
374
|
-
before any session exists, so a broken configuration cannot make the diagnostic unreachable. It reports
|
|
375
|
-
every settings layer in precedence order with its state and cause, the merged keys with the layer that
|
|
376
|
-
contributed each, provider resolution and endpoint reachability, workspace trust, storage, plugins,
|
|
377
|
-
skills, hooks and MCP declarations — naming the exact file and cause, never a credential. Exit code
|
|
378
|
-
`0` means no check failed (warnings allowed); `1` means at least one did.
|
|
103
|
+
Sessions are saved, so you can come back to them.
|
|
379
104
|
|
|
380
105
|
```bash
|
|
381
|
-
robota
|
|
382
|
-
robota
|
|
383
|
-
robota
|
|
106
|
+
robota -c # continue the most recent session
|
|
107
|
+
robota -r <id-or-name> # resume a session
|
|
108
|
+
robota -r <id> --fork-session # continue a copy, leaving the original as it was
|
|
109
|
+
robota -n "refactor auth" # name a new session
|
|
384
110
|
```
|
|
385
111
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
### MCP Servers
|
|
391
|
-
|
|
392
|
-
#### Serve Robota to an MCP host
|
|
112
|
+
Inside a session, `/resume` switches sessions, `/rename` names this one, `/fork` copies the
|
|
113
|
+
conversation into a background session, and `/cd <directory>` moves the conversation to another
|
|
114
|
+
directory.
|
|
393
115
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
MCP client that supports a child-process working directory, configure:
|
|
116
|
+
A supervised session keeps running after you close the terminal, and a workspace daemon is one
|
|
117
|
+
long-lived runtime that terminals and the desktop app share. In a folder not trusted yet, the desktop
|
|
118
|
+
app asks in its window whether to trust it, start Restricted, or quit before it starts the daemon:
|
|
398
119
|
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
"cwd": "/absolute/path/to/trusted/project"
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
120
|
+
```bash
|
|
121
|
+
robota session start --background --name nightly
|
|
122
|
+
robota session list
|
|
123
|
+
robota session attach <supervised-id> # add --observe to watch read-only
|
|
124
|
+
robota daemon start # then: robota --attach
|
|
125
|
+
robota daemon stop
|
|
409
126
|
```
|
|
410
127
|
|
|
411
|
-
|
|
412
|
-
directory for its normal project-root, access and trust decision; an MCP `roots/list` value or an
|
|
413
|
-
environment variable does not silently change it. For Claude Code, whose stdio server environment
|
|
414
|
-
includes `CLAUDE_PROJECT_DIR`, a project-scoped launch command can select that directory explicitly:
|
|
128
|
+
See [Sessions and the daemon](../../content/guide/sessions-and-daemon.md).
|
|
415
129
|
|
|
416
|
-
|
|
417
|
-
claude mcp add --scope project --transport stdio robota -- \
|
|
418
|
-
/bin/sh -c 'cd "$CLAUDE_PROJECT_DIR" && exec /absolute/path/to/robota mcp serve'
|
|
419
|
-
```
|
|
130
|
+
### Control what the agent may do
|
|
420
131
|
|
|
421
|
-
|
|
422
|
-
appear only through their canonical `robota_command_*` names. Tools run through the session's normal
|
|
423
|
-
permission and hook policy; denied or approval-requiring calls return MCP tool errors, never an
|
|
424
|
-
interactive prompt on the protocol stream. The peer is a local process started by the user and can
|
|
425
|
-
request actions within that session's admitted workspace and permissions. This mode starts no web
|
|
426
|
-
server, WebSocket sidecar or TUI. Stdout carries only MCP messages; startup notices and failures go
|
|
427
|
-
to stderr. Closing the host's stdin or sending SIGINT/SIGTERM shuts down the carrier and session.
|
|
428
|
-
If the host reports a connection failure, run `robota trust status` and `robota doctor` separately in
|
|
429
|
-
the same project directory, then inspect the host's captured stderr for configuration errors.
|
|
430
|
-
|
|
431
|
-
The same session can also use an admitted external MCP tool while it serves the host. Its connected
|
|
432
|
-
client tools appear in the served catalog under canonical names such as `probe__echo`; they still
|
|
433
|
-
run through the session's normal permission policy. The server carrier and outbound client close
|
|
434
|
-
independently. An embedding host can supply its own `IMCPActivationApprovalStore` through
|
|
435
|
-
`startCli({ mcpApprovalStore })` before startup, along with an explicitly approved
|
|
436
|
-
`mcpHttpTransportDeps` egress policy when needed. Neither capability comes from MCP settings or the
|
|
437
|
-
remote caller. The ordinary `robota` executable supplies neither automatically.
|
|
438
|
-
|
|
439
|
-
#### Serve Robota to a remote MCP client
|
|
440
|
-
|
|
441
|
-
`--http-token-file` is for clients on the same machine: it binds only `127.0.0.1`, and its bearer
|
|
442
|
-
is never accepted beyond loopback. To serve a client elsewhere, run Robota as an OAuth resource
|
|
443
|
-
server behind an HTTPS reverse proxy. An authorization server you already run issues the access
|
|
444
|
-
tokens; Robota only verifies them.
|
|
445
|
-
|
|
446
|
-
```sh
|
|
447
|
-
robota mcp serve \
|
|
448
|
-
--http-public-url https://agents.example.com/robota/mcp \
|
|
449
|
-
--oauth-issuer https://auth.example.com \
|
|
450
|
-
--oauth-scopes mcp:use \
|
|
451
|
-
--oauth-allowed-subjects alice@example.com \
|
|
452
|
-
--http-host 127.0.0.1 --http-port 8765 \
|
|
453
|
-
--trusted-proxy 127.0.0.1
|
|
454
|
-
```
|
|
132
|
+
Every tool call passes through deny rules, ask rules, allow rules and then the permission mode.
|
|
455
133
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
scope, and issued to a listed subject. Every admitted client drives the same session, so name only
|
|
464
|
-
the people you would hand this terminal to.
|
|
465
|
-
- `--http-host` defaults to `127.0.0.1`, which suits a proxy on the same machine. Robota binds any
|
|
466
|
-
other address only when all the flags above are present.
|
|
467
|
-
- A request without a valid token receives `401` with
|
|
468
|
-
`WWW-Authenticate: Bearer resource_metadata="…"`, and a token missing a scope receives `403`
|
|
469
|
-
with `insufficient_scope`. The body is always empty. MCP clients that support authorization
|
|
470
|
-
use that challenge to discover the authorization server.
|
|
471
|
-
- Failed requests are counted per client address. After too many failures in a minute, that
|
|
472
|
-
address receives `429`; a valid token is never throttled. The client address is read from
|
|
473
|
-
`X-Forwarded-For` only when the connection comes from a `--trusted-proxy` address (repeatable).
|
|
474
|
-
- Each refusal is logged on stderr as a reason and an address class (`loopback`, `private`,
|
|
475
|
-
`public`), never the token or the address itself.
|
|
476
|
-
- The server is stateless: it issues no `Mcp-Session-Id`, so there are no sessions to enumerate or
|
|
477
|
-
hijack.
|
|
478
|
-
|
|
479
|
-
The settings described below configure Robota as an MCP **client**.
|
|
480
|
-
|
|
481
|
-
Declare remote MCP servers under an `mcpServers` key in any layered settings file (managed, user, or
|
|
482
|
-
project `.robota`/`.claude` settings) — the same precedence order every other setting uses. Each
|
|
483
|
-
entry names a `"type": "http"` transport and a `url`; `${VAR}`/`${VAR:-default}` references in `url`,
|
|
484
|
-
`headers`, and `env` are resolved from the process environment. Every declared server is
|
|
485
|
-
**deny-by-default**: a server must be explicitly approved with `/mcp approve <serverId>` before its
|
|
486
|
-
tools are connected. Use `/mcp` (or `/mcp list`) to see every declared server's admission status,
|
|
487
|
-
and `/mcp reject`/`/mcp revoke` to withdraw approval. Only approved servers already known at startup
|
|
488
|
-
are connected. Approval is in-memory for the ordinary executable, so `/mcp approve` mid-session
|
|
489
|
-
records a decision for that session but does not connect the server in the running session or
|
|
490
|
-
persist it across a restart. An embedding host can preserve approval state across starts by
|
|
491
|
-
supplying the same store; it remains responsible for when to reconnect approved definitions.
|
|
492
|
-
|
|
493
|
-
A remote server that declares `"oauth": {}` (optionally with `clientId`, `callbackPort`,
|
|
494
|
-
`authServerMetadataUrl` and `scopes`) needs its own sign-in before a session can use it. Sign-in is
|
|
495
|
-
per server, naming the server — inside a session with `/mcp login <server>`, or from a terminal:
|
|
496
|
-
|
|
497
|
-
```bash
|
|
498
|
-
robota mcp login files # opens your browser; tokens kept owner-only in ~/.robota/mcp-credentials
|
|
499
|
-
robota mcp login files --no-browser # prints the URL; paste back the address your browser was sent to
|
|
500
|
-
robota mcp login files --client-secret # a pre-registered confidential client: asks for the secret
|
|
501
|
-
robota mcp logout files # deletes the stored tokens, then revokes them where the server allows
|
|
502
|
-
```
|
|
134
|
+
| Mode | Reads | File edits | Shell commands |
|
|
135
|
+
| ------------------- | ----- | ---------- | ---------------------------------------- |
|
|
136
|
+
| `plan` | yes | refused | refused (except built-in read-only ones) |
|
|
137
|
+
| `default` | yes | asks | asks |
|
|
138
|
+
| `acceptEdits` | yes | yes | asks |
|
|
139
|
+
| `auto` | yes | yes | decided by a model classifier |
|
|
140
|
+
| `bypassPermissions` | yes | yes | yes |
|
|
503
141
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
this sign-in's redirect address and carries its `state`, and only within the same five minutes the
|
|
508
|
-
browser flow allows.
|
|
509
|
-
|
|
510
|
-
`robota mcp logout <server>` always deletes that server's local credential, even when the
|
|
511
|
-
authorization server cannot be reached or refuses to revoke the tokens; it then says, per token,
|
|
512
|
-
whether it was revoked, and otherwise why not (by a short reason) or that the server offers no
|
|
513
|
-
revocation. `/mcp` shows each OAuth server's sign-in state — `signed in`, `token expired, will
|
|
514
|
-
refresh`, `sign-in required` or `signed out` — never a token, and for a server that needs a sign-in
|
|
515
|
-
it names `/mcp login <server>` and `robota mcp login <server>` (the server's name appears in them
|
|
516
|
-
only when it is a plain name that is safe to paste into any shell). `/mcp logout <serverId>` signs
|
|
517
|
-
out of that one server from inside a session and stops the session sending the token it holds.
|
|
518
|
-
|
|
519
|
-
`/mcp login <server>` signs in without leaving the session: it first shows the authorization URL,
|
|
520
|
-
where you can choose to open your browser, paste the redirect instead, or cancel. When no browser
|
|
521
|
-
can be opened — or with `/mcp login <server> --no-browser` — it asks for the redirect address in the
|
|
522
|
-
session's own prompt (the input is not shown). Once signed
|
|
523
|
-
in, a server that could not connect at startup is admitted as usual (it must be approved) and
|
|
524
|
-
connected, and its tools are available from your next message; a server whose sign-in lapsed
|
|
525
|
-
mid-session works again. A failed or cancelled sign-in changes nothing. A client secret is never
|
|
526
|
-
typed into a session: for a pre-registered client that needs one, run
|
|
527
|
-
`robota mcp login <server> --client-secret` in a terminal.
|
|
528
|
-
|
|
529
|
-
### MCP Background Handoff
|
|
530
|
-
|
|
531
|
-
A slow MCP tool call can be handed to a background task instead of blocking the turn. Configure it
|
|
532
|
-
under an `mcp` key (beside `mcpServers`, in the same layered settings files):
|
|
142
|
+
Set the mode with `--permission-mode <mode>` (`--dry-run` is `plan`) or change it in a session with
|
|
143
|
+
`/permissions <mode>`. `/permissions` alone lists the rules in force and recent denials. Rules live in
|
|
144
|
+
any settings file:
|
|
533
145
|
|
|
534
146
|
```json
|
|
535
147
|
{
|
|
536
|
-
"
|
|
537
|
-
"
|
|
538
|
-
"
|
|
148
|
+
"permissions": {
|
|
149
|
+
"allow": ["Bash(pnpm *)", "Bash(git status)"],
|
|
150
|
+
"ask": ["Bash(git push *)"],
|
|
151
|
+
"deny": ["Bash(rm -rf *)", "Write(.env)"]
|
|
539
152
|
}
|
|
540
153
|
}
|
|
541
154
|
```
|
|
542
155
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
- `callTimeoutMs` (default 600000 ms): the tool call's own budget, enforced by the MCP client in
|
|
547
|
-
every mode — including print. `autoBackgroundMs` must be less than `callTimeoutMs`, or the handoff
|
|
548
|
-
is disabled with a warning.
|
|
549
|
-
- The handoff applies to the interactive TUI and `robota --serve`. In print mode (`-p`) a slow MCP call always runs to completion in the
|
|
550
|
-
foreground, bounded by `callTimeoutMs`; a positive `autoBackgroundMs` is reported as ignored there.
|
|
551
|
-
|
|
552
|
-
### CLI Updates
|
|
553
|
-
|
|
554
|
-
Robota can check npm for a newer `@robota-sdk/agent-cli` version:
|
|
555
|
-
|
|
556
|
-
```bash
|
|
557
|
-
robota --check-update
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
When an update is available, Robota prints the npm global install command:
|
|
561
|
-
|
|
562
|
-
```bash
|
|
563
|
-
npm install -g '@robota-sdk/agent-cli@latest'
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
Robota does not implement its own updater and does not modify `~/.robota/settings.json` for update checks. Interactive startup checks use a user-level operational cache at `~/.robota/update-check.json` and can be skipped for one run with `--disable-update-check`. Print/headless mode (`robota -p`) does not perform automatic startup update checks so scripted stdout and stderr remain deterministic.
|
|
567
|
-
|
|
568
|
-
### Print Mode Output Formats
|
|
156
|
+
An `ask` rule asks even in `bypassPermissions`, and a few actions are never approved automatically
|
|
157
|
+
in any mode: `rm` on the root, home or working directory, and writes into `.git`, `.robota`,
|
|
158
|
+
`.claude`, `.agents` or shell and tool configuration files.
|
|
569
159
|
|
|
570
|
-
|
|
160
|
+
Shell commands can also run inside an OS sandbox (bubblewrap on Linux, Seatbelt on macOS): `/sandbox`
|
|
161
|
+
switches between `auto-allow`, `regular` and `off`, and the `sandbox` settings key configures it.
|
|
162
|
+
When something misbehaves, `robota --safe-mode` starts with instruction files, skills, plugins, hooks
|
|
163
|
+
and MCP servers all off.
|
|
571
164
|
|
|
572
|
-
|
|
573
|
-
| ------------- | ------------------------------------------------------------------ |
|
|
574
|
-
| `text` | Plain text response to stdout (default) |
|
|
575
|
-
| `json` | Single JSON object: `{ type, result, session_id, subtype }` |
|
|
576
|
-
| `stream-json` | Newline-delimited JSON with `content_block_delta` streaming events |
|
|
577
|
-
|
|
578
|
-
### Exit Codes (print mode)
|
|
579
|
-
|
|
580
|
-
| Code | Meaning |
|
|
581
|
-
| ---- | ---------------------------------------------- |
|
|
582
|
-
| 0 | Success |
|
|
583
|
-
| 1 | General error |
|
|
584
|
-
| 2 | Argument error |
|
|
585
|
-
| 3 | Configuration error (missing provider/API key) |
|
|
586
|
-
| 4 | API error |
|
|
587
|
-
| 5 | Tool execution error |
|
|
588
|
-
|
|
589
|
-
### Stdin Pipe
|
|
590
|
-
|
|
591
|
-
When stdin is piped, the CLI reads it automatically. If a positional prompt is also given, the piped content is appended inside `<stdin>` tags:
|
|
165
|
+
Workspace trust is granted per Git worktree and kept in `~/.robota/workspace-trust.json`:
|
|
592
166
|
|
|
593
167
|
```bash
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
## First-Run Setup
|
|
600
|
-
|
|
601
|
-
When no usable settings file exists, the CLI prompts for:
|
|
602
|
-
|
|
603
|
-
1. **Provider selection** from the providers assembled into the CLI binary
|
|
604
|
-
2. **Provider-specific setup fields** such as model, base URL, and masked API key
|
|
605
|
-
3. **Response language** (ko/en/ja/zh, default: en)
|
|
606
|
-
|
|
607
|
-
Creates `~/.robota/settings.json`. Use `robota --reset` to return to first-run state.
|
|
608
|
-
|
|
609
|
-
Provider setup is generated from provider definitions. The default CLI build includes Anthropic,
|
|
610
|
-
OpenAI-compatible, DeepSeek, Gemma, and Qwen providers; other embeddings can inject their own
|
|
611
|
-
provider definitions.
|
|
612
|
-
Interactive setup creates a readable profile key from the selected model id, such as
|
|
613
|
-
`claude-sonnet-4-6` or `gpt-4o`, and appends `-2`, `-3`, etc. when that key already exists. Generated
|
|
614
|
-
profile keys never include API keys or credential hints.
|
|
615
|
-
|
|
616
|
-
Inside the TUI, `/provider` and `/provider list` show configured profiles as an interactive picker. Selecting a profile opens command-owned actions for switch, edit, test, duplicate, delete, and cancel. Headless mode prints the same profile list text without opening prompts.
|
|
617
|
-
|
|
618
|
-
Non-interactive/headless mode never prompts. Configure a provider ahead of time with `robota --configure` in an interactive terminal, or use `robota --configure-provider <profile> --type <type> ... --set-current`.
|
|
619
|
-
|
|
620
|
-
## Built-in Tools
|
|
621
|
-
|
|
622
|
-
The AI agent can invoke 9 distinct local tools (the runtime registers 10 tool names — `Bash` is the model-familiar alias of `Shell`):
|
|
623
|
-
|
|
624
|
-
| Tool | Description | Primary Argument |
|
|
625
|
-
| ----------------- | ---------------------------------------------- | ---------------- |
|
|
626
|
-
| `Bash` | Execute shell commands | `command` |
|
|
627
|
-
| `Read` | Read file contents with line numbers | `filePath` |
|
|
628
|
-
| `Write` | Write content to a file | `filePath` |
|
|
629
|
-
| `Edit` | Replace a string in a file | `filePath` |
|
|
630
|
-
| `Glob` | Find files matching a pattern | `pattern` |
|
|
631
|
-
| `Grep` | Search file contents with regex | `pattern` |
|
|
632
|
-
| `WebFetch` | Fetch URL content as text | `url` |
|
|
633
|
-
| `WebSearch` | Search the internet (requires `BRAVE_API_KEY`) | `query` |
|
|
634
|
-
| `AskUserQuestion` | Ask the user structured questions mid-task | `questions` |
|
|
635
|
-
|
|
636
|
-
> **WebSearch** requires a `BRAVE_API_KEY` environment variable. Without it, the tool returns a setup message instead of results. Get a free key at [brave.com/search/api](https://brave.com/search/api/) (2,000 queries/month free tier).
|
|
637
|
-
|
|
638
|
-
## Recent TUI Capabilities
|
|
639
|
-
|
|
640
|
-
- Provider setup and profile management are generated from provider definitions, so the default CLI
|
|
641
|
-
build can configure, switch, edit, test, duplicate, and delete Anthropic, OpenAI-compatible,
|
|
642
|
-
DeepSeek, Gemma, and Qwen profiles without provider-specific UI branches.
|
|
643
|
-
- Interactive startup can check npm for newer CLI versions; print/headless mode skips startup update checks to keep scripted output deterministic.
|
|
644
|
-
- Long-running sessions show provider usage summaries, status activity, background job tree rows, and collapsed command-output transcripts.
|
|
645
|
-
- Edit results render as context hunks with markdown-friendly diff blocks.
|
|
646
|
-
- Background subagents are real runtime jobs with transcripts and resumable task snapshots.
|
|
647
|
-
- Explicit multi-agent requests use the `/agent` command module batch path through the SDK runtime.
|
|
648
|
-
|
|
649
|
-
### Recap when you come back
|
|
650
|
-
|
|
651
|
-
The TUI notices when you leave the terminal — by focus, where the terminal reports it (iTerm2,
|
|
652
|
-
Kitty, WezTerm, Alacritty, Ghostty, VS Code, Windows Terminal, tmux with `focus-events on`), or
|
|
653
|
-
after five minutes without a keystroke elsewhere — and on your return prints one line for the
|
|
654
|
-
interval, or nothing if nothing happened:
|
|
655
|
-
|
|
656
|
-
```
|
|
657
|
-
While away 12m: 2 turns finished (1 wake) · 1 needs input · 1 failed
|
|
168
|
+
robota trust status # is this workspace trusted, and what would trust load? (--json: one line)
|
|
169
|
+
robota trust --yes # trust the Git workspace you are in
|
|
170
|
+
robota trust revoke --yes
|
|
658
171
|
```
|
|
659
172
|
|
|
660
|
-
|
|
661
|
-
`completed`, `failed`, `stopped`), the one-line headline, and for a sleeping `/schedule` a live
|
|
662
|
-
`in 59s` countdown. `ROBOTA_FOCUS_EVENTS=0` turns focus reporting off (idle detection remains);
|
|
663
|
-
`=1` requests it even where the TUI would not.
|
|
664
|
-
|
|
665
|
-
### Prompt history
|
|
666
|
-
|
|
667
|
-
`Ctrl+R` searches every prompt you have typed — in this session, in this project, or anywhere —
|
|
668
|
-
the way a shell's reverse search does. Type to narrow the list (newest first, matches highlighted),
|
|
669
|
-
`Ctrl+S` cycles the scope `all → session → project`, `Enter` or `Tab` puts the highlighted prompt back
|
|
670
|
-
in the input, `Ctrl+E` runs it, `Esc` returns you to exactly the draft you had. Every key is
|
|
671
|
-
rebindable in `~/.robota/keybindings.json` (context `history-search`, and `chat-input.history-search`
|
|
672
|
-
for the opener).
|
|
673
|
-
|
|
674
|
-
What is written, where, and how to turn it off: the interactive TUI appends each prompt you submit
|
|
675
|
-
to `~/.robota/history.jsonl` (one JSON line — timestamp, session id, project root, text; readable by
|
|
676
|
-
you only). Prompts are already kept verbatim in the session record; this file is a searchable index
|
|
677
|
-
of them across sessions. `--serve` and print mode never write it. Set `"promptHistory": false` in
|
|
678
|
-
`~/.robota/settings.json` to turn it off, or `ROBOTA_PROMPT_HISTORY=0` for one run (`=1` overrides
|
|
679
|
-
the setting). Delete the file to forget everything.
|
|
173
|
+
See [Permissions and hooks](../../content/guide/permissions-and-hooks.md).
|
|
680
174
|
|
|
681
|
-
|
|
682
|
-
so every message of a resumed session is in your terminal's own scrollback and search.
|
|
175
|
+
### Choose providers and models
|
|
683
176
|
|
|
684
|
-
|
|
177
|
+
Each provider profile in `providers` names a `type` (`anthropic`, `openai`, `gemini`, `deepseek`,
|
|
178
|
+
`qwen`, `gemma`), a model, and optionally a base URL and API key; `currentProvider` picks the one to
|
|
179
|
+
use. Setup fills the key in as a reference to an environment variable:
|
|
685
180
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
`
|
|
694
|
-
"bad" — for the roughly 1 in 12 men with a colour-vision deficiency. The daltonized pair is checked
|
|
695
|
-
mechanically: a test simulates protanopia and deuteranopia over the pairs whose difference in colour
|
|
696
|
-
carries meaning and fails if any of them come too close.
|
|
697
|
-
|
|
698
|
-
Without the picker: `/theme list` shows what is installed and what is active, `/theme <id>` switches,
|
|
699
|
-
`/theme syntax on|off` toggles code-block highlighting, and `/theme motion on|off` toggles animation.
|
|
700
|
-
All three persist to `~/.robota/settings.json` as the flat keys `theme`, `syntaxHighlighting` and
|
|
701
|
-
`reducedMotion`.
|
|
702
|
-
|
|
703
|
-
#### Writing your own
|
|
704
|
-
|
|
705
|
-
Drop a `.json` file in `~/.robota/themes/` and it appears in the list as `custom:<file-name>`. The
|
|
706
|
-
name becomes part of an id you type, so it may use up to 24 characters from letters, digits, `.`,
|
|
707
|
-
`-` and `_` — a file named anything else is skipped with a line saying so, rather than listed as a theme no command can apply:
|
|
181
|
+
| Provider type | Default key variable | Notes |
|
|
182
|
+
| ------------- | -------------------- | ------------------------------------------------------------------------------------ |
|
|
183
|
+
| `anthropic` | `ANTHROPIC_API_KEY` | |
|
|
184
|
+
| `openai` | `OPENAI_API_KEY` | also other OpenAI-compatible endpoints, through `baseURL` |
|
|
185
|
+
| `gemini` | `GEMINI_API_KEY` | |
|
|
186
|
+
| `deepseek` | `DEEPSEEK_API_KEY` | |
|
|
187
|
+
| `qwen` | `DASHSCOPE_API_KEY` | Alibaba Cloud Model Studio |
|
|
188
|
+
| `gemma` | none | a local Gemma model; the base URL defaults to LM Studio's `http://localhost:1234/v1` |
|
|
708
189
|
|
|
709
190
|
```json
|
|
710
191
|
{
|
|
711
|
-
"
|
|
712
|
-
"
|
|
713
|
-
|
|
192
|
+
"currentProvider": "claude",
|
|
193
|
+
"providers": {
|
|
194
|
+
"claude": {
|
|
195
|
+
"type": "anthropic",
|
|
196
|
+
"model": "claude-sonnet-4-6",
|
|
197
|
+
"apiKey": "$ENV:ANTHROPIC_API_KEY"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
714
200
|
}
|
|
715
201
|
```
|
|
716
202
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
the
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
`custom:<plugin>:<file-name>`, and the plugin's own name has to satisfy the same rule for the same
|
|
724
|
-
reason. Both namespaces start with `custom:`, so a file can never take a
|
|
725
|
-
built-in's name whatever it is called.
|
|
726
|
-
|
|
727
|
-
A file is applied whole or not at all. An unknown token, a value that is not a colour, or JSON that
|
|
728
|
-
does not parse skips the WHOLE file with the path that refused it — printed once at startup as
|
|
729
|
-
`Skipped theme "mine.json": $.overrides.colors.text.accent: "nope" is not a colour …`, and shown in
|
|
730
|
-
the picker as a row that carries the same reason and cannot be chosen. Its neighbours still load.
|
|
731
|
-
|
|
732
|
-
Motion can also be decided per run: `--reduced-motion` / `--no-reduced-motion` beat
|
|
733
|
-
`ROBOTA_REDUCED_MOTION=1|0`, which beats the setting. A run that pins it says so — `/theme motion on`
|
|
734
|
-
reports that it saved the setting and that this run keeps what pinned it, rather than appearing to
|
|
735
|
-
do nothing. `NO_COLOR`, `FORCE_COLOR=0`, a non-TTY stdout and screen-reader mode still win over
|
|
736
|
-
every theme: no colour and no animation, exactly as before.
|
|
737
|
-
|
|
738
|
-
## Permission System
|
|
739
|
-
|
|
740
|
-
Every tool call passes through a three-step permission gate:
|
|
741
|
-
|
|
742
|
-
1. **Deny list** — if any deny pattern matches, the action is blocked
|
|
743
|
-
2. **Allow list** — if any allow pattern matches, the action is auto-approved
|
|
744
|
-
3. **Mode policy** — the active permission mode determines the decision
|
|
745
|
-
|
|
746
|
-
### Permission Modes
|
|
747
|
-
|
|
748
|
-
| Mode | Read/Glob/Grep | Write/Edit | Bash |
|
|
749
|
-
| ------------------- | :------------: | :--------: | :-----: |
|
|
750
|
-
| `plan` | auto | deny | deny |
|
|
751
|
-
| `default` | auto | approve | approve |
|
|
752
|
-
| `acceptEdits` | auto | auto | approve |
|
|
753
|
-
| `bypassPermissions` | auto | auto | auto |
|
|
754
|
-
|
|
755
|
-
### Changing Mode at Runtime
|
|
203
|
+
In a session, `/provider list`, `/provider switch <profile>`, `/provider add` and `/provider test`
|
|
204
|
+
manage profiles. For one run, `--provider <profile>` picks a profile (add `--set-current` to make it
|
|
205
|
+
the default), `--model` overrides the model, `--fallback-model a,b` continues a turn on another model
|
|
206
|
+
when the first is overloaded, `--effort <level>` sets model effort, and `--advisor <profile[:model]>`
|
|
207
|
+
lets the model consult a second model. See [Providers](../../content/guide/providers.md) and
|
|
208
|
+
[Local LLM setup](../../content/guide/local-llm.md).
|
|
756
209
|
|
|
757
|
-
|
|
210
|
+
### Connect MCP servers, or serve Robota over MCP
|
|
758
211
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
212
|
+
Declare remote MCP servers under `mcpServers` in a settings file. A declared server is not connected
|
|
213
|
+
until you approve it: `/mcp` shows each server's state and `/mcp approve <server>` records your
|
|
214
|
+
approval. The `robota` executable keeps approvals in memory only, so they do not carry over to the
|
|
215
|
+
next start. A server that uses OAuth also needs a sign-in — `/mcp login <server>` in a session, or
|
|
216
|
+
`robota mcp login <server>` in a terminal — and an approved server connects in the running session
|
|
217
|
+
once you sign in.
|
|
764
218
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"mcpServers": {
|
|
222
|
+
"docs": { "type": "http", "url": "https://mcp.example.com/mcp", "oauth": {} }
|
|
223
|
+
}
|
|
224
|
+
}
|
|
769
225
|
```
|
|
770
226
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
227
|
+
`robota mcp serve` does the reverse: it serves one Robota session to an MCP host over stdio (or over
|
|
228
|
+
authenticated HTTP with the `--http-*` and `--oauth-*` flags). Trust the project first, and give the
|
|
229
|
+
host the absolute path of `robota` and the project directory:
|
|
774
230
|
|
|
775
231
|
```json
|
|
776
232
|
{
|
|
777
|
-
"
|
|
778
|
-
"
|
|
779
|
-
|
|
233
|
+
"mcpServers": {
|
|
234
|
+
"robota": {
|
|
235
|
+
"command": "/absolute/path/to/robota",
|
|
236
|
+
"args": ["mcp", "serve"],
|
|
237
|
+
"cwd": "/absolute/path/to/trusted/project"
|
|
238
|
+
}
|
|
780
239
|
}
|
|
781
240
|
}
|
|
782
241
|
```
|
|
783
242
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
## Keyboard Controls
|
|
787
|
-
|
|
788
|
-
| Key | Action |
|
|
789
|
-
| ---------- | ----------------------------------------------------------- |
|
|
790
|
-
| Enter | Submit input |
|
|
791
|
-
| Ctrl+R | Search prompt history (see "Prompt history") |
|
|
792
|
-
| ESC | Abort current execution (graceful — saves partial response) |
|
|
793
|
-
| Ctrl+C | Exit process immediately |
|
|
794
|
-
| Up/Down | Navigate visual lines in wrapped multi-line input |
|
|
795
|
-
| Arrow keys | Navigate slash command autocomplete, permission prompt |
|
|
243
|
+
See [MCP](../../content/guide/mcp.md).
|
|
796
244
|
|
|
797
|
-
|
|
245
|
+
### Add skills, commands, agents and plugins
|
|
798
246
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
After the Edit tool runs, a `DiffBlock` component renders the change inline:
|
|
247
|
+
Skills and commands are Markdown files the CLI finds in `.robota/skills/`, `.claude/skills/`,
|
|
248
|
+
`.claude/commands/` and `.agents/skills/` — in a trusted project and under your home directory. Each
|
|
249
|
+
one becomes a slash command (`/<name>`), and `/skills` lists them. Agent definitions are read from
|
|
250
|
+
`.robota/agents/`, `.agents/agents/` and `.claude/agents/`. Plugins bundle these together with hooks,
|
|
251
|
+
themes and MCP servers:
|
|
806
252
|
|
|
253
|
+
```text
|
|
254
|
+
/plugin marketplace add <source>
|
|
255
|
+
/plugin install <name>@<marketplace>
|
|
256
|
+
/plugin # open the plugin manager
|
|
807
257
|
```
|
|
808
|
-
✓ Edit(src/provider.ts)
|
|
809
|
-
│ src/provider.ts
|
|
810
|
-
│ - const DEFAULT_MAX_TOKENS = 4096;
|
|
811
|
-
│ + const maxTokens = getModelMaxOutput(modelId);
|
|
812
|
-
```
|
|
813
|
-
|
|
814
|
-
Removed lines appear in red with `-`, added lines in green with `+`. Diffs longer than 10 lines show the first 8 + a `... and N more lines` summary.
|
|
815
|
-
|
|
816
|
-
## Session Management
|
|
817
258
|
|
|
818
|
-
|
|
259
|
+
See the [CLI guide](../../content/guide/cli.md) for skill frontmatter and plugin management.
|
|
819
260
|
|
|
820
|
-
###
|
|
261
|
+
### Use the graphical interface
|
|
821
262
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
| `--fork-session <id>` | Fork a session (new session with copied history) |
|
|
827
|
-
| `--name <name>` | Assign a name to the session at startup |
|
|
263
|
+
`robota --serve --open` starts a headless runtime for the current workspace, serves the Robota GUI
|
|
264
|
+
on `127.0.0.1` and opens it in your browser. The Electron desktop app in this repository
|
|
265
|
+
([`apps/agent-app`](../../apps/agent-app/docs/README.md)) shows the same GUI over the workspace
|
|
266
|
+
daemon; it is not published to npm. See [The GUI and the Desktop App](../../content/guide/gui.md).
|
|
828
267
|
|
|
829
|
-
###
|
|
268
|
+
### Reach other sessions and your other devices
|
|
830
269
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
270
|
+
`/peers` lists the other live `robota` sessions on this machine, and `/peers send <session-id>
|
|
271
|
+
<message>` sends one a message; the receiving session handles it under its own permissions, like
|
|
272
|
+
its own work. `/handoff <session-id>` moves this conversation to another session once both sides
|
|
273
|
+
confirm. To reach your other devices too, create a device identity with `/devices init`, link each
|
|
274
|
+
new device with `/devices add` and `/devices join`, and set `transports.mesh.enabled` to `true` in
|
|
275
|
+
your user settings. `/remote-control enable` pairs a browser to co-drive the current session.
|
|
835
276
|
|
|
836
|
-
|
|
277
|
+
See [Devices and remote control](../../content/guide/devices-and-remote.md).
|
|
837
278
|
|
|
838
|
-
|
|
839
|
-
launched in that directory: its settings, trust decision, tools, skills and `AGENTS.md` apply, and the
|
|
840
|
-
conversation resumes. The system prompt is kept as it was, so a provider's prompt cache survives. One
|
|
841
|
-
message tells the model about the new directory and its project instructions.
|
|
842
|
-
|
|
843
|
-
- `/cd` is refused while a turn is running or a background task is still running, and in a session
|
|
844
|
-
started with `--no-session-persistence`, which has no saved conversation to carry.
|
|
845
|
-
- A restricted (untrusted) session stays restricted after a move. A trusted session takes the target
|
|
846
|
-
directory's own trust decision.
|
|
847
|
-
- A `Cd(...)` deny rule keeps sessions out of a directory, for example
|
|
848
|
-
`"deny": ["Cd(/secrets/**)"]`.
|
|
849
|
-
|
|
850
|
-
### Session Name Display
|
|
851
|
-
|
|
852
|
-
When a session has a name, it appears in three places:
|
|
853
|
-
|
|
854
|
-
- **Input border** — session name shown in the input area border
|
|
855
|
-
- **Terminal title** — updated via ANSI escape sequences
|
|
856
|
-
- **StatusBar** — displayed alongside activity, model, and context usage
|
|
857
|
-
|
|
858
|
-
## Deep Links
|
|
859
|
-
|
|
860
|
-
A `robota://open` link starts a session in a directory you have already trusted, with a prompt
|
|
861
|
-
already in the composer and **not** submitted — you read it and press Enter, or clear it.
|
|
279
|
+
### Check your setup and usage
|
|
862
280
|
|
|
863
281
|
```bash
|
|
864
|
-
robota
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
| -------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
869
|
-
| `v` | Contract version. Required, and must be `1`. |
|
|
870
|
-
| `prompt` | The text to prefill. At most 5,000 characters; it may not begin with `/`. |
|
|
871
|
-
| `cwd` | Absolute path of the directory to open. |
|
|
872
|
-
| `repo` | `owner/name` of an already-trusted local clone, when you do not want to name a path. `cwd` wins if both are present. |
|
|
873
|
-
|
|
874
|
-
Everything else is refused, and a refusal discards the whole link, says which rule it broke, writes
|
|
875
|
-
to stderr and exits non-zero without starting a session: an unknown key (so a link cannot carry
|
|
876
|
-
`provider=`, `permission-mode=`, `plugin=` or any other configuration), a duplicate key, a missing
|
|
877
|
-
or different `v`, a link over 8,192 characters, a prompt over 5,000, a prompt beginning with `/`
|
|
878
|
-
(one Enter would otherwise run it as a command), a relative, UNC or `..`-bearing path, and a second
|
|
879
|
-
link appended after the first (the argv shape a desktop handler can be made to produce). Your own
|
|
880
|
-
flags still apply after the link; a trailing token that is neither a link nor a flag is currently
|
|
881
|
-
discarded rather than refused — a CLI-wide gap tracked separately, not specific to links.
|
|
882
|
-
|
|
883
|
-
The target must already be trusted — `robota trust --yes` in that directory — for `cwd=` exactly as
|
|
884
|
-
for `repo=`. A link opens only what you have already approved; it never clones, never fetches, and
|
|
885
|
-
never reads a repository you have not trusted. While the composer still holds exactly what the link
|
|
886
|
-
supplied, the line `Prompt from an external link` sits below the input, and above 1,000 characters it
|
|
887
|
-
adds the character count and asks you to read the whole thing before sending. Edit that text and the
|
|
888
|
-
line goes: what is in the composer is then yours, and the label would be claiming otherwise.
|
|
889
|
-
|
|
890
|
-
**Known limitations.** No URL scheme is registered with the operating system yet, so a browser
|
|
891
|
-
cannot hand the link over: pass it to `robota open` yourself, or point your own handler at that
|
|
892
|
-
command. Registering the scheme on macOS, Linux and Windows, and the HTTPS launcher that works
|
|
893
|
-
around chat clients stripping custom schemes, are tracked separately.
|
|
894
|
-
|
|
895
|
-
## Slash Commands
|
|
896
|
-
|
|
897
|
-
Typing `/` in the TUI opens an autocomplete popup. Arrow keys navigate, Tab inserts without executing, Enter executes. Subcommands (e.g., `/provider list`) show a nested submenu.
|
|
898
|
-
|
|
899
|
-
### Session & Context
|
|
900
|
-
|
|
901
|
-
| Command | Description |
|
|
902
|
-
| ------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
903
|
-
| `/clear` | Clear conversation history |
|
|
904
|
-
| `/compact [instructions]` | Compress context window |
|
|
905
|
-
| `/context` | Context window details, reference inventory, and auto-compact controls |
|
|
906
|
-
| `/cost` | Show session token usage and cost |
|
|
907
|
-
| `/effort [level]` | Show or change model effort (`auto`, `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) |
|
|
908
|
-
| `/resume` | List recent sessions and resume one |
|
|
909
|
-
| `/rename <name>` | Rename the current session |
|
|
910
|
-
| `/cd <directory>` | Move this conversation to another directory (see below) |
|
|
911
|
-
| `/rewind` | List, inspect, restore, or rollback edit checkpoints |
|
|
912
|
-
|
|
913
|
-
### Providers & Settings
|
|
914
|
-
|
|
915
|
-
| Command | Description |
|
|
916
|
-
| ------------------------ | -------------------------------------------------------------------- | ------- | -------------------------------------------------- |
|
|
917
|
-
| `/provider [subcommand]` | Manage provider profiles: `list`, `switch`, `add`, `test`, `current` |
|
|
918
|
-
| `/mode [mode]` | Show or switch permission mode |
|
|
919
|
-
| `/permissions [mode]` | Show permission rules or change permission mode |
|
|
920
|
-
| `/sandbox [mode]` | Show or change how shell commands are confined |
|
|
921
|
-
| `/settings` | Open transport settings (enable/disable transports) |
|
|
922
|
-
| `/language [lang]` | Set response language (ko, en, ja, zh), saves and restarts |
|
|
923
|
-
| `/statusline [on | off | reset]` | Configure status-line fields (model, context, git) |
|
|
924
|
-
|
|
925
|
-
### Tools & Memory
|
|
926
|
-
|
|
927
|
-
| Command | Description |
|
|
928
|
-
| ---------------------- | -------------------------------------------------------------------- |
|
|
929
|
-
| `/memory [subcommand]` | Inspect, add, or review project memory entries |
|
|
930
|
-
| `/background` | List and control background tasks |
|
|
931
|
-
| `/goal <objective>` | Assign an autonomous goal pursued across turns (`status` / `cancel`) |
|
|
932
|
-
| `/agent` | Run and manage background subagent jobs |
|
|
933
|
-
| `/skills [name]` | List registered skills or activate one by name |
|
|
934
|
-
| `/plugin [subcommand]` | Plugin management |
|
|
935
|
-
|
|
936
|
-
### Git
|
|
937
|
-
|
|
938
|
-
| Command | Description |
|
|
939
|
-
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
940
|
-
| `/git status` | Branch plus the staged, unstaged and untracked paths |
|
|
941
|
-
| `/git diff [--staged \| <rev> \| <a>..<b>] [-- <path> ...]` | Unstaged diff, staged diff, or a diff against one or two revisions (each revision is verified first) |
|
|
942
|
-
| `/git commit [<subject>]` | Commit the staged changes after a confirmation listing the message and the staged files |
|
|
943
|
-
|
|
944
|
-
`/git commit` operates on the staged set only — no `-a`, no paths. The subject must follow the
|
|
945
|
-
Conventional Commits form `<type>[(scope)][!]: <description>`; the type list, the 72-character limit
|
|
946
|
-
and a trailing period are warnings, not refusals. With nothing staged it says so, with the unstaged and
|
|
947
|
-
untracked counts. Headless (`-p`) runs cancel the commit because no confirmation can be asked for.
|
|
948
|
-
Other git flags are not accepted — `/shell git ...` remains the way to run arbitrary git.
|
|
949
|
-
|
|
950
|
-
### Sessions on this host
|
|
951
|
-
|
|
952
|
-
| Command | Description |
|
|
953
|
-
| ------------------------------------ | ----------------------------------------- |
|
|
954
|
-
| `/peers` | List the other live sessions on this host |
|
|
955
|
-
| `/peers send <session-id> <message>` | Send a message to one of them |
|
|
956
|
-
|
|
957
|
-
See [Talking to another session](#talking-to-another-session) for the flow and what happens when the
|
|
958
|
-
other session is busy.
|
|
959
|
-
|
|
960
|
-
### Utility
|
|
961
|
-
|
|
962
|
-
| Command | Description |
|
|
963
|
-
| -------- | -------------------------------------------------- |
|
|
964
|
-
| `/help` | Show available commands |
|
|
965
|
-
| `/reset` | Delete user settings and return to first-run state |
|
|
966
|
-
| `/exit` | Exit CLI |
|
|
967
|
-
|
|
968
|
-
Skill commands from the CLI's ordered `.robota/skills/`, `.claude/skills/`, `.claude/commands/`, and
|
|
969
|
-
`.agents/skills/` roots appear alongside built-in commands.
|
|
970
|
-
|
|
971
|
-
## Talking to another session
|
|
972
|
-
|
|
973
|
-
Two `robota` sessions running on the same host, as the same user, can see and address each other.
|
|
974
|
-
Nothing crosses a machine boundary and nothing is configured — a session becomes discoverable by
|
|
975
|
-
being alive and stops being discoverable when it exits.
|
|
976
|
-
|
|
977
|
-
### Seeing who is there
|
|
978
|
-
|
|
979
|
-
```
|
|
980
|
-
/peers
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
With nothing else running:
|
|
984
|
-
|
|
985
|
-
```
|
|
986
|
-
No other live session is announced. Start a second session on this host, as this user,
|
|
987
|
-
and it appears here.
|
|
988
|
-
```
|
|
989
|
-
|
|
990
|
-
That is a sentence rather than an empty list on purpose: "no one is there" and "discovery is not
|
|
991
|
-
working" are different answers, and an empty list cannot tell you which one you got.
|
|
992
|
-
|
|
993
|
-
With a second session up:
|
|
994
|
-
|
|
995
|
-
```
|
|
996
|
-
Live sessions:
|
|
997
|
-
b8319b98-bb7b-486c-a499-cf1585b39e61 (this session)
|
|
998
|
-
97ffafe3-f770-4877-90a4-bd86df6be010
|
|
999
|
-
|
|
1000
|
-
Send to one: /peers send <session-id> <message>
|
|
1001
|
-
```
|
|
1002
|
-
|
|
1003
|
-
### Sending
|
|
1004
|
-
|
|
1005
|
-
```
|
|
1006
|
-
/peers send 97ffafe3-f770-4877-90a4-bd86df6be010 rerun the failing suite
|
|
1007
|
-
```
|
|
1008
|
-
|
|
1009
|
-
The message becomes a **turn** in the other session — the agent there answers it as if the operator
|
|
1010
|
-
had typed it. The sender is told which of four things happened, as a sentence:
|
|
1011
|
-
|
|
1012
|
-
| Outcome | What it means |
|
|
1013
|
-
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------- |
|
|
1014
|
-
| `Delivered to <id>.` | It arrived and started. |
|
|
1015
|
-
| `<id> has the message; it is waiting behind work already running there.` | It arrived and is queued. Deliberately **not** reported as delivered. |
|
|
1016
|
-
| `<id> had already seen that message.` | A retry that the receiver recognised; it does not run twice. |
|
|
1017
|
-
| `Not delivered to <id>. <reason>` | Nothing ran. The reason names the target, e.g. that no such session is announced. |
|
|
1018
|
-
|
|
1019
|
-
The second row is the one worth knowing. Reporting a queued message as delivered would hide a wait
|
|
1020
|
-
the operator can otherwise see and act on.
|
|
1021
|
-
|
|
1022
|
-
### What the receiving operator sees
|
|
1023
|
-
|
|
1024
|
-
The message is attributed to the sender, not to whoever is sitting at the receiving terminal:
|
|
1025
|
-
|
|
1026
|
-
```
|
|
1027
|
-
peer:b8319b98-bb7b-486c-a499-cf1585b39e61:
|
|
1028
|
-
rerun the failing suite
|
|
1029
|
-
Robota:
|
|
1030
|
-
…
|
|
282
|
+
robota doctor # settings layers, provider, trust, storage, plugins, hooks, MCP
|
|
283
|
+
robota usage # sessions, turns, tokens and cost for the last 7 days (--period 30d)
|
|
284
|
+
robota --check-update # is a newer version on npm?
|
|
285
|
+
robota eval <definition> # run an evals-as-code definition; exits 1 on a metric breach
|
|
1031
286
|
```
|
|
1032
287
|
|
|
1033
|
-
|
|
1034
|
-
it is not a display name the sender chose, because a name the transcript's reader trusts must not be
|
|
1035
|
-
picked by the party being named. It is display attribution only: nothing anywhere uses it to decide
|
|
1036
|
-
what a turn is allowed to do.
|
|
1037
|
-
|
|
1038
|
-
### When the other session is busy
|
|
1039
|
-
|
|
1040
|
-
A message arriving mid-turn joins that session's existing pending queue rather than interrupting or
|
|
1041
|
-
opening a second one. Three things follow from how that queue works:
|
|
1042
|
-
|
|
1043
|
-
- **Consecutive messages from the same sender coalesce**, last one wins. That is right for a person
|
|
1044
|
-
retyping and wrong for a peer saying two separate things. The replaced one is not swallowed: it
|
|
1045
|
-
settles as refused with the reason `coalesced`, so the sender learns it never ran rather than
|
|
1046
|
-
assuming both did. Tracked as `PEER-003`.
|
|
1047
|
-
- **Messages from different senders do not coalesce** — they queue in arrival order.
|
|
1048
|
-
- **The queue holds 32.** Beyond that a message settles as refused with the reason `dropped`.
|
|
1049
|
-
- **A cleared queue** — abort, cancel, or shutdown — settles the waiting entries with `cancelled`.
|
|
1050
|
-
|
|
1051
|
-
In every case the submission that never became a turn says so. A message that arrived and was then
|
|
1052
|
-
displaced is a different thing from one that ran, and the sender is told which it got.
|
|
1053
|
-
|
|
1054
|
-
### Limits
|
|
1055
|
-
|
|
1056
|
-
- Same host, same user. There is no network path here.
|
|
1057
|
-
- A session that exits removes its own entry; a crashed one is reaped by the next session that looks.
|
|
1058
|
-
- Session ids are what you address. There are no aliases.
|
|
1059
|
-
|
|
1060
|
-
## Plugin Management
|
|
288
|
+
## Configuration files
|
|
1061
289
|
|
|
1062
|
-
|
|
290
|
+
Settings are merged from these files, lowest priority first. The two user files always apply; the
|
|
291
|
+
four project files apply only in a trusted workspace.
|
|
1063
292
|
|
|
1064
|
-
|
|
|
1065
|
-
|
|
|
1066
|
-
|
|
|
1067
|
-
|
|
|
1068
|
-
|
|
|
1069
|
-
|
|
|
1070
|
-
|
|
|
1071
|
-
|
|
|
1072
|
-
| `/plugin marketplace remove <name>` | Remove a marketplace source |
|
|
1073
|
-
| `/plugin marketplace update <name>` | Update a marketplace source |
|
|
1074
|
-
| `/plugin marketplace list` | List configured marketplace sources |
|
|
293
|
+
| File | Scope |
|
|
294
|
+
| ----------------------------- | --------------------------------------- |
|
|
295
|
+
| `~/.robota/settings.json` | user |
|
|
296
|
+
| `~/.claude/settings.json` | user (Claude Code-compatible) |
|
|
297
|
+
| `.robota/settings.json` | project, committed |
|
|
298
|
+
| `.robota/settings.local.json` | project, local to this machine |
|
|
299
|
+
| `.claude/settings.json` | project (Claude Code-compatible) |
|
|
300
|
+
| `.claude/settings.local.json` | project, local (Claude Code-compatible) |
|
|
1075
301
|
|
|
1076
|
-
|
|
302
|
+
Other files the CLI keeps under `~/.robota/`:
|
|
1077
303
|
|
|
1078
|
-
|
|
304
|
+
| Path | Contents |
|
|
305
|
+
| ---------------------- | ----------------------------------------------------------------------- |
|
|
306
|
+
| `workspace-trust.json` | workspaces you have trusted |
|
|
307
|
+
| `sessions/` | saved sessions (a trusted project may keep them in `.robota/sessions/`) |
|
|
308
|
+
| `history.jsonl` | prompts you typed, for `Ctrl+R` (`"promptHistory": false` turns it off) |
|
|
309
|
+
| `keybindings.json` | key bindings |
|
|
310
|
+
| `themes/` | your own `/theme` themes |
|
|
311
|
+
| `plugins/` | installed plugins (a project may have its own `.robota/plugins/`) |
|
|
312
|
+
| `mcp-credentials/` | OAuth tokens for MCP servers, readable by you only |
|
|
1079
313
|
|
|
1080
|
-
|
|
1081
|
-
2. `~/.claude/settings.json` (user global, Claude Code compatible)
|
|
1082
|
-
3. `.robota/settings.json` (project, shared)
|
|
1083
|
-
4. `.robota/settings.local.json` (local, gitignored)
|
|
1084
|
-
5. `.claude/settings.json` (project, Claude Code compatible)
|
|
1085
|
-
6. `.claude/settings.local.json` (local, gitignored, Claude Code compatible)
|
|
314
|
+
## Use it from code
|
|
1086
315
|
|
|
1087
|
-
The
|
|
1088
|
-
|
|
1089
|
-
separately approved settings writer for the same authority.
|
|
316
|
+
The package also exports `startCli`, the function the `robota` executable runs, and its options
|
|
317
|
+
type `IStartCliOptions`. The package is ESM-only: load it with `import`, not `require()`.
|
|
1090
318
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
Robota admits project-controlled settings and executable contributions only after a host-owned grant
|
|
1094
|
-
for the canonical Git workspace identity. In a new or revoked workspace, interactive startup remains
|
|
1095
|
-
usable with project settings, hooks, plugins, skills, and provider overrides disabled. Headless startup
|
|
1096
|
-
fails closed until trust is granted:
|
|
319
|
+
## Work on the CLI in this repository
|
|
1097
320
|
|
|
1098
321
|
```bash
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
```
|
|
1103
|
-
|
|
1104
|
-
The grant survives process restart and is invalidated by repository replacement, revocation, or a
|
|
1105
|
-
trust-store error. Symlink aliases resolve to the canonical workspace; a different repository at the
|
|
1106
|
-
same textual path does not inherit the grant. `robota doctor` reports trust and endpoint provenance
|
|
1107
|
-
without printing credentials. If a lower-trust settings layer changes a provider endpoint without
|
|
1108
|
-
providing its own key, Robota removes the inherited key and reports `provider endpoint quarantined`.
|
|
1109
|
-
|
|
1110
|
-
```json
|
|
1111
|
-
{
|
|
1112
|
-
"defaultMode": "default",
|
|
1113
|
-
"language": "en",
|
|
1114
|
-
"currentProvider": "qwen-plus",
|
|
1115
|
-
"providers": {
|
|
1116
|
-
"qwen-plus": {
|
|
1117
|
-
"type": "qwen",
|
|
1118
|
-
"model": "qwen-plus",
|
|
1119
|
-
"apiKey": "$ENV:DASHSCOPE_API_KEY",
|
|
1120
|
-
"baseURL": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
|
1121
|
-
},
|
|
1122
|
-
"supergemma4-26b-uncensored-v2": {
|
|
1123
|
-
"type": "gemma",
|
|
1124
|
-
"model": "supergemma4-26b-uncensored-v2",
|
|
1125
|
-
"apiKey": "lm-studio",
|
|
1126
|
-
"baseURL": "http://localhost:1234/v1"
|
|
1127
|
-
},
|
|
1128
|
-
"gpt-4o": {
|
|
1129
|
-
"type": "openai",
|
|
1130
|
-
"model": "gpt-4o",
|
|
1131
|
-
"apiKey": "$ENV:OPENAI_API_KEY"
|
|
1132
|
-
},
|
|
1133
|
-
"claude-sonnet-4-6": {
|
|
1134
|
-
"type": "anthropic",
|
|
1135
|
-
"model": "claude-sonnet-4-6",
|
|
1136
|
-
"apiKey": "$ENV:ANTHROPIC_API_KEY"
|
|
1137
|
-
}
|
|
1138
|
-
},
|
|
1139
|
-
"permissions": {
|
|
1140
|
-
"allow": ["Bash(pnpm *)"],
|
|
1141
|
-
"deny": ["Bash(rm -rf *)"]
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
```
|
|
1145
|
-
|
|
1146
|
-
`currentProvider` selects a profile key from `providers`. The key is the stable profile identity, not
|
|
1147
|
-
the provider type; multiple profile keys may use the same provider type and model when they represent
|
|
1148
|
-
different credentials, endpoints, accounts, or operational defaults. Qwen Model Studio profiles use
|
|
1149
|
-
`type: "qwen"` with a DashScope-compatible `baseURL`; the API key is usually stored as
|
|
1150
|
-
`$ENV:DASHSCOPE_API_KEY`. DeepSeek profiles use `type: "deepseek"` with
|
|
1151
|
-
`https://api.deepseek.com` and `$ENV:DEEPSEEK_API_KEY`. Gemma-family LM Studio models use
|
|
1152
|
-
`type: "gemma"` so Robota can apply Gemma-specific channel-marker projection while still talking to
|
|
1153
|
-
the OpenAI-compatible `/v1/chat/completions` API through `baseURL`. Generic OpenAI-compatible profiles use
|
|
1154
|
-
`type: "openai"` and do not apply provider-specific projection. Use `--provider <profile>` for a
|
|
1155
|
-
one-shot invocation override; add `--set-current` only when the selected profile should become the
|
|
1156
|
-
persisted default. The legacy single-provider shape remains supported:
|
|
1157
|
-
|
|
1158
|
-
```json
|
|
1159
|
-
{
|
|
1160
|
-
"provider": {
|
|
1161
|
-
"name": "anthropic",
|
|
1162
|
-
"model": "claude-sonnet-4-6",
|
|
1163
|
-
"apiKey": "$ENV:ANTHROPIC_API_KEY"
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
```
|
|
1167
|
-
|
|
1168
|
-
## Context Discovery
|
|
1169
|
-
|
|
1170
|
-
With trusted project access, the CLI discovers and loads:
|
|
1171
|
-
|
|
1172
|
-
- **AGENTS.md** — walking only within the authenticated worktree root
|
|
1173
|
-
- **CLAUDE.md** — the same root-bounded discovery
|
|
1174
|
-
- **Project metadata** — from `package.json`, `tsconfig.json`
|
|
1175
|
-
|
|
1176
|
-
All context is assembled into the system prompt.
|
|
1177
|
-
|
|
1178
|
-
Ordinary prompts may also reference workspace-local files with path-like `@file` tokens, for
|
|
1179
|
-
example `@AGENTS.md` or `@docs/SPEC.md`. The CLI passes those prompts through unchanged; the SDK
|
|
1180
|
-
resolves bounded file content through the accepted project reader, sends the enriched prompt to the model, and
|
|
1181
|
-
records a structured file-reference event in the session history.
|
|
1182
|
-
|
|
1183
|
-
## Memory Management
|
|
1184
|
-
|
|
1185
|
-
- **Message windowing** — React state keeps the most recent 100 messages. Older messages are dropped from the render tree; full history remains in the session store.
|
|
1186
|
-
- **Tool state cleanup** — Completed tool execution states are trimmed to the most recent 50 entries.
|
|
1187
|
-
- **React.memo** — `MessageItem` uses `React.memo` to skip redundant re-renders.
|
|
1188
|
-
|
|
1189
|
-
## Session Logging
|
|
1190
|
-
|
|
1191
|
-
Trusted composition writes project session logs and resumable records through authority-backed
|
|
1192
|
-
`session-logs` and `sessions` state facets. Restricted composition opens no project log path and uses
|
|
1193
|
-
the user session store instead. Session records include messages, UI history, the exact system prompt,
|
|
1194
|
-
registered tool schemas, and background task snapshots; high-frequency streaming chunks remain in
|
|
1195
|
-
the separately injected JSONL sink.
|
|
1196
|
-
|
|
1197
|
-
## Architecture
|
|
1198
|
-
|
|
1199
|
-
The CLI is a pure TUI layer. All business logic lives in `@robota-sdk/agent-framework`'s `InteractiveSession`. `useInteractiveSession` is the sole React↔SDK bridge, converting SDK events to React state.
|
|
1200
|
-
|
|
322
|
+
pnpm install && pnpm build
|
|
323
|
+
pnpm cli:dev # run the CLI from source
|
|
324
|
+
pnpm cli:trust # trust this repository for the source CLI
|
|
1201
325
|
```
|
|
1202
|
-
bin.ts → cli.ts (arg parsing)
|
|
1203
|
-
└── ui/render.tsx → App.tsx (thin JSX shell)
|
|
1204
|
-
├── useInteractiveSession (ONLY React↔SDK bridge)
|
|
1205
|
-
│ ├── InteractiveSession (SDK)
|
|
1206
|
-
│ ├── CommandRegistry (SDK, re-exported by CLI)
|
|
1207
|
-
│ │ ├── BuiltinCommandSource (SDK, empty by default)
|
|
1208
|
-
│ │ ├── agent-command (./skills) (/skills command + virtual skill aliases)
|
|
1209
|
-
│ │ ├── PluginCommandSource (SDK, plugin skills)
|
|
1210
|
-
│ │ └── ICommandModule sources (/help, /compact, ...)
|
|
1211
|
-
│ └── SystemCommandExecutor (SDK)
|
|
1212
|
-
├── plugin-hooks-merger.ts (merges plugin hooks into SDK config)
|
|
1213
|
-
├── MessageList.tsx
|
|
1214
|
-
├── InputArea.tsx (CjkTextInput, bracketed paste, slash detection)
|
|
1215
|
-
├── StatusBar.tsx (activity, conditional mode, model, context %)
|
|
1216
|
-
├── PermissionPrompt.tsx (arrow-key Allow/Deny)
|
|
1217
|
-
├── SlashAutocomplete.tsx (command popup with scroll)
|
|
1218
|
-
├── DiffBlock.tsx (Edit tool diff display)
|
|
1219
|
-
├── MenuSelect.tsx (arrow-key menu, Plugin TUI)
|
|
1220
|
-
├── PluginTUI.tsx (plugin management screen stack)
|
|
1221
|
-
├── TextPrompt.tsx (text input for Plugin TUI)
|
|
1222
|
-
└── ConfirmPrompt.tsx (reusable yes/no prompt)
|
|
1223
|
-
```
|
|
1224
|
-
|
|
1225
|
-
## Dependencies
|
|
1226
|
-
|
|
1227
|
-
| Package | Purpose |
|
|
1228
|
-
| ----------------------------- | ----------------------------------------------------------------------------- |
|
|
1229
|
-
| `@robota-sdk/agent-framework` | Session factory, query, config, context |
|
|
1230
|
-
| `@robota-sdk/agent-core` | Types (TPermissionMode, TToolArgs) |
|
|
1231
|
-
| `@robota-sdk/agent-framework` | Headless runner and registry for print mode (`-p`); terminal I/O is CLI-local |
|
|
1232
|
-
| `ink` 7, `react` 19.2+ | TUI rendering |
|
|
1233
|
-
| `chalk` | Terminal colors |
|
|
1234
|
-
| `marked`, `marked-terminal` | Markdown parsing and terminal rendering |
|
|
1235
|
-
| `string-width` | Unicode-aware string width (CJK support) |
|
|
1236
326
|
|
|
1237
327
|
## Documentation
|
|
1238
328
|
|
|
1239
|
-
|
|
329
|
+
- [CLI guide](../../content/guide/cli.md) — every command, flag and setting
|
|
330
|
+
- [Sessions and the daemon](../../content/guide/sessions-and-daemon.md)
|
|
331
|
+
- [Permissions and hooks](../../content/guide/permissions-and-hooks.md)
|
|
332
|
+
- [Providers](../../content/guide/providers.md) and [Local LLM setup](../../content/guide/local-llm.md)
|
|
333
|
+
- [MCP](../../content/guide/mcp.md)
|
|
334
|
+
- [Devices and remote control](../../content/guide/devices-and-remote.md)
|
|
335
|
+
- [SPEC.md](./docs/SPEC.md) — what this package owns and guarantees
|
|
1240
336
|
|
|
1241
337
|
## License
|
|
1242
338
|
|
|
1243
|
-
Robota is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a
|
|
339
|
+
Robota is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a
|
|
340
|
+
[commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
|