@robota-sdk/agent-cli 3.0.0-beta.10 → 3.0.0-beta.101
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 +3008 -0
- package/LICENSE +661 -21
- package/README.md +527 -170
- package/bin/agent.cjs +39 -0
- package/dist/node/artifact-DrPhOb_v.d.ts +749 -0
- package/dist/node/artifact-DrPhOb_v.d.ts.map +1 -0
- package/dist/node/bin.js +35 -19
- package/dist/node/bounded-output-BdWv9SX3-28em7iHq.js +2 -0
- package/dist/node/bounded-output-BdWv9SX3-28em7iHq.js.map +1 -0
- package/dist/node/bounded-output-BdWv9SX3-C4ucXwLR.js +2 -0
- package/dist/node/cli-core-CIzUq54B.js +2920 -0
- package/dist/node/command-executor-D_UBZHxh-CVZipoOV.js +2 -0
- package/dist/node/command-executor-D_UBZHxh-CVZipoOV.js.map +1 -0
- package/dist/node/command-executor-D_UBZHxh-D7UrdAlN.js +2 -0
- package/dist/node/desktop-host.d.ts +53 -0
- package/dist/node/desktop-host.d.ts.map +1 -0
- package/dist/node/desktop-host.js +2 -0
- package/dist/node/desktop-host.js.map +1 -0
- package/dist/node/headless.js +4 -0
- package/dist/node/host.d.ts +3 -0
- package/dist/node/host.js +1 -0
- package/dist/node/http-executor-ADn4locH-D-8crzF8.js +2 -0
- package/dist/node/http-executor-ADn4locH-D-8crzF8.js.map +1 -0
- package/dist/node/http-executor-ADn4locH-uz5KV6N-.js +2 -0
- package/dist/node/index.d.ts +790 -49
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +6 -13
- package/dist/node/index.js.map +1 -0
- package/dist/node/node-AQEjsK5o.js +2 -0
- package/dist/node/node-AQEjsK5o.js.map +1 -0
- package/dist/node/node-B5wKOmx1.js +165 -0
- package/dist/node/node-B5wKOmx1.js.map +1 -0
- package/dist/node/node-BQfSVkbA.js +2 -0
- package/dist/node/node-BRrU0Q8C.js +165 -0
- package/dist/node/node-CvUY6TbD.js +15 -0
- package/dist/node/node-DQ4XoykT.js +15 -0
- package/dist/node/node-DQ4XoykT.js.map +1 -0
- package/dist/node/product-host-Btm4B-p5.js +2954 -0
- package/dist/node/product-host-Btm4B-p5.js.map +1 -0
- package/dist/node/product-host-Cle0fPIc.d.ts +4691 -0
- package/dist/node/product-host-Cle0fPIc.d.ts.map +1 -0
- package/dist/node/rolldown-runtime-C9xYM0wc.js +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-Dz_rjoIZ-DA8BKB83.js +2 -0
- package/dist/node/verdict-decoder-Dz_rjoIZ-DA8BKB83.js.map +1 -0
- package/dist/node/verdict-decoder-Dz_rjoIZ-qM0jJVsB.js +2 -0
- package/dist/web/app-sandbox.html +145 -0
- 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-2GhVGsHN.js +314 -0
- package/dist/web/assets/index-BSxTg2Py.css +1 -0
- package/dist/web/index.html +15 -0
- package/package.json +203 -34
- package/scripts/koffi-bun-plugin.mjs +116 -0
- package/scripts/native-build.d.mts +19 -0
- package/scripts/native-build.mjs +72 -0
- package/scripts/qualify-koffi-gc.mjs +28 -0
- package/dist/node/bin.cjs +0 -1368
- package/dist/node/bin.d.cts +0 -1
- package/dist/node/bin.d.ts +0 -1
- package/dist/node/chunk-UT4RQDTI.js +0 -1337
- package/dist/node/index.cjs +0 -1375
- package/dist/node/index.d.cts +0 -49
package/README.md
CHANGED
|
@@ -1,254 +1,611 @@
|
|
|
1
|
+
**Language:** [English](README.md) | [Korean](docs/README-KO.md)
|
|
2
|
+
|
|
1
3
|
# @robota-sdk/agent-cli
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
`robota` is the configurable terminal interface for Robota, assembled from the
|
|
6
|
+
same TypeScript libraries you can embed. It is a coding-capable agent within the environment whose
|
|
7
|
+
direction is [our agents developing and advancing our agents](../../VISION.md). Autonomous
|
|
8
|
+
self-evolution remains an ambition; the behavior below describes the current CLI. It reads your
|
|
9
|
+
project, edits files and runs commands under a permission system you control, and works with
|
|
10
|
+
Anthropic, OpenAI, Gemini, DeepSeek, Qwen and local OpenAI-compatible models.
|
|
4
11
|
|
|
5
|
-
|
|
12
|
+
The CLI is assembled from the same packages you can use in your own app: `@robota-sdk/agent-framework`
|
|
13
|
+
for the session, `@robota-sdk/agent-ui-terminal` for the terminal UI, and one package per model
|
|
14
|
+
provider. To build your own agent rather than use this one, start with the
|
|
15
|
+
[SDK guide](../../content/guide/sdk.md).
|
|
6
16
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
npm install -g @robota-sdk/agent-cli
|
|
17
|
+
> **Beta.** Behavior may change before the stable release. Please
|
|
18
|
+
> [report issues](https://github.com/woojubb/robota/issues).
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
npx @robota-sdk/agent-cli
|
|
13
|
-
```
|
|
20
|
+
## Install
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
Requires Node.js 22.12.0 or later.
|
|
16
23
|
|
|
17
24
|
```bash
|
|
18
|
-
robota
|
|
19
|
-
robota
|
|
20
|
-
robota -p "List all files" # Print mode (one-shot, exit after response)
|
|
25
|
+
npm install -g @robota-sdk/agent-cli # installs the `robota` command
|
|
26
|
+
npx @robota-sdk/agent-cli # or run it once without installing
|
|
21
27
|
```
|
|
22
28
|
|
|
23
|
-
|
|
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.
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
| ------------------- | ----------------- | -------- |
|
|
27
|
-
| `ANTHROPIC_API_KEY` | Anthropic API key | Yes |
|
|
32
|
+
## First run
|
|
28
33
|
|
|
29
|
-
|
|
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 `<configured-user-state-dir>/settings.json`.
|
|
30
39
|
|
|
31
40
|
```bash
|
|
32
|
-
|
|
41
|
+
cd my-project
|
|
42
|
+
robota
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
|
|
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:
|
|
36
48
|
|
|
37
49
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# 2. Build dependencies and CLI
|
|
43
|
-
pnpm build:deps
|
|
44
|
-
pnpm --filter @robota-sdk/agent-cli build
|
|
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
|
|
45
54
|
```
|
|
46
55
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# From monorepo root
|
|
51
|
-
cd packages/agent-cli
|
|
56
|
+
`robota init` writes a starter `AGENTS.md` and `<configured-project-state-dir>/settings.json` for the current project.
|
|
57
|
+
`robota --configure` reruns the interactive provider setup, and `robota --reset` deletes
|
|
58
|
+
`<configured-user-state-dir>/settings.json`.
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
pnpm dev
|
|
60
|
+
## What you can do
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
pnpm start
|
|
62
|
+
### Work in the terminal UI
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```
|
|
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 `<configured-user-state-dir>/keybindings.json` (see the
|
|
67
|
+
[keybindings guide](../../content/guide/keybindings.md)).
|
|
64
68
|
|
|
65
|
-
|
|
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.
|
|
66
73
|
|
|
74
|
+
```bash
|
|
75
|
+
robota # new session
|
|
76
|
+
robota --permission-mode acceptEdits
|
|
77
|
+
robota --screen-reader # plain-text mode for screen readers
|
|
67
78
|
```
|
|
68
|
-
robota # Interactive REPL (default mode)
|
|
69
|
-
robota "prompt" # REPL with initial prompt
|
|
70
|
-
robota -p "prompt" # Print mode (one-shot, exit after response)
|
|
71
|
-
robota -c # Continue last session
|
|
72
|
-
robota -r <session-id> # Resume session by ID
|
|
73
|
-
robota --model <model> # Model override (e.g., claude-sonnet-4-6)
|
|
74
|
-
robota --permission-mode <mode> # plan | default | acceptEdits | bypassPermissions
|
|
75
|
-
robota --max-turns <n> # Limit agentic turns per interaction
|
|
76
|
-
robota --version # Show version
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Built-in Tools
|
|
80
79
|
|
|
81
|
-
|
|
80
|
+
### Run one prompt from a script
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| `Bash` | Execute shell commands | `command` |
|
|
86
|
-
| `Read` | Read file contents with line numbers | `filePath` |
|
|
87
|
-
| `Write` | Write content to a file | `filePath` |
|
|
88
|
-
| `Edit` | Replace a string in a file | `filePath` |
|
|
89
|
-
| `Glob` | Find files matching a pattern | `pattern` |
|
|
90
|
-
| `Grep` | Search file contents with regex | `pattern` |
|
|
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.
|
|
91
84
|
|
|
92
|
-
|
|
85
|
+
```bash
|
|
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
|
|
91
|
+
```
|
|
93
92
|
|
|
94
|
-
|
|
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.
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
2. **Allow list** — if any allow pattern matches, the action is auto-approved
|
|
98
|
-
3. **Mode policy** — the active permission mode determines the decision
|
|
101
|
+
### Keep sessions, run them in the background, share a daemon
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
Sessions are saved, so you can come back to them.
|
|
101
104
|
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
```bash
|
|
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
|
|
106
110
|
```
|
|
107
111
|
|
|
108
|
-
|
|
109
|
-
|
|
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.
|
|
110
115
|
|
|
111
|
-
|
|
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:
|
|
112
119
|
|
|
113
|
-
|
|
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
|
|
126
|
+
```
|
|
114
127
|
|
|
115
|
-
|
|
116
|
-
| ------------------- | -------- | :------------: | :--------: | :-----: |
|
|
117
|
-
| `plan` | safe | auto | deny | deny |
|
|
118
|
-
| `default` | moderate | auto | approve | approve |
|
|
119
|
-
| `acceptEdits` | full | auto | auto | approve |
|
|
120
|
-
| `bypassPermissions` | — | auto | auto | auto |
|
|
128
|
+
See [Sessions and the daemon](../../content/guide/sessions-and-daemon.md).
|
|
121
129
|
|
|
122
|
-
|
|
123
|
-
- **approve** — user is prompted to allow or deny
|
|
124
|
-
- **deny** — tool is blocked silently (no prompt shown)
|
|
130
|
+
### Control what the agent may do
|
|
125
131
|
|
|
126
|
-
|
|
132
|
+
Every tool call passes through deny rules, ask rules, allow rules and then the permission mode.
|
|
127
133
|
|
|
128
|
-
|
|
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 |
|
|
129
141
|
|
|
130
|
-
|
|
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:
|
|
131
145
|
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"permissions": {
|
|
149
|
+
"allow": ["Bash(pnpm *)", "Bash(git status)"],
|
|
150
|
+
"ask": ["Bash(git push *)"],
|
|
151
|
+
"deny": ["Bash(rm -rf *)", "Write(.env)"]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
132
154
|
```
|
|
133
|
-
> /mode # Show current mode
|
|
134
|
-
Current permission mode: default
|
|
135
155
|
|
|
136
|
-
|
|
137
|
-
|
|
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`, `<configured-project-state-dir>`,
|
|
158
|
+
`.claude`, `.agents` or shell and tool configuration files.
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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.
|
|
142
164
|
|
|
143
|
-
|
|
165
|
+
Workspace trust is granted per Git worktree and kept in `<configured-user-state-dir>/workspace-trust.json`:
|
|
144
166
|
|
|
145
167
|
```bash
|
|
146
|
-
robota --
|
|
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
|
|
147
171
|
```
|
|
148
172
|
|
|
149
|
-
|
|
173
|
+
See [Permissions and hooks](../../content/guide/permissions-and-hooks.md).
|
|
174
|
+
|
|
175
|
+
### Choose providers and models
|
|
150
176
|
|
|
151
|
-
|
|
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:
|
|
180
|
+
|
|
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` |
|
|
152
189
|
|
|
153
190
|
```json
|
|
154
191
|
{
|
|
155
|
-
"
|
|
156
|
-
|
|
157
|
-
"
|
|
192
|
+
"currentProvider": "claude",
|
|
193
|
+
"providers": {
|
|
194
|
+
"claude": {
|
|
195
|
+
"type": "anthropic",
|
|
196
|
+
"model": "claude-sonnet-4-6",
|
|
197
|
+
"apiKey": "$ENV:ANTHROPIC_API_KEY"
|
|
198
|
+
}
|
|
158
199
|
}
|
|
159
200
|
}
|
|
160
201
|
```
|
|
161
202
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
**Evaluation order:** deny patterns are checked first, then allow patterns, then the mode policy. Deny always wins.
|
|
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).
|
|
170
209
|
|
|
171
|
-
|
|
210
|
+
### Connect MCP servers, or serve the session over MCP
|
|
172
211
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
| `/resume` | List and resume a saved session |
|
|
179
|
-
| `/cost` | Show token usage |
|
|
180
|
-
| `/model` | Show current model |
|
|
181
|
-
| `/exit` | Exit CLI |
|
|
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>` connects it in
|
|
214
|
+
the running session and keeps the approval in `<configured-user-state-dir>/mcp-approvals.json` for later starts. A
|
|
215
|
+
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 connects once you sign in.
|
|
182
217
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"mcpServers": {
|
|
221
|
+
"docs": { "type": "http", "url": "https://mcp.example.com/mcp", "oauth": {} }
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
186
225
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
226
|
+
An HTTP or stdio definition can explicitly select `"protocolVersion": "2026-07-28"` for a stateless
|
|
227
|
+
peer. Omit that field for the legacy handshake. Changing it requires approval again; unsupported values
|
|
228
|
+
are refused rather than silently ignored. The selected version is visible in the definition details.
|
|
229
|
+
Startup reports unavailable client-input, subscription and extension capabilities. Selecting this
|
|
230
|
+
version does not enable distributed Skills or give the server any additional authority. Add
|
|
231
|
+
`"skills": true` to explicitly opt that definition into a peer's advertised Skills extension;
|
|
232
|
+
changing this selection requires fresh server approval. `/mcp skill-list <server>` reads metadata
|
|
233
|
+
only. A local terminal or app user can review `/mcp skill-inspect <server> <uri>`, then copy its
|
|
234
|
+
`/mcp skill-approve <server> <uri> <fingerprint>` command to consent to those exact instructions and
|
|
235
|
+
frontmatter. `/mcp skill-withdraw <server> <uri>` withdraws that consent. JSON string arrays also
|
|
236
|
+
accept opaque names and URIs containing spaces. Content decisions persist separately in
|
|
237
|
+
`<configured-user-state-dir>/mcp-skill-approvals.json`, bound to the host origin, workspace and URI.
|
|
238
|
+
Observed changed or removed manifests withdraw consent even if the peer later reverts them.
|
|
239
|
+
Discovery returns an exact invocation name for each supported skill, or a reason its profile is
|
|
240
|
+
unavailable. Invoke that name through the session's skill command. Instructions load only when
|
|
241
|
+
the actual turn starts, under current content consent; ending or cancelling that turn closes its
|
|
242
|
+
activation. A queued or cancelled request does not load instructions into another turn. Remote
|
|
243
|
+
shell expressions remain instruction text and do not execute as local preprocessing. During an
|
|
244
|
+
active execution, `/skill-read ["<invocation-name>", "<resource-uri>"]` reads a listed supporting
|
|
245
|
+
file with fresh verification. A fork can read only files from its own activations; a nested SKILL.md remains
|
|
246
|
+
supporting data until separately approved and activated.
|
|
247
|
+
|
|
248
|
+
MCP calls recheck approval and the current source immediately before dispatch. Removing or
|
|
249
|
+
replacing a definition, revoking approval, changing required workspace trust, or closing the
|
|
250
|
+
composition refuses new calls through retained tools. Calls already dispatched keep their real
|
|
251
|
+
outcome; revocation is not rollback. A changed configuration needs a fresh startup and approval
|
|
252
|
+
rather than silently substituting a new connection into an existing tool chain. The startup host
|
|
253
|
+
also exposes declarative contribution descriptors bound to configuration fingerprints, without
|
|
254
|
+
credential values or an invented server version.
|
|
255
|
+
|
|
256
|
+
| Surface | Verified coverage | Limit |
|
|
257
|
+
| ------------------------------------------ | -------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
258
|
+
| Linux interactive, serve and print startup | Real admitted stdio calls; changed settings refused before another call | Shared startup composition; not a rendered app UI trial |
|
|
259
|
+
| Installed Linux bundle in serve startup | Disable, uninstall and selected-revision update; durable approval rechecked at restart | Already dispatched calls settle; no rollback claim |
|
|
260
|
+
| Remote HTTP | Composition, transport admission and call routing regressions | No live account benchmark |
|
|
261
|
+
| macOS and Windows | Repository CI build routes | No external-plugin pilot on those OSes |
|
|
262
|
+
|
|
263
|
+
`robota mcp serve` does the reverse: it serves one agent session to an MCP host over stdio (or over
|
|
264
|
+
authenticated HTTP with the `--http-*` and `--oauth-*` flags). Trust the project first, and give the
|
|
265
|
+
host the absolute path of `robota` and the project directory:
|
|
190
266
|
|
|
191
267
|
```json
|
|
192
268
|
{
|
|
193
|
-
"
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
"permissions": {
|
|
200
|
-
"allow": ["Bash(pnpm *)"],
|
|
201
|
-
"deny": ["Bash(rm -rf *)"]
|
|
269
|
+
"mcpServers": {
|
|
270
|
+
"robota": {
|
|
271
|
+
"command": "/absolute/path/to/robota",
|
|
272
|
+
"args": ["mcp", "serve"],
|
|
273
|
+
"cwd": "/absolute/path/to/trusted/project"
|
|
274
|
+
}
|
|
202
275
|
}
|
|
203
276
|
}
|
|
204
277
|
```
|
|
205
278
|
|
|
206
|
-
|
|
279
|
+
See [MCP](../../content/guide/mcp.md).
|
|
280
|
+
|
|
281
|
+
### Add skills, commands, agents and plugins
|
|
207
282
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
283
|
+
Skills and commands are Markdown files the CLI finds in `<configured-project-state-dir>/skills/`, `.claude/skills/`,
|
|
284
|
+
`.claude/commands/` and `.agents/skills/` — in a trusted project and under your home directory. Each
|
|
285
|
+
one becomes a slash command (`/<name>`), and `/skills` lists them. Agent definitions are read from
|
|
286
|
+
`<configured-project-state-dir>/agents/`, `.agents/agents/` and `.claude/agents/`. Plugins bundle these together with hooks,
|
|
287
|
+
themes and MCP servers:
|
|
211
288
|
|
|
212
|
-
|
|
289
|
+
```text
|
|
290
|
+
/plugin marketplace add <source>
|
|
291
|
+
/plugin install <name>@<marketplace>
|
|
292
|
+
/plugin # open the plugin manager
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
See the [CLI guide](../../content/guide/cli.md) for skill frontmatter and plugin management.
|
|
213
296
|
|
|
214
|
-
|
|
297
|
+
### Use the graphical interface
|
|
215
298
|
|
|
216
|
-
|
|
299
|
+
`robota --serve --open` starts a headless runtime for the current workspace, serves the configured GUI
|
|
300
|
+
on `127.0.0.1` and opens it in your browser. The Electron desktop app in this repository
|
|
301
|
+
([`apps/agent-app`](../../apps/agent-app/docs/README.md)) shows the same GUI over the workspace
|
|
302
|
+
daemon; it is not published to npm. See [The GUI and the Desktop App](../../content/guide/gui.md).
|
|
217
303
|
|
|
218
|
-
|
|
219
|
-
- **CLAUDE.md** — same walk-up discovery
|
|
220
|
-
- **Project metadata** — from `package.json`, `tsconfig.json`
|
|
304
|
+
### Let other apps and services use the agent
|
|
221
305
|
|
|
222
|
-
|
|
306
|
+
`robota --serve --http-port <port>` also serves the agent over HTTP on `127.0.0.1:<port>`, so another
|
|
307
|
+
application or service can use it without a Robota client library. Every request presents the
|
|
308
|
+
bearer you choose in `PRODUCT_HTTP_TOKEN` (at least 32 characters); the runtime removes it from its
|
|
309
|
+
environment, so the commands it runs do not inherit it. A command running as the same OS user can
|
|
310
|
+
still read the server's launch environment unless the OS sandbox confines it (or the server runs
|
|
311
|
+
as a separate user), so enable the sandbox on a server. With the bearer it binds loopback only.
|
|
223
312
|
|
|
224
|
-
|
|
313
|
+
To reach it from elsewhere, either put your own reverse proxy or tunnel in front, or serve it as an
|
|
314
|
+
OAuth resource server, the same way `robota mcp serve` does: give `--http-public-url`, `--oauth-issuer`,
|
|
315
|
+
`--oauth-scopes` and `--oauth-allowed-subjects` (optionally `--http-host <ip>` and `--trusted-proxy`)
|
|
316
|
+
and no `PRODUCT_HTTP_TOKEN`. Clients then present access tokens from that issuer whose audience is the
|
|
317
|
+
public URL, which carry the scopes and name an allowed subject. The routes below are served under the
|
|
318
|
+
public URL's path, and its RFC 9728 metadata at `/.well-known/oauth-protected-resource<path>`.
|
|
225
319
|
|
|
320
|
+
```bash
|
|
321
|
+
PRODUCT_HTTP_TOKEN="$(openssl rand -hex 32)" robota --serve --http-port 8787
|
|
322
|
+
robota --serve --http-port 8787 --http-host 0.0.0.0 \
|
|
323
|
+
--http-public-url https://agents.example.com/agent --oauth-issuer https://auth.example.com \
|
|
324
|
+
--oauth-scopes agent.run --oauth-allowed-subjects client-a
|
|
226
325
|
```
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
326
|
+
|
|
327
|
+
| Request | Does |
|
|
328
|
+
| --- | --- |
|
|
329
|
+
| `POST /submit` `{"prompt": "...", "receivePrompts"?: true}` | Runs a turn and streams it as SSE (`text_delta`, `complete`, `error`; with `receivePrompts`, also `permission_request`, `ask_request`, `prompt_resolved`); `409` while a turn is running |
|
|
330
|
+
| `GET /prompts` · `POST /prompts/<id>` `{"result": true}` | Lists the open permission/ask prompts · answers one (`{"response": ...}` for an ask) |
|
|
331
|
+
| `POST /command` `{"name": "help", "args": ""}` | Runs a slash command |
|
|
332
|
+
| `POST /abort` · `POST /cancel-queue` | Aborts the running turn · drops the queued prompt |
|
|
333
|
+
| `GET /messages` · `/context` · `/executing` · `/pending` | Reads the conversation and its state |
|
|
334
|
+
|
|
335
|
+
A client that submits with `receivePrompts: true` answers the permission and ask prompts its turn
|
|
336
|
+
raises; without it, a question no other client answers is denied, so choose the permission mode and
|
|
337
|
+
rules the server runs under.
|
|
338
|
+
|
|
339
|
+
`robota acp` serves the agent to an editor (Zed, JetBrains and other
|
|
340
|
+
[Agent Client Protocol](https://agentclientprotocol.com/) clients) over stdio. Configure the editor to
|
|
341
|
+
run `robota acp` with the project folder as its working directory. Workspace trust, permissions and
|
|
342
|
+
the sandbox apply as in the terminal, and the editor asks you to approve each tool call the terminal
|
|
343
|
+
would. See [Editors](../../content/guide/cli.md#editors-agent-client-protocol).
|
|
344
|
+
|
|
345
|
+
### Reach other sessions and your other devices
|
|
346
|
+
|
|
347
|
+
`/peers` lists the other live `robota` sessions on this machine, and `/peers send <session-id>
|
|
348
|
+
<message>` sends one a message; the receiving session handles it under its own permissions, like
|
|
349
|
+
its own work. `/handoff <session-id>` moves this conversation to another session once both sides
|
|
350
|
+
confirm. To reach your other devices too, create a device identity with `/devices init`, link each
|
|
351
|
+
new device with `/devices add` and `/devices join`, and set `transports.mesh.enabled` to `true` in
|
|
352
|
+
your user settings. `/remote-control enable` pairs a browser to co-drive the current session.
|
|
353
|
+
|
|
354
|
+
See [Devices and remote control](../../content/guide/devices-and-remote.md).
|
|
355
|
+
|
|
356
|
+
### Check your setup and usage
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
robota doctor # settings layers, provider, trust, storage, plugins, hooks, MCP
|
|
360
|
+
robota usage # sessions, turns, tokens and cost for the last 7 days (--period 30d)
|
|
361
|
+
robota --check-update # is a newer version on npm?
|
|
362
|
+
robota eval <definition> # run an evals-as-code definition; exits 1 on a metric breach
|
|
240
363
|
```
|
|
241
364
|
|
|
242
|
-
|
|
365
|
+
## Configuration files
|
|
366
|
+
|
|
367
|
+
Settings are merged from these files, lowest priority first. The two user files always apply; the
|
|
368
|
+
four project files apply only in a trusted workspace.
|
|
369
|
+
|
|
370
|
+
| File | Scope |
|
|
371
|
+
| ---------------------------------------------------- | --------------------------------------- |
|
|
372
|
+
| `<configured-user-state-dir>/settings.json` | user |
|
|
373
|
+
| `~/.claude/settings.json` | user (Claude Code-compatible) |
|
|
374
|
+
| `<configured-project-state-dir>/settings.json` | project, committed |
|
|
375
|
+
| `<configured-project-state-dir>/settings.local.json` | project, local to this machine |
|
|
376
|
+
| `.claude/settings.json` | project (Claude Code-compatible) |
|
|
377
|
+
| `.claude/settings.local.json` | project, local (Claude Code-compatible) |
|
|
378
|
+
|
|
379
|
+
Other files the CLI keeps under `<configured-user-state-dir>/`:
|
|
380
|
+
|
|
381
|
+
| Path | Contents |
|
|
382
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------- |
|
|
383
|
+
| `workspace-trust.json` | workspaces you have trusted |
|
|
384
|
+
| `sessions/` | saved sessions (a trusted project may keep them in `<configured-project-state-dir>/sessions/`) |
|
|
385
|
+
| `history.jsonl` | prompts you typed, for `Ctrl+R` (`"promptHistory": false` turns it off) |
|
|
386
|
+
| `keybindings.json` | key bindings |
|
|
387
|
+
| `themes/` | your own `/theme` themes |
|
|
388
|
+
| `plugins/` | installed plugins (a project may have its own `<configured-project-state-dir>/plugins/`) |
|
|
389
|
+
| `mcp-credentials/` | OAuth tokens for MCP servers, readable by you only |
|
|
390
|
+
|
|
391
|
+
## Use it from code
|
|
392
|
+
|
|
393
|
+
The package also exports `startCli`, the function the `robota` executable runs, and its options
|
|
394
|
+
type `IStartCliOptions`. The package is ESM-only: load it with `import`, not `require()`.
|
|
395
|
+
|
|
396
|
+
A subagent runs in a child process that starts your entry script again with a worker flag; when
|
|
397
|
+
`startCli()` sees that flag it runs the subagent instead of the CLI, and the returned promise never
|
|
398
|
+
settles (the worker ends the process). So call `startCli()` from the script Node started, and put
|
|
399
|
+
nothing before it that must not run once per subagent.
|
|
400
|
+
|
|
401
|
+
### Hosted task-worker execution
|
|
402
|
+
|
|
403
|
+
The library also exports `HostedOrganizationControl` and `createHostedOrganizationGateway` for
|
|
404
|
+
the owner-hosted company backend. This composition requires an anchored `OrganizationLedger`,
|
|
405
|
+
an `OrganizationAudit`, provider-backed worker inventory and named detection, containment,
|
|
406
|
+
assessment and recovery owners. The gateway serves the configured admission endpoints and
|
|
407
|
+
OpenAI model endpoints; its worker ingress has no policy, approval or recovery routes.
|
|
408
|
+
Each model-only grant has a distinct owner-issued task token and runtime binding. The logical task
|
|
409
|
+
root survives grant rotation; provider inventory and gateway admission pin its current binding. Issuer signing
|
|
410
|
+
capabilities, upstream credentials, policy, audit and private payload storage stay outside workers.
|
|
411
|
+
Sign task access with the exported `hostedWorkerAccessBytes` and provision E2B workers with an
|
|
412
|
+
`organization` binding; `createE2BOrganizationInventory` enumerates all pages, including paused
|
|
413
|
+
workers, and rechecks ownership before deletion. Owner stop methods persist withdrawal first,
|
|
414
|
+
abort affected broker calls, and wait for descendant provider cleanup; unresolved cleanup is
|
|
415
|
+
reported to the incident owners.
|
|
416
|
+
|
|
417
|
+
`HostedOrganizationPayloads` stores bounded request/response bytes in an owner-only directory;
|
|
418
|
+
the durable journal and audit retain digests rather than these bodies. Install
|
|
419
|
+
`createHostedOrganizationModelAction` with a fixed provider endpoint/model, owner-selected
|
|
420
|
+
reservation, input/output bounds and explicit upstream idempotency support. A mandatory trusted
|
|
421
|
+
`countInputTokens` port counts the exact immutable upstream input before dispatch; input plus the
|
|
422
|
+
owner-selected output cap must fit the token and conservative cost reservation.
|
|
423
|
+
`createHostedOrganizationInputTokenCounter` connects a fixed private counting endpoint through an
|
|
424
|
+
owner-selected encoder. A Responses counter does not establish exact Chat token counts; select a
|
|
425
|
+
verified counter for that surface. The counting service must be read-only and covered by the
|
|
426
|
+
owner's pricing assumptions. The gateway buffers
|
|
427
|
+
the upstream result until durable settlement, then returns JSON or OpenAI stream events.
|
|
428
|
+
Configure the worker's OpenAI profile with `options: { durableOperations: true }`: one operation
|
|
429
|
+
identity survives SDK retries, and missing identities are refused. Unknown provider outcomes
|
|
430
|
+
retain reservations and require asset-owner reconciliation; this adapter never retries upstream.
|
|
431
|
+
The private payload store retains digest-bound operation claims for recovery. Owner code may
|
|
432
|
+
load those claims with `operation` and call `reconcileExternalOperation` with confirmed asset-owner
|
|
433
|
+
evidence. Reconciliation charges the entire retained reservation and cannot restore revoked
|
|
434
|
+
authority; the worker gateway exposes no reconciliation route.
|
|
435
|
+
Broker supervisory token/cost observations report settled usage; pending reservations remain
|
|
436
|
+
enforced by the hierarchical ledger. Local process and wire tests establish these software paths,
|
|
437
|
+
while physical containment, provider billing and independent remote custody require deployment
|
|
438
|
+
measurements.
|
|
439
|
+
|
|
440
|
+
Hosted posture requires current signed admission for a separate task worker and company broker.
|
|
441
|
+
The installed E2B executor runs the stock CLI inside that worker. The runtime forwards arguments,
|
|
442
|
+
input and output and owns cancellation, credential expiry and provider deletion; it does not run
|
|
443
|
+
task tools against its own filesystem. Direct `--api-key` configuration is refused.
|
|
444
|
+
|
|
445
|
+
`PRODUCT_HOSTED_RUNTIME_CONFIG` selects an owner-controlled version-3 deployment file. It retains
|
|
446
|
+
`identity`, `epoch`, `worker`, `broker`, `snapshot`, `lifetimeMs` and `probeTimeoutMs`, and requires
|
|
447
|
+
`limits: { sessions, modelCalls, modelTokens, costMicros }` with nonnegative safe integer ceilings.
|
|
448
|
+
Version-2 deployments and proofs are refused because they cannot attest current accounting.
|
|
449
|
+
The worker and broker answer version-3 admission challenges with the configured limits; worker
|
|
450
|
+
proofs carry `usage: null`, while broker proofs carry cumulative usage in that same four-counter
|
|
451
|
+
shape. The broker measures registered sessions and provider calls outside the worker for the
|
|
452
|
+
current identity and epoch. Counts and micro-cost units come from its trusted instrumentation,
|
|
453
|
+
not CLI output, model messages or a checkpoint. Both attestations sign the fixed tuple returned by
|
|
454
|
+
the exported `hostedAdmissionBytes`, binding limits and accounting to the current challenge,
|
|
455
|
+
identity, root, epoch and checkpoint. The issuer must validate requested limits against owner policy
|
|
456
|
+
before attesting them.
|
|
457
|
+
|
|
458
|
+
`HostedRuntimeController.status()` exposes the latest verified observations to the owner. The
|
|
459
|
+
controller checks them before executor allocation, during admission refresh and after short
|
|
460
|
+
executions before reporting success. Invalid, regressing, unavailable or over-limit observations
|
|
461
|
+
refuse admission or stop and release owned execution. Runtime ceilings supervise observed totals;
|
|
462
|
+
the broker's per-request reservations must bound new model calls and their maximum token/cost
|
|
463
|
+
usage before dispatch. Supervisory polling does not replace those reservations or establish an
|
|
464
|
+
invoice hard cap. The broker must retain cumulative accounting across controller restart/resume;
|
|
465
|
+
recovered task content cannot reset it. Actual provider charges and cleanup remain separately
|
|
466
|
+
measured operational evidence.
|
|
467
|
+
|
|
468
|
+
The operator supplies `PRODUCT_E2B_API_KEY` to the runtime and sets
|
|
469
|
+
`PRODUCT_HOSTED_WORKER_EXECUTION_CONFIG` to an absolute owner-only JSON file. Its version-1 shape is:
|
|
243
470
|
|
|
471
|
+
```json
|
|
472
|
+
{
|
|
473
|
+
"version": 1,
|
|
474
|
+
"templateId": "operator-pinned-template",
|
|
475
|
+
"nodeExecutable": "/usr/local/bin/node",
|
|
476
|
+
"workspaceRoot": "/workspace",
|
|
477
|
+
"entrypoint": { "path": "/opt/agent/cli.mjs", "digest": "<sha256>" },
|
|
478
|
+
"productConfig": { "path": "/opt/agent/product.env", "digest": "<sha256>" },
|
|
479
|
+
"access": {
|
|
480
|
+
"version": 1,
|
|
481
|
+
"identity": {
|
|
482
|
+
"tenant": "...",
|
|
483
|
+
"task": "...",
|
|
484
|
+
"rootTask": "...",
|
|
485
|
+
"actor": "...",
|
|
486
|
+
"runtime": "..."
|
|
487
|
+
},
|
|
488
|
+
"worker": "...",
|
|
489
|
+
"broker": "...",
|
|
490
|
+
"epoch": 1,
|
|
491
|
+
"endpoint": "https://company-broker.example/v1",
|
|
492
|
+
"token": "<task-scoped-broker-token>",
|
|
493
|
+
"issuedAt": 0,
|
|
494
|
+
"expiresAt": 0,
|
|
495
|
+
"signature": "<broker-ed25519-base64url-signature>"
|
|
496
|
+
}
|
|
497
|
+
}
|
|
244
498
|
```
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
499
|
+
|
|
500
|
+
The broker signs the fixed tuple encoded by `hostedWorkerAccessBytes` in the implementation.
|
|
501
|
+
Access must match the admission's identity, resources and epoch, use the admitted broker origin,
|
|
502
|
+
and expire within both admission and sixty seconds of issuance. This executor ends execution at
|
|
503
|
+
expiry; it does not renew credentials. The template's CLI and product environment artifacts must
|
|
504
|
+
match their pinned digests. The product artifact accepts only CLI product metadata variables.
|
|
505
|
+
Provider metadata must match task ownership and the template, with public traffic disabled and
|
|
506
|
+
outbound access limited to the broker hostname and no attached volumes. The resource must already
|
|
507
|
+
be running, with timeout deletion and auto-resume disabled; connecting a paused memory image is
|
|
508
|
+
refused. These checks do not establish measured cloud containment.
|
|
509
|
+
|
|
510
|
+
An owner backend can call `provisionE2BTaskWorker` before issuing admission. It creates the
|
|
511
|
+
operator-selected clean template with closed networking, no worker credentials or volumes, and
|
|
512
|
+
an exclusive new workspace. It returns the resource, workspace root, operation ID, checkpoint
|
|
513
|
+
reference, optional conversation artifact receipt and an idempotent `release()` operation. The management capability stays in this
|
|
514
|
+
owner-side SDK composition. After the receipt, the owner signs current worker/broker admission
|
|
515
|
+
and task access for the returned resource and configures that workspace in the execution input.
|
|
516
|
+
|
|
517
|
+
For recovery, supply an owner-approved `{ id, digest }` reference and the matching UTF-8 JSON bytes
|
|
518
|
+
in `checkpoint`. The manifest has `version: 1`, `id`, the source `identity`, `epoch`, `worker`, and
|
|
519
|
+
`files: [{ path, base64 }]`. Paths are relative regular workspace files; private HOME/TMPDIR and link or memory records
|
|
520
|
+
are not accepted. Owner authority journals stay outside this workspace. The source must belong
|
|
521
|
+
to the same tenant/task/root and precede the current epoch and runtime. File bytes are read back
|
|
522
|
+
and compared before the owner receives a successful result. Treat recovered project content as
|
|
523
|
+
untrusted; current profile, policy and credentials come from the clean operator composition.
|
|
524
|
+
For conversation recovery, use manifest `version: 2` with the same fields and `session` containing
|
|
525
|
+
an existing versioned session-record envelope (`{ schemaVersion, record }`). Only the conversation,
|
|
526
|
+
name, selector and timestamps survive. Saved system messages/prompts, message metadata, tool schemas,
|
|
527
|
+
VM state, goals, background jobs, loops, memory references and branch pointers do not restore;
|
|
528
|
+
current composition rebuilds execution and authority. Display history is rebuilt from the projected
|
|
529
|
+
conversation; saved events are not imported. The record's cwd becomes the fresh workspace.
|
|
530
|
+
Pass the returned `resumeSession: { id, path, digest }` in the private worker execution input and
|
|
531
|
+
invoke `--resume <id>` (or `--continue`, optionally with `--fork-session`). The default executor
|
|
532
|
+
verifies the receipt and copies the projected record into the current product artifact's selected
|
|
533
|
+
private user session store before CLI startup. It refuses an existing destination, mismatched
|
|
534
|
+
selector/digest, malformed record or a user state root inside recovered project files. No saved
|
|
535
|
+
settings, trust decision or credential is imported. A resume without this receipt refuses execution.
|
|
536
|
+
|
|
537
|
+
The default executor accepts this filesystem checkpoint only when signed current admission and
|
|
538
|
+
provider metadata agree on its digest, fresh identity/epoch and source resource. It does not
|
|
539
|
+
restore provider memory snapshots or reconnect the checkpoint source. Setup failures delete
|
|
540
|
+
verified allocations; unknown creation/ownership and unresolved deletion return
|
|
541
|
+
`E2BWorkerProvisioningError` with reconciliation identifiers. The external owner must retain and
|
|
542
|
+
reconcile those outcomes rather than retry or report cleanup as successful.
|
|
543
|
+
|
|
544
|
+
The worker receives a closed environment with private HOME/TMPDIR, product configuration and the
|
|
545
|
+
scoped broker token through the OpenAI-compatible provider interface. Management and upstream
|
|
546
|
+
credentials stay outside the worker. Interactive input uses a PTY; input EOF requests the stock
|
|
547
|
+
CLI's Ctrl-C shutdown. For `--serve`, include `serve: { port, workerPort, token }` in the private
|
|
548
|
+
execution input. `port` selects the runtime's IPv4 loopback ingress (`0` assigns a free port);
|
|
549
|
+
`workerPort` selects the worker daemon port. Generate a fresh, unpredictable owner client `token`
|
|
550
|
+
of 32–256 URL-safe characters and connect to the printed runtime URL with `?token=<token>`.
|
|
551
|
+
The runtime validates the client token, Host and Origin, then carries binary WebSocket traffic
|
|
552
|
+
through an owned provider command to the pinned worker loopback listener. It replaces client
|
|
553
|
+
headers and credentials with a separate per-launch worker token. The owner token and provider
|
|
554
|
+
management capability stay in the runtime. Stopping execution closes the listener and clients
|
|
555
|
+
and deletes the worker. This local ingress does not provide remote desktop pairing or TLS.
|
|
556
|
+
Credential renewal requires broker integration; this executor still ends at its signed access expiry.
|
|
557
|
+
|
|
558
|
+
Embedders can override the installed executor with `hostedRuntimeExecutorFactory`. It receives
|
|
559
|
+
`(admission, signal, invocation)` with immutable captured arguments and returns `run`, `stop` and
|
|
560
|
+
`release`. The adapter owns authenticated communication, input/output and trusted usage reporting;
|
|
561
|
+
stop and release settle only after cleanup. Missing or invalid authority refuses execution without
|
|
562
|
+
entering local host adapters. CLI flags request behavior and never confer company authority.
|
|
563
|
+
|
|
564
|
+
## Remote desktop owner composition
|
|
565
|
+
|
|
566
|
+
Use `HostedDesktopWorkerPort.connect({ endpoint, token, worker, control })` with the owner's private
|
|
567
|
+
runtime loopback ingress. It discovers and pins the actual worker session; retain this carrier across
|
|
568
|
+
desktop reconnects. Create `HostedDesktopAuthorization` with the public HTTPS URL, pinned issuer,
|
|
569
|
+
current `HostedOrganizationControl`, and owner-selected bindings containing `id`, `user`, `client`,
|
|
570
|
+
the discovered `session`, and the same `worker`. Give `HostedDesktopGateway` the owner's HTTPS server,
|
|
571
|
+
that authorization, a `HostedDesktopAuthorityStore` and a binding-ID-to-worker-port map. The store uses
|
|
572
|
+
a private existing directory and an independently held organization ledger anchor; `create: true` is only
|
|
573
|
+
for first creation. Store loss, rollback or an uncertain anchor acknowledgment refuses access.
|
|
574
|
+
|
|
575
|
+
The issuer signs a short-lived asymmetric JWT with exact `sub`, `client_id`, `tenant`, `task`, `session`,
|
|
576
|
+
`workload` and `epoch` binding claims, unique `jti`, `iat`, and `exp`. Ordinary credentials have the public
|
|
577
|
+
URL as audience and `desktop:pair desktop:drive` scopes. A separate operator credential has
|
|
578
|
+
`<publicUrl>/approval` as audience and `desktop:approve` scope. Credentials expire within two minutes;
|
|
579
|
+
pairing grants at most one minute and never extends current company authority. Reconnect uses new JWTs,
|
|
580
|
+
withdraws the previous connection and preserves the pinned worker session. Issuer/JWK outages and current
|
|
581
|
+
grant withdrawal close active access. `gateway.revoke(bindingId)` is an owner-only withdrawal API.
|
|
582
|
+
|
|
583
|
+
Remote traffic requires TLS and the pinned Host/Origin. TLS termination requires explicitly selected
|
|
584
|
+
proxy IPs with matching HTTPS forwarding headers; arbitrary proxy headers are refused. The renderer
|
|
585
|
+
cannot switch tasks/sessions, execute slash commands, change settings, or approve permissions. The
|
|
586
|
+
main-process operator channel binds Allow once/Deny to the currently pending operation digest and
|
|
587
|
+
rejects replay. Run all authority stores and gateway/control composition outside the task worker.
|
|
588
|
+
These local integration checks do not establish deployed cloud containment or operational latency.
|
|
589
|
+
|
|
590
|
+
## Work on the CLI in this repository
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
pnpm install && pnpm build
|
|
594
|
+
pnpm cli:dev # run the CLI from source
|
|
595
|
+
pnpm cli:trust # trust this repository for the source CLI
|
|
254
596
|
```
|
|
597
|
+
|
|
598
|
+
## Documentation
|
|
599
|
+
|
|
600
|
+
- [CLI guide](../../content/guide/cli.md) — every command, flag and setting
|
|
601
|
+
- [Sessions and the daemon](../../content/guide/sessions-and-daemon.md)
|
|
602
|
+
- [Permissions and hooks](../../content/guide/permissions-and-hooks.md)
|
|
603
|
+
- [Providers](../../content/guide/providers.md) and [Local LLM setup](../../content/guide/local-llm.md)
|
|
604
|
+
- [MCP](../../content/guide/mcp.md)
|
|
605
|
+
- [Devices and remote control](../../content/guide/devices-and-remote.md)
|
|
606
|
+
- [SPEC.md](./docs/SPEC.md) — what this package owns and guarantees
|
|
607
|
+
|
|
608
|
+
## License
|
|
609
|
+
|
|
610
|
+
This package is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a
|
|
611
|
+
[commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
|