@robota-sdk/agent-cli 3.0.0-beta.79 → 3.0.0-beta.81
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/README.md +740 -55
- package/dist/node/bin.js +3 -406
- package/dist/node/bounded-output-DpjpS98g-DFgAppgl.js +2 -0
- package/dist/node/bounded-output-DpjpS98g-DFgAppgl.js.map +1 -0
- package/dist/node/bounded-output-DpjpS98g-DoRuRGhV.js +2 -0
- package/dist/node/bounded-output-DpjpS98g-yPybHprY.cjs +1 -0
- package/dist/node/cli-core-Bah38oug.js +2795 -0
- package/dist/node/command-executor-DV-H2oD6-BfKoGoFw.js +2 -0
- package/dist/node/command-executor-DV-H2oD6-OKy8pwYH.js +2 -0
- package/dist/node/command-executor-DV-H2oD6-OKy8pwYH.js.map +1 -0
- package/dist/node/command-executor-DV-H2oD6-iQAXtTLY.cjs +1 -0
- package/dist/node/headless.js +4 -0
- package/dist/node/http-executor-cWzI2svn-C7F17ZGz.cjs +1 -0
- package/dist/node/http-executor-cWzI2svn-TG_TMYKh.js +2 -0
- package/dist/node/http-executor-cWzI2svn-TG_TMYKh.js.map +1 -0
- package/dist/node/http-executor-cWzI2svn-Ype0naht.js +2 -0
- package/dist/node/index.cjs +2641 -251
- package/dist/node/index.d.cts +3421 -0
- package/dist/node/index.d.cts.map +1 -0
- package/dist/node/index.d.ts +3412 -5
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2641 -251
- package/dist/node/index.js.map +1 -1
- package/dist/node/node-2-nrieFn.js +2 -0
- package/dist/node/node-2-nrieFn.js.map +1 -0
- package/dist/node/node-C-hnFnOP.js +67 -0
- package/dist/node/node-CFTax5Wl.cjs +1 -0
- package/dist/node/node-CJnrbkAS.js +14 -0
- package/dist/node/node-CJnrbkAS.js.map +1 -0
- package/dist/node/node-ChG9Tg1I.js +2 -0
- package/dist/node/node-DDl02brx.cjs +66 -0
- package/dist/node/node-DIRGC_1P.js +67 -0
- package/dist/node/node-DIRGC_1P.js.map +1 -0
- package/dist/node/node-OBnZskvR.cjs +1 -0
- package/dist/node/node-bJ0lEuNF.js +2 -0
- package/dist/node/node-bJ0lEuNF.js.map +1 -0
- package/dist/node/node-tf433Aey.cjs +13 -0
- package/dist/node/node-uwhEt6sT.js +14 -0
- package/dist/node/rolldown-runtime-C9xYM0wc.js +1 -0
- package/dist/node/rolldown-runtime-DK3Fl9T5-BIInC43l.cjs +1 -0
- package/dist/node/rolldown-runtime-DK3Fl9T5-BeX3Bzvn.js +2 -0
- package/dist/node/rolldown-runtime-DK3Fl9T5-DK3Fl9T5.js +2 -0
- package/dist/node/rolldown-runtime-DK3Fl9T5-DK3Fl9T5.js.map +1 -0
- package/dist/node/rolldown-runtime-rs7quPpn.js +2 -0
- package/dist/node/verdict-decoder-Dk_w2NG9-BKWMtxp8.js +2 -0
- package/dist/node/verdict-decoder-Dk_w2NG9-Bka7Cldj.js +2 -0
- package/dist/node/verdict-decoder-Dk_w2NG9-Bka7Cldj.js.map +1 -0
- package/dist/node/verdict-decoder-Dk_w2NG9-DNTeVdQ8.cjs +1 -0
- package/dist/web/assets/index-8_Slbxe7.css +1 -0
- package/dist/web/assets/index-Cgu5C1kn.js +77 -0
- package/dist/web/index.html +3 -3
- package/package.json +106 -39
- package/dist/node/bin.d.ts +0 -2
- package/dist/node/bin.js.map +0 -1
- package/dist/web/assets/index-DiahfakU.css +0 -2
- package/dist/web/assets/index-LMW0IDmj.js +0 -37
package/README.md
CHANGED
|
@@ -21,16 +21,28 @@ AI coding assistant CLI built on Robota SDK. Loads AGENTS.md/CLAUDE.md for proje
|
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
import { createAgentRuntime } from '@robota-sdk/agent-framework';
|
|
24
|
-
import { createAnthropicProvider } from '@robota-sdk/agent-provider';
|
|
24
|
+
import { createAnthropicProvider } from '@robota-sdk/agent-provider-anthropic';
|
|
25
25
|
|
|
26
26
|
const runtime = createAgentRuntime({
|
|
27
27
|
cwd: process.cwd(),
|
|
28
28
|
provider: createAnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY }),
|
|
29
|
+
// projectAccess: hostWorkspaceDecision,
|
|
29
30
|
});
|
|
30
31
|
const session = runtime.createSession({ permissionMode: 'bypassPermissions' });
|
|
31
|
-
|
|
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');
|
|
32
38
|
```
|
|
33
39
|
|
|
40
|
+
A bare `cwd` is provenance, not project authority. Without a host-issued
|
|
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
|
+
|
|
34
46
|
## Prerequisites
|
|
35
47
|
|
|
36
48
|
Node.js **22 or higher** is required. The TUI renderer ([ink 7.x](https://github.com/vadimdemedes/ink)) requires Node.js 22+.
|
|
@@ -51,10 +63,11 @@ volta install node@22
|
|
|
51
63
|
|
|
52
64
|
## Demo
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
<!-- Run `pnpm demo:record` to capture a demo recording — see docs/DEMO-SCRIPT.md for instructions -->
|
|
66
|
+

|
|
56
67
|
|
|
57
|
-
|
|
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).
|
|
58
71
|
|
|
59
72
|
## Installation
|
|
60
73
|
|
|
@@ -96,11 +109,19 @@ export ANTHROPIC_API_KEY=sk-ant-...
|
|
|
96
109
|
## Development Setup (Monorepo)
|
|
97
110
|
|
|
98
111
|
```bash
|
|
99
|
-
# Build
|
|
100
|
-
pnpm build
|
|
101
|
-
pnpm --filter @robota-sdk/agent-cli build
|
|
112
|
+
# Build all packages, including the CLI and its web monitor
|
|
113
|
+
pnpm build
|
|
102
114
|
```
|
|
103
115
|
|
|
116
|
+
`pnpm build` runs each package's own build in dependency order. The CLI build runs `tsdown` and then
|
|
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.
|
|
124
|
+
|
|
104
125
|
## Usage (Monorepo)
|
|
105
126
|
|
|
106
127
|
```bash
|
|
@@ -133,17 +154,401 @@ robota --max-turns <n> # Limit agentic turns per interaction
|
|
|
133
154
|
robota --goal "<objective>" # Pursue an autonomous goal headlessly until satisfied or a bound
|
|
134
155
|
robota --goal-max-iterations <n> # Per-goal turn budget (default 25)
|
|
135
156
|
robota --output-format <fmt> # text | json | stream-json (print mode)
|
|
157
|
+
robota --effort <level> # auto | none | minimal | low | medium | high | xhigh | max
|
|
136
158
|
robota --system-prompt <text> # Replace system prompt (print mode)
|
|
137
159
|
robota --append-system-prompt <text> # Append to system prompt (print mode)
|
|
138
160
|
robota --model claude-sonnet-4-6 # Override provider model for this session
|
|
139
161
|
robota --allowed-tools "Bash,Read" # Whitelist specific tools
|
|
140
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
|
|
141
183
|
robota --reset # Delete user settings and exit
|
|
142
184
|
robota --check-update # Check npm for a newer CLI version and exit
|
|
143
185
|
robota --disable-update-check # Skip interactive startup update check for this run
|
|
144
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
|
+
```
|
|
190
|
+
|
|
191
|
+
### Personal Usage
|
|
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.
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
robota doctor # full report
|
|
382
|
+
robota doctor --repair settings.user.robota # one allowlisted repair, asks [y/N] first
|
|
383
|
+
robota doctor --repair storage.user --yes # no prompt (required in a non-interactive shell)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Repairs are limited to an empty user settings file (rewritten as `{}`) and a missing or too-open
|
|
387
|
+
user storage directory; everything else is reported with the path to fix. `/doctor` runs the same
|
|
388
|
+
report inside a session, and `/doctor repair <check-id>` asks before writing.
|
|
389
|
+
|
|
390
|
+
### MCP Servers
|
|
391
|
+
|
|
392
|
+
#### Serve Robota to an MCP host
|
|
393
|
+
|
|
394
|
+
Install `@robota-sdk/agent-cli`, configure a provider with `robota --configure`, and grant the
|
|
395
|
+
intended project with `robota trust --yes` before starting a headless server. Resolve the actual
|
|
396
|
+
executable (`command -v robota`) and use its **absolute path** in the host configuration. For an
|
|
397
|
+
MCP client that supports a child-process working directory, configure:
|
|
398
|
+
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"mcpServers": {
|
|
402
|
+
"robota": {
|
|
403
|
+
"command": "/absolute/path/to/robota",
|
|
404
|
+
"args": ["mcp", "serve"],
|
|
405
|
+
"cwd": "/absolute/path/to/trusted/project"
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
The host must launch the process in the intended project directory. Robota uses that inherited
|
|
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:
|
|
415
|
+
|
|
416
|
+
```sh
|
|
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
|
+
```
|
|
420
|
+
|
|
421
|
+
The host receives the canonical runtime tool catalog plus `robota_submit`. Model-invocable commands
|
|
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
|
+
```
|
|
455
|
+
|
|
456
|
+
- `--http-public-url` is the `https` address clients use. It is also the token audience and the
|
|
457
|
+
`resource` Robota advertises. Robota serves MCP at its path (`/robota/mcp` above) and the RFC 9728
|
|
458
|
+
protected-resource metadata at `/.well-known/oauth-protected-resource` followed by that path. The
|
|
459
|
+
proxy must forward both paths unchanged (do not strip the prefix) and must preserve the client's
|
|
460
|
+
`Host` header. Robota checks `Host` and `Origin` against the public URL, not the address it binds.
|
|
461
|
+
- `--oauth-issuer`, `--oauth-scopes` and `--oauth-allowed-subjects` are all required. A token must
|
|
462
|
+
be an RFC 9068 access token from that issuer, addressed to the public URL, carrying every listed
|
|
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
|
+
```
|
|
503
|
+
|
|
504
|
+
Use `--no-browser` when the browser runs on another machine (for example over SSH). After you
|
|
505
|
+
approve, the browser is sent to a `http://127.0.0.1:<port>/callback` address that may not load; copy
|
|
506
|
+
that full address and paste it at the prompt (the input is not echoed). It is accepted only if it is
|
|
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):
|
|
533
|
+
|
|
534
|
+
```json
|
|
535
|
+
{
|
|
536
|
+
"mcp": {
|
|
537
|
+
"autoBackgroundMs": 120000,
|
|
538
|
+
"callTimeoutMs": 600000
|
|
539
|
+
}
|
|
540
|
+
}
|
|
145
541
|
```
|
|
146
542
|
|
|
543
|
+
- `autoBackgroundMs` (default 120000 ms): a tool call still running at this point is handed to a
|
|
544
|
+
`tool-invocation` background task; `/tasks` shows it like any other background task. `0` disables
|
|
545
|
+
the handoff.
|
|
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
|
+
|
|
147
552
|
### CLI Updates
|
|
148
553
|
|
|
149
554
|
Robota can check npm for a newer `@robota-sdk/agent-cli` version:
|
|
@@ -214,18 +619,19 @@ Non-interactive/headless mode never prompts. Configure a provider ahead of time
|
|
|
214
619
|
|
|
215
620
|
## Built-in Tools
|
|
216
621
|
|
|
217
|
-
The AI agent can invoke
|
|
622
|
+
The AI agent can invoke 9 distinct local tools (the runtime registers 10 tool names — `Bash` is the model-familiar alias of `Shell`):
|
|
218
623
|
|
|
219
|
-
| Tool
|
|
220
|
-
|
|
|
221
|
-
| `Bash`
|
|
222
|
-
| `Read`
|
|
223
|
-
| `Write`
|
|
224
|
-
| `Edit`
|
|
225
|
-
| `Glob`
|
|
226
|
-
| `Grep`
|
|
227
|
-
| `WebFetch`
|
|
228
|
-
| `WebSearch`
|
|
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` |
|
|
229
635
|
|
|
230
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).
|
|
231
637
|
|
|
@@ -240,6 +646,95 @@ The AI agent can invoke 8 local tools:
|
|
|
240
646
|
- Background subagents are real runtime jobs with transcripts and resumable task snapshots.
|
|
241
647
|
- Explicit multi-agent requests use the `/agent` command module batch path through the SDK runtime.
|
|
242
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
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Every background row carries its state word beside the glyph (`working`, `needs-input`,
|
|
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.
|
|
680
|
+
|
|
681
|
+
Searching the conversation itself needs no viewer: the TUI never switches to the alternate screen,
|
|
682
|
+
so every message of a resumed session is in your terminal's own scrollback and search.
|
|
683
|
+
|
|
684
|
+
### Themes
|
|
685
|
+
|
|
686
|
+
`/theme` opens a picker: moving the highlight previews that theme in the live region — the input
|
|
687
|
+
frame, the status bar and the overlay itself — so you judge a colour scheme against the thing it
|
|
688
|
+
applies to rather than a swatch. `Enter` applies it, `Esc` leaves the previous one in place. The
|
|
689
|
+
transcript above keeps the colours it was written in, because the terminal owns those lines once
|
|
690
|
+
they are printed.
|
|
691
|
+
|
|
692
|
+
Four built-ins ship: `dark` (what Robota has always looked like), `light`, and `dark-daltonized` /
|
|
693
|
+
`light-daltonized`, which avoid the red/green distinction entirely — blue for "good", orange for
|
|
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:
|
|
708
|
+
|
|
709
|
+
```json
|
|
710
|
+
{
|
|
711
|
+
"name": "Mine",
|
|
712
|
+
"base": "light",
|
|
713
|
+
"overrides": { "colors": { "text": { "accent": "#56b4e9" } } }
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
`base` is any built-in and `overrides` is a sparse map over the same token paths the built-ins use —
|
|
718
|
+
`colors`, `markdown`, `syntax` and `motion` — so you change the colours you care about and inherit
|
|
719
|
+
the rest. Values use Ink's colour grammar: a chalk colour name, `#rgb`, `#rrggbb`, `ansi256(n)` or
|
|
720
|
+
`rgb(r,g,b)`. A raw escape sequence is not in that grammar, so it cannot enter through a theme.
|
|
721
|
+
|
|
722
|
+
A plugin ships themes the same way, in its own `themes/` directory; they are listed as
|
|
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
|
+
|
|
243
738
|
## Permission System
|
|
244
739
|
|
|
245
740
|
Every tool call passes through a three-step permission gate:
|
|
@@ -262,7 +757,7 @@ Every tool call passes through a three-step permission gate:
|
|
|
262
757
|
Use the `/permissions` slash command:
|
|
263
758
|
|
|
264
759
|
```
|
|
265
|
-
> /permissions # Show
|
|
760
|
+
> /permissions # Show mode, rules by settings file, approvals, recent denials
|
|
266
761
|
> /permissions plan # Switch to plan (read-only)
|
|
267
762
|
> /permissions bypassPermissions # Skip all prompts
|
|
268
763
|
```
|
|
@@ -293,6 +788,7 @@ Pattern syntax: `ToolName` matches any invocation; `ToolName(pattern)` matches o
|
|
|
293
788
|
| Key | Action |
|
|
294
789
|
| ---------- | ----------------------------------------------------------- |
|
|
295
790
|
| Enter | Submit input |
|
|
791
|
+
| Ctrl+R | Search prompt history (see "Prompt history") |
|
|
296
792
|
| ESC | Abort current execution (graceful — saves partial response) |
|
|
297
793
|
| Ctrl+C | Exit process immediately |
|
|
298
794
|
| Up/Down | Navigate visual lines in wrapped multi-line input |
|
|
@@ -337,6 +833,20 @@ The CLI supports continuing, resuming, forking, and naming sessions.
|
|
|
337
833
|
| `/resume` | List recent sessions and resume one |
|
|
338
834
|
| `/rename <name>` | Rename the current session |
|
|
339
835
|
|
|
836
|
+
### Moving to another directory (`/cd`)
|
|
837
|
+
|
|
838
|
+
`/cd <directory>` continues the conversation in another directory. Robota starts again there, as if
|
|
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
|
+
|
|
340
850
|
### Session Name Display
|
|
341
851
|
|
|
342
852
|
When a session has a name, it appears in three places:
|
|
@@ -345,31 +855,71 @@ When a session has a name, it appears in three places:
|
|
|
345
855
|
- **Terminal title** — updated via ANSI escape sequences
|
|
346
856
|
- **StatusBar** — displayed alongside activity, model, and context usage
|
|
347
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.
|
|
862
|
+
|
|
863
|
+
```bash
|
|
864
|
+
robota open 'robota://open?v=1&prompt=Summarize%20the%20README&cwd=/absolute/path/to/repo'
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
| Key | Meaning |
|
|
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
|
+
|
|
348
895
|
## Slash Commands
|
|
349
896
|
|
|
350
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.
|
|
351
898
|
|
|
352
899
|
### Session & Context
|
|
353
900
|
|
|
354
|
-
| Command | Description
|
|
355
|
-
| ------------------------- |
|
|
356
|
-
| `/clear` | Clear conversation history
|
|
357
|
-
| `/compact [instructions]` | Compress context window
|
|
358
|
-
| `/context` | Context window details, reference inventory, and auto-compact controls
|
|
359
|
-
| `/cost` | Show session token usage and cost
|
|
360
|
-
| `/
|
|
361
|
-
| `/
|
|
362
|
-
| `/
|
|
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 |
|
|
363
912
|
|
|
364
913
|
### Providers & Settings
|
|
365
914
|
|
|
366
|
-
| Command
|
|
915
|
+
| Command | Description |
|
|
367
916
|
| ------------------------ | -------------------------------------------------------------------- | ------- | -------------------------------------------------- |
|
|
368
917
|
| `/provider [subcommand]` | Manage provider profiles: `list`, `switch`, `add`, `test`, `current` |
|
|
369
|
-
| `/mode [mode]`
|
|
370
|
-
| `/permissions [mode]`
|
|
371
|
-
| `/
|
|
372
|
-
| `/
|
|
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 |
|
|
373
923
|
| `/statusline [on | off | reset]` | Configure status-line fields (model, context, git) |
|
|
374
924
|
|
|
375
925
|
### Tools & Memory
|
|
@@ -383,6 +933,30 @@ Typing `/` in the TUI opens an autocomplete popup. Arrow keys navigate, Tab inse
|
|
|
383
933
|
| `/skills [name]` | List registered skills or activate one by name |
|
|
384
934
|
| `/plugin [subcommand]` | Plugin management |
|
|
385
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
|
+
|
|
386
960
|
### Utility
|
|
387
961
|
|
|
388
962
|
| Command | Description |
|
|
@@ -391,7 +965,97 @@ Typing `/` in the TUI opens an autocomplete popup. Arrow keys navigate, Tab inse
|
|
|
391
965
|
| `/reset` | Delete user settings and return to first-run state |
|
|
392
966
|
| `/exit` | Exit CLI |
|
|
393
967
|
|
|
394
|
-
Skill commands
|
|
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
|
+
…
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
Your own turns still read `You:`. The name in the label is **derived from the peer's session id** —
|
|
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.
|
|
395
1059
|
|
|
396
1060
|
## Plugin Management
|
|
397
1061
|
|
|
@@ -420,6 +1084,29 @@ Settings are merged in this order, from lowest to highest priority:
|
|
|
420
1084
|
5. `.claude/settings.json` (project, Claude Code compatible)
|
|
421
1085
|
6. `.claude/settings.local.json` (local, gitignored, Claude Code compatible)
|
|
422
1086
|
|
|
1087
|
+
The two user layers are always host-owned. The four project layers participate only when the CLI host
|
|
1088
|
+
supplies trusted project access; Restricted composition does not probe them. Project writes require a
|
|
1089
|
+
separately approved settings writer for the same authority.
|
|
1090
|
+
|
|
1091
|
+
### Workspace trust
|
|
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:
|
|
1097
|
+
|
|
1098
|
+
```bash
|
|
1099
|
+
robota trust status
|
|
1100
|
+
robota trust --yes
|
|
1101
|
+
robota trust revoke --yes
|
|
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
|
+
|
|
423
1110
|
```json
|
|
424
1111
|
{
|
|
425
1112
|
"defaultMode": "default",
|
|
@@ -480,17 +1167,17 @@ persisted default. The legacy single-provider shape remains supported:
|
|
|
480
1167
|
|
|
481
1168
|
## Context Discovery
|
|
482
1169
|
|
|
483
|
-
|
|
1170
|
+
With trusted project access, the CLI discovers and loads:
|
|
484
1171
|
|
|
485
|
-
- **AGENTS.md** — walking
|
|
486
|
-
- **CLAUDE.md** — same
|
|
1172
|
+
- **AGENTS.md** — walking only within the authenticated worktree root
|
|
1173
|
+
- **CLAUDE.md** — the same root-bounded discovery
|
|
487
1174
|
- **Project metadata** — from `package.json`, `tsconfig.json`
|
|
488
1175
|
|
|
489
1176
|
All context is assembled into the system prompt.
|
|
490
1177
|
|
|
491
1178
|
Ordinary prompts may also reference workspace-local files with path-like `@file` tokens, for
|
|
492
1179
|
example `@AGENTS.md` or `@docs/SPEC.md`. The CLI passes those prompts through unchanged; the SDK
|
|
493
|
-
resolves bounded file content
|
|
1180
|
+
resolves bounded file content through the accepted project reader, sends the enriched prompt to the model, and
|
|
494
1181
|
records a structured file-reference event in the session history.
|
|
495
1182
|
|
|
496
1183
|
## Memory Management
|
|
@@ -501,9 +1188,11 @@ records a structured file-reference event in the session history.
|
|
|
501
1188
|
|
|
502
1189
|
## Session Logging
|
|
503
1190
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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.
|
|
507
1196
|
|
|
508
1197
|
## Architecture
|
|
509
1198
|
|
|
@@ -535,19 +1224,15 @@ bin.ts → cli.ts (arg parsing)
|
|
|
535
1224
|
|
|
536
1225
|
## Dependencies
|
|
537
1226
|
|
|
538
|
-
| Package
|
|
539
|
-
|
|
|
540
|
-
| `@robota-sdk/agent-framework`
|
|
541
|
-
| `@robota-sdk/agent-core`
|
|
542
|
-
| `@robota-sdk/agent-
|
|
543
|
-
| `ink` 7, `react` 19.2+
|
|
544
|
-
| `
|
|
545
|
-
| `
|
|
546
|
-
| `
|
|
547
|
-
| `ink-text-input` | Base text input (extended by CjkTextInput) |
|
|
548
|
-
| `marked`, `marked-terminal` | Markdown parsing and terminal rendering |
|
|
549
|
-
| `cli-highlight` | Syntax highlighting for code blocks |
|
|
550
|
-
| `string-width` | Unicode-aware string width (CJK support) |
|
|
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) |
|
|
551
1236
|
|
|
552
1237
|
## Documentation
|
|
553
1238
|
|