rlmness-cli 0.2.0__py3-none-any.whl

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.
Files changed (203) hide show
  1. rlmagent/__init__.py +1 -0
  2. rlmagent/__main__.py +8 -0
  3. rlmagent/acp/__init__.py +1 -0
  4. rlmagent/acp/runtime.py +71 -0
  5. rlmagent/acp/server.py +598 -0
  6. rlmagent/acp/updates.py +128 -0
  7. rlmagent/agentnet.py +237 -0
  8. rlmagent/agents/__init__.py +1 -0
  9. rlmagent/agents/approval.py +90 -0
  10. rlmagent/agents/bridge.py +109 -0
  11. rlmagent/agents/budget.py +212 -0
  12. rlmagent/agents/child_handles.py +46 -0
  13. rlmagent/agents/child_mailbox.py +30 -0
  14. rlmagent/agents/kernel_api.py +156 -0
  15. rlmagent/agents/output.py +34 -0
  16. rlmagent/agents/patch.py +107 -0
  17. rlmagent/agents/prompts.py +156 -0
  18. rlmagent/agents/trace.py +290 -0
  19. rlmagent/agents/tree.py +682 -0
  20. rlmagent/agents/wasm_api.py +105 -0
  21. rlmagent/agents/workspace.py +357 -0
  22. rlmagent/autopilot.py +447 -0
  23. rlmagent/backend.py +946 -0
  24. rlmagent/backend_context.py +74 -0
  25. rlmagent/cli/__init__.py +5 -0
  26. rlmagent/cli/config_cmd.py +177 -0
  27. rlmagent/cli/health.py +156 -0
  28. rlmagent/cli/main.py +1194 -0
  29. rlmagent/cli/update.py +188 -0
  30. rlmagent/clipboard.py +63 -0
  31. rlmagent/config/__init__.py +37 -0
  32. rlmagent/config/config.py +297 -0
  33. rlmagent/config/loader.py +119 -0
  34. rlmagent/config/prompts.py +124 -0
  35. rlmagent/config/secure_input.py +213 -0
  36. rlmagent/config/store.py +275 -0
  37. rlmagent/context/__init__.py +47 -0
  38. rlmagent/context/budget.py +557 -0
  39. rlmagent/contract.py +311 -0
  40. rlmagent/contract_run.py +232 -0
  41. rlmagent/conversation.py +2547 -0
  42. rlmagent/cron.py +77 -0
  43. rlmagent/directives.py +893 -0
  44. rlmagent/discovery.py +356 -0
  45. rlmagent/execution_log.py +66 -0
  46. rlmagent/factory.py +189 -0
  47. rlmagent/factory_graph.py +413 -0
  48. rlmagent/harness/__init__.py +63 -0
  49. rlmagent/harness/contracts/__init__.py +1 -0
  50. rlmagent/harness/contracts/stream.py +129 -0
  51. rlmagent/harness/contracts/tooling.py +127 -0
  52. rlmagent/harness/contracts/transcript/__init__.py +68 -0
  53. rlmagent/harness/contracts/transcript/_base.py +29 -0
  54. rlmagent/harness/contracts/transcript/diagnostics.py +52 -0
  55. rlmagent/harness/contracts/transcript/entries.py +180 -0
  56. rlmagent/harness/contracts/transcript/segments.py +64 -0
  57. rlmagent/harness/contracts/values.py +6 -0
  58. rlmagent/harness/driver.py +397 -0
  59. rlmagent/harness/engine.py +489 -0
  60. rlmagent/harness/mending.py +153 -0
  61. rlmagent/harness/provider/__init__.py +1 -0
  62. rlmagent/harness/provider/base.py +27 -0
  63. rlmagent/harness/provider/wire.py +189 -0
  64. rlmagent/harness/py.typed +0 -0
  65. rlmagent/harness/session/__init__.py +5 -0
  66. rlmagent/harness/session/index.py +218 -0
  67. rlmagent/harness/session/lease.py +66 -0
  68. rlmagent/harness/session/records.py +118 -0
  69. rlmagent/harness/session/replay.py +165 -0
  70. rlmagent/harness/session/store.py +155 -0
  71. rlmagent/harness/session/summary.py +46 -0
  72. rlmagent/hints.py +47 -0
  73. rlmagent/history.py +92 -0
  74. rlmagent/hooks/__init__.py +1 -0
  75. rlmagent/hooks/hooks.py +1 -0
  76. rlmagent/instructions.py +157 -0
  77. rlmagent/job_runner.py +117 -0
  78. rlmagent/jobs.py +365 -0
  79. rlmagent/kept_agents.py +397 -0
  80. rlmagent/kernel/__init__.py +5 -0
  81. rlmagent/kernel/session.py +205 -0
  82. rlmagent/kernel/wasm.py +169 -0
  83. rlmagent/logs.py +208 -0
  84. rlmagent/managed_release.py +368 -0
  85. rlmagent/mcp.py +411 -0
  86. rlmagent/mcp_oauth.py +213 -0
  87. rlmagent/model/__init__.py +29 -0
  88. rlmagent/model/_claude/__init__.py +1 -0
  89. rlmagent/model/_claude/courier.py +117 -0
  90. rlmagent/model/_claude/emitter.py +378 -0
  91. rlmagent/model/_oai/__init__.py +1 -0
  92. rlmagent/model/_oai/helpers.py +256 -0
  93. rlmagent/model/_oai/normalize.py +263 -0
  94. rlmagent/model/_oai/parsers.py +317 -0
  95. rlmagent/model/_oai/payloads.py +226 -0
  96. rlmagent/model/_oai/transport.py +127 -0
  97. rlmagent/model/claude.py +552 -0
  98. rlmagent/model/copilot.py +142 -0
  99. rlmagent/model/correlation.py +21 -0
  100. rlmagent/model/deadline.py +19 -0
  101. rlmagent/model/discovery.py +181 -0
  102. rlmagent/model/external/__init__.py +11 -0
  103. rlmagent/model/external/acp.py +202 -0
  104. rlmagent/model/external/acp_install.py +109 -0
  105. rlmagent/model/external/cli.py +248 -0
  106. rlmagent/model/external/textcalls.py +57 -0
  107. rlmagent/model/failover.py +129 -0
  108. rlmagent/model/google.py +199 -0
  109. rlmagent/model/limits.py +46 -0
  110. rlmagent/model/oai_compatible.py +414 -0
  111. rlmagent/model/preferences.py +56 -0
  112. rlmagent/model/py.typed +0 -0
  113. rlmagent/model/registered_oauth.py +195 -0
  114. rlmagent/model/scripted.py +55 -0
  115. rlmagent/model/settings.py +271 -0
  116. rlmagent/model/subscription.py +398 -0
  117. rlmagent/model/token_bounds.py +15 -0
  118. rlmagent/model/transport/__init__.py +1 -0
  119. rlmagent/model/transport/backoff.py +87 -0
  120. rlmagent/model/transport/client.py +87 -0
  121. rlmagent/model/transport/faults.py +65 -0
  122. rlmagent/model/transport/responses_socket.py +223 -0
  123. rlmagent/model/vertex.py +93 -0
  124. rlmagent/network.py +123 -0
  125. rlmagent/packages.py +246 -0
  126. rlmagent/planning.py +84 -0
  127. rlmagent/playbook/__init__.py +1 -0
  128. rlmagent/playbook/apply.py +106 -0
  129. rlmagent/playbook/digest.py +63 -0
  130. rlmagent/playbook/improver.py +272 -0
  131. rlmagent/playbook/plan.py +99 -0
  132. rlmagent/playbook/store.py +67 -0
  133. rlmagent/plugins.py +327 -0
  134. rlmagent/policy.py +105 -0
  135. rlmagent/prompt_refs.py +57 -0
  136. rlmagent/prompts.py +331 -0
  137. rlmagent/prune.py +60 -0
  138. rlmagent/py.typed +0 -0
  139. rlmagent/reasoning.py +135 -0
  140. rlmagent/refinement/__init__.py +1 -0
  141. rlmagent/refinement/controller.py +448 -0
  142. rlmagent/refinement/engine.py +220 -0
  143. rlmagent/refinement/evidence.py +131 -0
  144. rlmagent/refinement/scoped.py +90 -0
  145. rlmagent/refinement/store.py +193 -0
  146. rlmagent/refresh.py +202 -0
  147. rlmagent/routing.py +52 -0
  148. rlmagent/runtime.py +575 -0
  149. rlmagent/safety.py +267 -0
  150. rlmagent/session_html.py +57 -0
  151. rlmagent/session_import.py +52 -0
  152. rlmagent/session_share.py +55 -0
  153. rlmagent/sessions.py +249 -0
  154. rlmagent/shell_sandbox.py +88 -0
  155. rlmagent/skillset.py +320 -0
  156. rlmagent/steering.py +148 -0
  157. rlmagent/stops.py +62 -0
  158. rlmagent/subscriptions.py +219 -0
  159. rlmagent/tasks.py +98 -0
  160. rlmagent/toolhost.py +310 -0
  161. rlmagent/tools/__init__.py +56 -0
  162. rlmagent/tools/_shared.py +210 -0
  163. rlmagent/tools/files.py +462 -0
  164. rlmagent/tools/kernel.py +93 -0
  165. rlmagent/tools/patch_tool.py +68 -0
  166. rlmagent/tools/search.py +188 -0
  167. rlmagent/trust.py +383 -0
  168. rlmagent/tui/__init__.py +1 -0
  169. rlmagent/tui/adapter.py +506 -0
  170. rlmagent/tui/app.py +711 -0
  171. rlmagent/tui/approval_screen.py +57 -0
  172. rlmagent/tui/choice_screen.py +47 -0
  173. rlmagent/tui/completions.py +116 -0
  174. rlmagent/tui/components.py +25 -0
  175. rlmagent/tui/composer.py +40 -0
  176. rlmagent/tui/factory_view.py +86 -0
  177. rlmagent/tui/inspect.py +193 -0
  178. rlmagent/tui/messages.py +215 -0
  179. rlmagent/tui/model_screen.py +307 -0
  180. rlmagent/tui/prompt.py +98 -0
  181. rlmagent/tui/question_screen.py +52 -0
  182. rlmagent/tui/replay.py +141 -0
  183. rlmagent/tui/rlm_agent.tcss +405 -0
  184. rlmagent/tui/search_box.py +91 -0
  185. rlmagent/tui/sidebar.py +182 -0
  186. rlmagent/tui/status.py +49 -0
  187. rlmagent/tui/steps.py +283 -0
  188. rlmagent/tui/suggest.py +778 -0
  189. rlmagent/tui/transcript.py +172 -0
  190. rlmagent/tui/trust_dialog.py +58 -0
  191. rlmagent/tui/worker_attach.py +141 -0
  192. rlmagent/ui/__init__.py +1 -0
  193. rlmagent/ui/render.py +211 -0
  194. rlmagent/undo.py +109 -0
  195. rlmagent/utils/__init__.py +1 -0
  196. rlmagent/websearch.py +75 -0
  197. rlmagent/worker.py +1275 -0
  198. rlmagent/worker_service.py +203 -0
  199. rlmness_cli-0.2.0.dist-info/METADATA +882 -0
  200. rlmness_cli-0.2.0.dist-info/RECORD +203 -0
  201. rlmness_cli-0.2.0.dist-info/WHEEL +4 -0
  202. rlmness_cli-0.2.0.dist-info/entry_points.txt +2 -0
  203. rlmness_cli-0.2.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,882 @@
1
+ Metadata-Version: 2.5
2
+ Name: rlmness-cli
3
+ Version: 0.2.0
4
+ Summary: A terminal coding agent with a persistent Python kernel and recursive sub-agents.
5
+ Project-URL: Homepage, https://github.com/kartikg-gk/rlmagent
6
+ Project-URL: Repository, https://github.com/kartikg-gk/rlmagent
7
+ Project-URL: Issues, https://github.com/kartikg-gk/rlmagent/issues
8
+ Author: Kartik G
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,cli,coding-agent,llm,recursive-language-models,tui
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: httpx[socks]>=0.27
21
+ Requires-Dist: ipykernel>=6.29
22
+ Requires-Dist: jupyter-client>=8.6
23
+ Requires-Dist: packaging>=24
24
+ Requires-Dist: psutil>=5.9
25
+ Requires-Dist: pydantic>=2.7
26
+ Requires-Dist: pyyaml>=6.0
27
+ Requires-Dist: rlmness>=0.2.4
28
+ Requires-Dist: textual>=8.2.8
29
+ Requires-Dist: tzdata; sys_platform == 'win32'
30
+ Provides-Extra: copilot
31
+ Requires-Dist: github-copilot-sdk<2,>=1.0.28; extra == 'copilot'
32
+ Provides-Extra: mcp-keyring
33
+ Requires-Dist: keyring>=25; extra == 'mcp-keyring'
34
+ Provides-Extra: subscription
35
+ Requires-Dist: keyring>=25; extra == 'subscription'
36
+ Requires-Dist: pyjwt[crypto]<3,>=2.10; extra == 'subscription'
37
+ Requires-Dist: websockets<17,>=15; extra == 'subscription'
38
+ Provides-Extra: vertex
39
+ Requires-Dist: google-auth[requests]>=2.0; extra == 'vertex'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # rlmagent
43
+
44
+ A terminal coding agent with a persistent Python workspace and recursive agents.
45
+ The application supplies the terminal interface, editor protocol, workspace tools,
46
+ and approvals. The `rlmness` backend runs the model loop, Python cells, recursive
47
+ delegation, and shared budget.
48
+
49
+ ## Install
50
+
51
+ Python 3.12 or newer is required. The default sandbox also requires Node.js.
52
+
53
+ ```sh
54
+ pip install rlmness-cli
55
+ rlmness --setup
56
+ ```
57
+
58
+ Or install it as a tool with one line, which also sets up the sandbox when Node is
59
+ present (`RLMAGENT_VERSION` pins a version):
60
+
61
+ ```sh
62
+ curl -fsSL https://raw.githubusercontent.com/kartikg-gk/rlmagent/main/scripts/install.sh | sh
63
+ ```
64
+
65
+ ```powershell
66
+ irm https://raw.githubusercontent.com/kartikg-gk/rlmagent/main/scripts/install.ps1 | iex
67
+ ```
68
+
69
+ `rlm-agent config show` prints the saved provider and model, and any
70
+ `RLM_AGENT_PROVIDER`, `RLM_AGENT_MODEL`, `RLM_AGENT_API_KEY` or `RLM_AGENT_HOME`
71
+ set in the environment, which take precedence for a run. `rlm-agent config path`
72
+ prints where the file is. Providers include OpenAI, Anthropic, OpenRouter, Ollama,
73
+ Hugging Face, Google Gemini, Mistral, Azure OpenAI, Vertex and Codex subscription sign-in.
74
+
75
+ This revision requires `rlmness>=0.2.4`. When installing unreleased local builds,
76
+ install the matching backend wheel before the application wheel.
77
+
78
+ ## Run
79
+
80
+ Run `rlm-agent` in a project folder. The first run opens a page to pick a provider and model; after that it opens the terminal UI. Where a security policy blocks the `rlm-agent` launcher, `python -m rlmagent` runs the same command.
81
+
82
+ Configure an API provider, or use an installed and authenticated external CLI:
83
+
84
+ ```sh
85
+ rlm-agent --provider cli --model 'cli:claude-code?model=haiku' "Inspect this project"
86
+ rlm-agent --provider cli --model 'cli:codex' "Fix the failing check"
87
+ rlm-agent --provider cli --model 'cli:claude-code?model=haiku' -p "Summarize the project"
88
+ ```
89
+
90
+ Run `rlm-agent --help` for provider, model, session, and budget settings. Keys are
91
+ read from provider configuration or environment variables. Keep keys out of prompts.
92
+
93
+ For native subscription sign-in, install the optional credential-store and identity
94
+ verification dependencies, then complete browser consent:
95
+
96
+ ```sh
97
+ pip install 'rlmness-cli[subscription]'
98
+ rlm-agent provider login codex
99
+ rlm-agent provider models codex
100
+ rlm-agent --provider codex --model MODEL_FROM_CATALOG "Inspect this project"
101
+ rlm-agent provider logout codex
102
+ ```
103
+
104
+ Subscription access, refresh and identity tokens are kept in the platform credential
105
+ store, separately for each `RLM_AGENT_HOME`. Requests use the public Responses API
106
+ with server-side response storage disabled. Model availability and usage limits come
107
+ from the signed-in account. `provider test` checks the model endpoint; a completed
108
+ model response is required to verify inference access. `login --new-account` replaces
109
+ the selected account after validating its identity. Sign-out clears local tokens and
110
+ reports whether remote revocation succeeded.
111
+
112
+ The native Gemini provider reads `GOOGLE_API_KEY`; Mistral reads `MISTRAL_API_KEY`.
113
+ Azure reads `AZURE_OPENAI_API_KEY` and requires `AZURE_OPENAI_BASE_URL` ending in
114
+ `/openai/v1`. `/tier auto|default|flex|priority|off` changes subsequent requests when
115
+ the active provider supports a service tier.
116
+
117
+ `/fast on|off` selects the priority or default tier for the current model. Tier
118
+ preferences are saved per provider and model. Use `/model cycle add MODEL`,
119
+ `/model cycle remove MODEL`, and `/model cycle next` to maintain a provider-specific
120
+ rotation. `--offline` suppresses startup model discovery and update checks; an
121
+ explicitly requested model run still uses its provider.
122
+
123
+ Set `RLM_AGENT_CODEX_TRANSPORT=websocket` to reuse a Responses WebSocket per agent.
124
+ The default is HTTP. Socket cancellation closes that agent's connection. A lost
125
+ server context can be resent once before output begins; visible output is never
126
+ automatically replayed. `NODE_EXTRA_CA_CERTS` adds a PEM certificate bundle to
127
+ the platform and bundled TLS roots for HTTP and WebSocket connections.
128
+
129
+ This release focuses on Codex and Claude subscription accounts. For Claude, use
130
+ the installed official CLI:
131
+
132
+ ```sh
133
+ rlm-agent provider login claude-subscription
134
+ rlm-agent --provider claude-subscription --model cli:claude-code "Inspect this project"
135
+ ```
136
+
137
+ Claude authentication remains within that CLI. Additional provider integrations
138
+ are retained for compatibility; their release qualification is deferred:
139
+
140
+ - `pip install 'rlmness-cli[copilot]'` enables `--provider copilot`. Run
141
+ `rlm-agent provider login copilot` through the official CLI first. This adapter
142
+ uses the official SDK with its own tools and hooks disabled. Sign out with
143
+ `/logout` in that CLI.
144
+ - `--provider claude-subscription --model cli:claude-code` uses the installed,
145
+ unmodified CLI. `provider login claude-subscription` invokes its sign-in.
146
+ This route does not extract subscription OAuth credentials.
147
+ - `--provider xai` reads `XAI_API_KEY`. The experimental `xai-subscription`
148
+ route requires your own registered public OAuth client and compatible API
149
+ entitlement. `provider login xai-subscription --client-registration FILE`
150
+ accepts exactly `client_id`, `authorization_endpoint`, `token_endpoint`,
151
+ `scope`, `resource`, and `redirect_port`. Endpoints must be provider-owned
152
+ HTTPS URLs; `resource` is `null` or `https://api.x.ai/v1`, and `redirect_port`
153
+ selects the registered loopback callback port (zero requests a dynamic port).
154
+ There is no built-in registration or verified subscription entitlement for
155
+ this experimental route. Keep client secrets and tokens out of this file.
156
+
157
+ ## Execution
158
+
159
+ `--engine rlmness` is the default. Recursive agents execute through the backend;
160
+ the frontend does not run another recursive model loop around each backend step.
161
+ `--engine session` selects the previous engine for compatibility.
162
+
163
+ `--kernel wasm` uses separate Pyodide interpreters in a shared Node host.
164
+ `--kernel local` uses host Python with the backend engine; it has machine access.
165
+ The compatibility engine uses its previous IPython kernel for local execution.
166
+ `fetch_url` refuses local and private addresses, including through redirects, unless
167
+ `--allow-private-fetch` is passed. Sandbox code using httpx directly and approved
168
+ shell commands are not covered by this check.
169
+ `--no-network` disables the sandbox network setup. With networking enabled, use
170
+ async httpx; blocking requests-based libraries are not supported by this host.
171
+
172
+ The backend exposes `rlm(piece, instruction=question)` and `gather_rlm(pieces, ...)`.
173
+ Background work uses `await spawn(task, data, keep=False, role=None, model=None)`.
174
+ Handles provide `result`, `status`, `send`, `messages`, `cancel`, and `id`.
175
+ Persistent agents use `keep=True`; they retain saved variables between questions.
176
+ `await children()` lists handles and `await tell_parent(text)` sends a child update.
177
+ Depth, call, cost, live-agent, and time limits apply across recursive execution.
178
+
179
+ ## Workspace approvals
180
+
181
+ Sandbox code reaches the project through `read_file` (whole files or a line range),
182
+ `list_files`, `search_files` (regex search of file contents), `write_file`,
183
+ `edit_file`, `apply_patch`, `ask_user`, and `run`. File paths are confined to the configured workspace.
184
+ Writes, edits, and commands use the application's approval policy. Shell commands
185
+ run with the user's permissions; the workspace path restriction is not an OS shell
186
+ sandbox. Command cancellation and timeout handling terminate the process tree.
187
+
188
+ Use `/auto` in line mode or Shift+Tab in the terminal UI to toggle automatic
189
+ approval for the session. `--auto-approve` enables it at launch. Headless runs deny
190
+ mutations by default. Approval checks bind commands and edit payloads to their content.
191
+
192
+ ## State and playbooks
193
+
194
+ Saved frontend sessions have a matching `.backend.json` state file. Resume loads
195
+ the backend's saved values and supported definitions; unsupported objects are
196
+ reported as dropped. Ephemeral sessions retain state only while the app is open.
197
+ Live background jobs end with the application session; they are not restarted
198
+ automatically after process exit. `/undo` restores its filesystem/transcript
199
+ checkpoint and rolls back saved backend variables, unless they are too large
200
+ to copy; effects outside the workspace are not undone. `rlm-agent session prune
201
+ --older-than DAYS` lists old sessions and snapshots; add `--yes` to remove them.
202
+
203
+ Use `await playbook(id)` to inspect a saved entry, `await skill(id)` to load a skill,
204
+ and `await improve(instructions, shared=False)` to queue a playbook update at the
205
+ turn boundary. Compaction also schedules the existing automatic improvement check,
206
+ as do every 5 finished tasks (`--improve-every`) and any task with 3 or more failed
207
+ tool calls. A memory saved automatically is dropped 3 finished tasks later unless a
208
+ later edit keeps it, since it describes one moment of the work.
209
+ Contracts select their execution engine explicitly with `"engine": "rlmness"`.
210
+ Existing contracts without this field retain the previous session engine. Contract
211
+ settings take precedence over the normal CLI engine default.
212
+
213
+ Contracts can select a playbook explicitly:
214
+
215
+ ```json
216
+ "playbook": {"file": "./playbook.json", "update": false}
217
+ ```
218
+
219
+ The file is relative to the contract workspace. `update: false` allows reading
220
+ entries while rejecting changes; `true` enables updates and automatic checks.
221
+ Contracts that omit this section have no playbook.
222
+
223
+ The shared Node host can stall on a runaway cell. Recovery may reset every sandbox
224
+ in that host. The backend state is a saved namespace, not a complete process clone;
225
+ external effects are not rolled back or replayed by variable restoration.
226
+
227
+ ## Editor and external agents
228
+
229
+ `rlm-agent --acp` serves the Agent Client Protocol over stdio. Configure the editor
230
+ to launch this command with the desired provider and model arguments. Approvals
231
+ and project trust are requested through the editor.
232
+
233
+ `cli:` and `acp:` models use external agents as model providers. For supported ACP
234
+ bridges, run `rlm-agent acp install` and inspect `rlm-agent acp status`.
235
+ ACP model usage may be unreported; use call and time caps as well as a cost cap.
236
+
237
+ ## Development
238
+
239
+ Run tests one file at a time with `bash scripts/test_each.sh`. Failing files print
240
+ their complete diagnostics. The backend integration tests use actual sandbox
241
+ interpreters with scripted model replies and require the sandbox setup.
242
+
243
+ End-to-end tasks give a real model real work and check the workspace it leaves, in
244
+ place, through a tool host over stdio, and over TCP. They cost money, so they run only
245
+ when asked:
246
+
247
+ ```sh
248
+ RLM_AGENT_E2E=1 pytest tests/e2e -m e2e
249
+ ```
250
+
251
+ `RLM_AGENT_E2E_PROVIDER` and `RLM_AGENT_E2E_MODEL` pick the model (default: the Claude
252
+ Code CLI with haiku).
253
+
254
+
255
+ ### Project tools and execution records
256
+
257
+ The default backend provides `await instruction_docs()` to discover project
258
+ instructions and skills, and `await instruction_docs(path)` to read a selected
259
+ file. Discovery excludes build, environment and version-control folders.
260
+ `await fetch_url(url, max_chars=50000)` returns bounded HTTP(S) text, the final
261
+ URL and a truncation flag. It is unavailable with `--no-network`.
262
+
263
+ Ordinary workspace errors return text beginning with `Error:` so a cell can
264
+ inspect and correct a failed operation. Approval refusals still stop the operation.
265
+ Write and edit approvals show a unified diff. A file changed while approval is
266
+ pending must be read again before a new change can be approved.
267
+
268
+ Saved sessions write `<session-id>.backend.events.jsonl` alongside their state.
269
+ These records include generated code, outputs, host-tool results, child lifecycle
270
+ and per-call usage. Contract runs write `<trace-file>.backend.events.jsonl`.
271
+ Usage totals preserve input, output, cache reads/writes and reasoning counts from
272
+ all recursive model calls. Providers that omit counts cannot supply those totals.
273
+
274
+ `rlm-agent session view [id]` replays those steps as cards, and
275
+ `rlm-agent session steps [id] [--json]` prints steps, tokens, cost and time per agent.
276
+
277
+ ### Terminal UI
278
+
279
+ With the default engine each agent step is a card: depth, a short agent id, the step
280
+ number and its state, then the code, the first lines of output and, once it ends,
281
+ tokens, cost and time. Sub-agent cards are indented under their parent. Enter or a
282
+ click opens a card in full; F2 shows the agent tree, F3 a timeline of steps and F4
283
+ the background workers with their heartbeats and scheduled jobs. The status bar shows steps,
284
+ running agents, depth and spend against the run's limits. Messages typed while a
285
+ run is going are queued and sent when it ends.
286
+
287
+ `/diff` shows what the session changed in the project (`/diff last` for the last
288
+ turn, `/diff stat` for a file summary). Agents keep a task list with
289
+ `await todo("add", text)` and `await todo("done", n)` (a `todo` tool in the session
290
+ engine); it is saved with the session, shown in the sidebar and by `/tasks`. The
291
+ session engine also has `ApplyPatch` for multi-file unified diffs, plus `Grep` and `Glob`.
292
+
293
+ ### Remote models and cloud credentials
294
+
295
+ In the model picker, Ctrl+F fetches remote models, Ctrl+T checks credentials, and
296
+ Ctrl+E sets a compatible API base URL. The model list also accepts a custom model
297
+ identifier. The CLI offers `rlm-agent provider models openrouter` and
298
+ `rlm-agent provider test openrouter`. A successful model-list check establishes
299
+ access to that endpoint; it does not prove permission to generate with every model.
300
+
301
+ For Google Vertex, install `rlmness-cli[vertex]`. Vertex support is experimental: mocked authentication checks pass,
302
+ but a live completion with a configured cloud account has not been verified.
303
+ Configure Application Default Credentials, and set `GOOGLE_CLOUD_PROJECT` and optionally `GOOGLE_CLOUD_LOCATION`
304
+ (default `us-central1`). Select `--provider vertex --model google/MODEL_ID`.
305
+ Credentials refresh when needed and remain in memory. Vertex credential checks
306
+ verify ADC refresh; remote model discovery is unavailable for this endpoint, so
307
+ enter a compatible model identifier. Model access still requires a live completion.
308
+
309
+ Workspace commands execute through non-login Bash, with a default 120-second timeout and a maximum of 1,800 seconds.
310
+
311
+ ## Workers
312
+
313
+ A worker is a named agent that keeps running after the terminal closes. It is an
314
+ ordinary saved session, so `--resume` works on it once it has stopped.
315
+
316
+ ```text
317
+ rlm-agent worker start nightly --auto-approve
318
+ rlm-agent worker send nightly "check the build"
319
+ rlm-agent worker schedule nightly "review open issues" --in 3600
320
+ rlm-agent worker schedule nightly "run the tests" --at 2027-01-02T09:00 --every 86400
321
+ rlm-agent worker schedule nightly "weekday build" --cron "0 9 * * 1-5" --timezone America/New_York
322
+ rlm-agent worker list
323
+ rlm-agent worker jobs nightly
324
+ rlm-agent worker log nightly --follow
325
+ rlm-agent worker attach nightly
326
+ rlm-agent worker recover
327
+ rlm-agent worker incidents nightly
328
+ rlm-agent worker watch
329
+ rlm-agent worker watch --stop
330
+ rlm-agent worker stop-all --wait 60
331
+ rlm-agent worker stop nightly
332
+ ```
333
+
334
+ Cron schedules accept five numeric fields or `@hourly`, `@daily`, `@weekly`, and
335
+ `@monthly`. Lists, ranges, and steps work within fields. If both day fields are
336
+ set, both must match. The timezone defaults to UTC. Missing local times during a
337
+ daylight-saving jump are skipped, and repeated local times can run at both
338
+ occurrences. After downtime, one overdue run is taken and the next run follows
339
+ the wall-clock schedule.
340
+
341
+ `worker recover` restarts interrupted saved workers from their original launch
342
+ settings and session IDs. Pass a worker name to recover only that worker.
343
+ `worker incidents NAME` shows worker exits and fleet recovery attempts with the
344
+ saved session, last heartbeat, active turn, affected message and job IDs, and
345
+ restart outcome. A one-shot job interrupted by a worker exit remains visible in
346
+ `worker jobs` and is skipped on restart.
347
+ `worker watch` runs a fleet monitor in the foreground. It checks for interrupted
348
+ workers at startup and continues checking while it runs. Use `worker watch --stop`
349
+ from another terminal to stop the monitor.
350
+ `worker service install` registers and starts a watcher for the current app home
351
+ using Windows Task Scheduler, the Linux systemd user manager or a macOS launchd
352
+ agent. It starts again
353
+ when the user logs in. Use `worker service status`, `start`, `stop`, and
354
+ `uninstall` to manage it. The service uses the Python installation and session
355
+ directory from installation time. On Windows and macOS, watcher output goes to
356
+ `fleet-service.log` in the app home. On Linux, use the user journal. The macOS
357
+ agent is covered by tests of its definition and commands, not yet on a Mac.
358
+ `worker stop-all` lets the current turns finish and records the stop request
359
+ for interrupted workers, so recovery skips them.
360
+
361
+ Start a saved worker with `--idle-passivate 300` to close its process after
362
+ five idle minutes. With `worker watch` or the watcher service running, a queued
363
+ message or due job wakes the same saved session. `worker attach NAME` also wakes
364
+ it. An explicit stop suppresses automatic wakeup until you start the worker again.
365
+
366
+ Send `/goal <objective>` and then `/autonomous` to a saved worker session to
367
+ keep working after you detach. The worker saves its continuation and budgets
368
+ before starting the next turn. A queued turn survives a restart. If the worker
369
+ was killed during a turn, inspect the saved conversation and re-enable
370
+ `/autonomous` to continue.
371
+
372
+ Start flags are the normal run flags. The folder's trust is decided when you start
373
+ it, because a worker has nobody to ask. For the same reason anything needing
374
+ approval is refused unless it was started with `--auto-approve`, and `ask_user`
375
+ has no answer. A job that was running when a worker died is not run again; a job
376
+ due while a worker was down runs when it next starts. Workers do not restart on
377
+ their own after a reboot.
378
+
379
+ ## Goals and autonomous mode
380
+
381
+ `/goal TEXT [--tokens N]` sets an objective that is put in front of the model on every
382
+ turn until it calls `await goal_done(summary)`; `/goal pause`, `resume` and `clear`
383
+ manage it. `/autonomous` then starts the next turn by itself while the goal is open,
384
+ and stops at its limits (`/autonomous turns N`, `tokens N`, `seconds N`), when the
385
+ goal is done, or when you press Esc. `/autonomous gate CMD` sets the default
386
+ verification command. Use `/autonomous gate add NAME CMD` for additional gates,
387
+ `/autonomous gate list` to see their latest status, and
388
+ `/autonomous gate remove NAME` to remove a named gate. Every configured command
389
+ must exit zero on the same `goal_done` attempt. A retry reruns all gates and
390
+ records each result separately.
391
+ Autonomous continuation also stops if the same failed operation, or the same
392
+ pair of failed turns, repeats three times. This check uses tool arguments and
393
+ root cell failures, so rephrasing the final reply does not reset it.
394
+
395
+ ## Agents working together
396
+
397
+ Open sessions and workers can reach each other. In a cell: `await list_agents()`,
398
+ `await send_message(to, text)`, `await read_messages()`. A message to a worker runs as
399
+ its next task; a message to a session is shown to it before its next turn.
400
+ Pass `receipt=True` to `send_message` to get a message ID and recipient kind. The
401
+ sender can check `await message_receipt(to, message_id, kind)` after reconnecting.
402
+ For a session, `read` means the recipient retrieved the message through the inbox.
403
+ For a worker, the receipt reports the queued, running, or final task outcome.
404
+ `await schedule(task, in_seconds=..., every=None, worker=None)` or
405
+ `await schedule(task, cron="0 9 * * 1-5", timezone="America/New_York")` queues work on a
406
+ worker, and `await heartbeat(text)` reports progress, shown in the terminal and in
407
+ `rlm-agent worker log`.
408
+
409
+ Use `await watch_start(job=job_id)` or `await watch_start(path="results")` to save a
410
+ subscription. The recursive backend also supports `await watch_child(handle)` for a
411
+ kept child you own. `watch_list()` shows watch IDs and unread counts. Read event
412
+ metadata with `watch_events(watch_id)` and retrieve an event with
413
+ `watch_read(watch_id, event_id)`. Read status survives reopening. Watches sample
414
+ changes and can combine several changes into one event. `watch_cancel(watch_id)`
415
+ removes a watch and its history.
416
+
417
+ End a backend cell with `await wait_for_activity(watch_id, timeout=60)` to pause
418
+ before the next provider request, until a new watch event, pending steering, or
419
+ the timeout. The cell finishes before the wait starts. In the Node engine a
420
+ waiting batch child also returns its fan-out permit and reacquires it before
421
+ continuing.
422
+
423
+ Other functions: `await web_search(query)` when `BRAVE_API_KEY`, `TAVILY_API_KEY` or
424
+ `SERPER_API_KEY` is set; `await context_usage()`; `await compact()` to summarize older
425
+ conversation when the turn ends. `/btw QUESTION` answers from the conversation so far; neither the
426
+ question nor the answer is kept in it.
427
+
428
+ `/image PATH` attaches a PNG, JPEG, GIF or WebP file (up to 5 MB) to your next
429
+ message. Use a model and provider that accept image input.
430
+
431
+ Press F1 for keyboard help. Focus a finished step and press Space to hide or
432
+ show its details, or Enter to open the full step.
433
+
434
+ To keep a saved session running between terminals, close the original terminal
435
+ session and start its detached process from the project folder:
436
+
437
+ ```sh
438
+ rlm-agent session detach SESSION_ID
439
+ rlm-agent session attach SESSION_ID
440
+ rlm-agent session attach SESSION_ID --tui
441
+ rlm-agent worker stop session-SESSION_ID
442
+ ```
443
+
444
+ Saved interactive sessions use the supervisor from the first turn.
445
+ Reconnect with `rlm-agent --resume SESSION_ID`. Use `--repl` for the line client,
446
+ `rlm-agent tui` to select Textual, or `--foreground` to run the interactive session
447
+ in the current process. `--supervised` explicitly selects the worker path.
448
+ A supervised worker shows approval requests and agent questions in
449
+ both clients. Follow the displayed `/answer REQUEST_ID VALUE` prompt to respond.
450
+ An unanswered request expires after 60 seconds. Approval responses are `once`,
451
+ `always`, `auto`, or `deny`. Questions accept text or a displayed option number.
452
+
453
+ Type `/detach` in the attached terminal to leave the process running. A detached
454
+ session uses the same unattended approval rules as a worker. Start detachment
455
+ between turns. A running turn cannot move between processes.
456
+ Saved sessions have a single active writer across terminal and worker processes.
457
+ The Textual attachment replays the saved conversation from the start of
458
+ detached execution and follows new prompts, streamed replies, and tool activity.
459
+ Multiple terminals can attach to the same worker and send prompts. Press Ctrl+D
460
+ to close the Textual client and leave the worker running. Ctrl+C interrupts the
461
+ current worker turn, or closes the client if the worker is idle.
462
+
463
+ A kept child in a saved session accepts `receipt = await handle.send(text)`
464
+ while it is busy. Use `await handle.delivery(receipt)` to inspect its status.
465
+ Kept children process these messages in order as follow-up turns. Queued
466
+ messages resume on the next parent run after reopening the session. A message
467
+ already running at the time of a crash is marked interrupted.
468
+ A detached supervisor restarts a crashed worker from its saved session, with
469
+ backoff. An interrupted turn is reported on resume.
470
+
471
+ On a saved session with the default engine, agents created with
472
+ `spawn(..., keep=True)` by the root or another kept agent retain their ID,
473
+ last completed result, and supported
474
+ kernel values across reopening. Find them with `children()` and send a new task
475
+ when the child is idle. In-flight child work is not replayed after a restart.
476
+
477
+ Use `await name_child(handle, "reviewer")` to name a child under its parent,
478
+ then `await find_child("reviewer")` to recover its handle. `await child_messages(handle)`
479
+ lists unread child-note receipts and `await read_child_message(handle, id)` retrieves a
480
+ note and records its read state. `await child_delivery_receipt(handle, id)` looks up
481
+ an existing backend send receipt. `await child_info(handle)`
482
+ shows status, pending deliveries, and recorded model usage without consuming the
483
+ result or messages. In the backend engine, names and usage for kept children
484
+ survive reopening the saved session.
485
+
486
+ Use `await steer_child(handle, text, message_id=None)` to add an instruction
487
+ at an active child's next model request. It returns a receipt, also available
488
+ through `child_info`. Reusing the message ID with the same text and child
489
+ returns the original receipt. If the active turn ends before another model
490
+ request, the receipt expires. Use `send()` to queue a separate follow-up turn.
491
+
492
+ For a protected HTTP MCP server, configure an `oauth` object beside its `url`
493
+ with `issuer`, a registered public `client_id`, and `redirect_port`. Register
494
+ `http://127.0.0.1:PORT/oauth/callback` with the issuer. Add `scope` if needed.
495
+ Use `/mcp login NAME` to sign in and `/mcp logout NAME` to disconnect locally.
496
+ Access tokens refresh when the server issues a refresh token. To reuse a login
497
+ after reopening, install `rlmness-cli[mcp-keyring]` and set `"persist": true` in
498
+ the OAuth object to use your platform credential store. With persistence
499
+ disabled, credentials live in the current process.
500
+
501
+ Use `"connector": "slack"` or `"connector": "notion"` instead of a server URL
502
+ to use a built-in endpoint. Supply your registered OAuth client details. For
503
+ confidential clients, set `client_secret_env` to the name of the environment
504
+ variable that holds the secret.
505
+
506
+ `rlm-agent factory workflow.json` runs a sequence of contract stages. Each
507
+ stage needs its own trace file. A failed stage stops the workflow. On success,
508
+ its final answer is included as data in the next stage's prompt.
509
+
510
+ ```sh
511
+ rlm-agent factory init my-review contract.json review
512
+ rlm-agent factory list
513
+ rlm-agent factory export my-review workflow.json
514
+ rlm-agent factory import my-other-review workflow.json
515
+ rlm-agent factory run my-review --state review-state.json
516
+ ```
517
+
518
+ The bundled recipes are `build`, `review`, and `release-review`. Run a saved
519
+ factory from a cell with `await factory_run("my-review")`, subject to workspace
520
+ command approval. Reuse the same `--state` file to continue after completed
521
+ stages. If a stage was interrupted or failed, review its workspace changes
522
+ before explicitly adding `--retry-stage`.
523
+ For a stage that needs to keep one agent and its kernel through several turns,
524
+ use `"resident": ["first prompt", "next prompt"]` in place of `prompt`. The
525
+ whole group shares one contract and counts as one checkpoint.
526
+
527
+ For a dependency graph, use `"format": "rlmagent.factory/2"` with a
528
+ `stages` object keyed by stage name. Each stage has a `contract`, a
529
+ `prompt`, and an optional `after` list. A stage normally requires all its
530
+ dependencies to succeed. Set `when` to `any_failed` for a recovery stage or
531
+ `always` to run after dependencies settle. `parallel` controls concurrency,
532
+ and stages with overlapping workspace paths are serialized.
533
+
534
+ Set a stage's `foreach` field to the name of a direct dependency that returns
535
+ a JSON array. The stage runs once for each item, and its dependents receive an
536
+ array of results in input order. A run can expand up to 128 items. On an explicit
537
+ retry, completed items are reused unless an upstream dependency is also rerun.
538
+
539
+ An optional `policy` object can set `max_transitions`, `max_live_agents`,
540
+ and `on_failure`. Each admitted stage or item consumes one transition,
541
+ including retries. The live-agent limit reserves capacity from the stage
542
+ contracts before starting them. Set `on_failure` to `stop` to finish active
543
+ stages and leave unstarted work waiting after a failure. The default
544
+ `continue` preserves the graph's dependency guards.
545
+
546
+ ```sh
547
+ rlm-agent factory launch graph.json
548
+ rlm-agent factory status RUN_ID
549
+ rlm-agent factory view RUN_ID
550
+ rlm-agent factory cancel RUN_ID
551
+ rlm-agent factory resume RUN_ID --retry-stages
552
+ ```
553
+
554
+ Editors can launch `rlm-agent --acp`, supply stdio or streamable HTTP MCP
555
+ servers for each session, and steer an active turn with text. Steering enters
556
+ at the next harness step. Closing a session stops its work and reports usage
557
+ and request counts. Saved sessions can be loaded again.
558
+
559
+ Saved sessions append a request ledger beside the transcript. It records how
560
+ model requests follow one another, delegate to children, receive child
561
+ returns, and follow compaction. HTTP model requests carry the corresponding
562
+ `X-Rlmagent-Request-Id`. Use `--engine session` when you need the same live
563
+ kernel across prompts and compaction.
564
+
565
+ ```json
566
+ {
567
+ "format": "rlmagent.factory/1",
568
+ "stages": [
569
+ {"contract": "inspect.json", "prompt": "Find the cause of the failing test."},
570
+ {"contract": "fix.json", "prompt": "Fix the issue and verify the result."}
571
+ ]
572
+ }
573
+ ```
574
+
575
+ `rlm-agent update` shows the installed version. Use `rlm-agent update --apply`
576
+ to upgrade an installation from a package index.
577
+
578
+ `rlm-agent status` shows configuration, sandbox, git, MCP, search, workers and open
579
+ sessions; `rlm-agent doctor` reports problems and `doctor --fix` repairs the ones it
580
+ can (stale workers and sessions, a missing Pyodide).
581
+
582
+ ## Background jobs and watches
583
+
584
+ `await job_start(cmd)` runs a command in the background; `job_read(id, cursor)` returns
585
+ what it wrote since `cursor`, `job_wait(id)` waits for it and `job_stop(id)` ends it and
586
+ everything it started. `await service_start(name, cmd, ready=regex)` keeps a dev server
587
+ or similar running and can wait for its ready line. `await watch(job=id)`,
588
+ `watch(path=p)` or `watch(messages=True)` waits until a job writes or ends, a path
589
+ changes, or another agent writes. Jobs belong to the session, so a sandbox restart
590
+ does not lose them, and they need the same approval as `run()`.
591
+
592
+ `await history(start, end)` reads every saved message of the session, including what
593
+ compaction summarized away; `history(agent=RUN_ID)` reads one agent's steps. When a
594
+ kernel process dies mid-run, a new one is started and the model is told which state
595
+ was lost, up to three times per kernel.
596
+
597
+ ## Run policy
598
+
599
+ | Flag | Effect |
600
+ | --- | --- |
601
+ | `--deny-git` | Refuse git commands that touch other branches, remotes or history (push, fetch, checkout, branch, tag, reset, ...) |
602
+ | `--max-tool-output BYTES` | Most output one cell shows the model (default 20000; zero disables this cap; the start and end are kept) |
603
+ | `--max-compactions N` | Most compactions in the session |
604
+ | `--agent-max-tokens N` | Most completion tokens any one agent may spend |
605
+ | `--search-block DOMAIN` | Drop web search results from a domain, `*.domain` or origin (repeatable) |
606
+
607
+ A contract can set the same through an optional `policy` object with `allow_git`,
608
+ `max_tool_output_bytes`, `max_compactions`, `agent_max_tokens` and `search_block`
609
+ (every field given, `null` for the default). The summary a contract run prints ends
610
+ with `stop_reason`: `done`, `max_calls`, `max_cost`, `max_tokens`, `max_seconds`,
611
+ `agent_tokens`, `compaction_failed`, `no_answer`, `cancelled` or `error`.
612
+
613
+ Optional `policy.allowed_tools` limits both the model tool list and the host
614
+ functions available to Python, including in descendants. For example,
615
+ `["python", "read_file", "list_files"]` allows a Wasm Python cell to read and
616
+ list workspace files. Model tools still have to appear in the contract's
617
+ `tools` list. Omit the allowlist to use the original tool policy. Restricted
618
+ Python requires Wasm. Delegation and guest networking use the separate
619
+ `limits.max_depth` and `kernel.network` settings.
620
+
621
+ Optional `limits.max_new_tokens` meters reported uncached input and output
622
+ across the whole run, including compaction. The run admits one provider
623
+ request at a time with this limit enabled. It estimates each request's size
624
+ from the full prompt and the provider's reply limit. An estimate can be low.
625
+ The run reports `max_tokens` when the budget refuses admission or settlement.
626
+
627
+ Set `limits.strict_new_tokens` to `true` for counted admission with a
628
+ provider-enforced reply cap. The first-party OpenAI Responses API over HTTP
629
+ supports this mode. Each admitted generation has one attempt. Cached input
630
+ counts toward the reservation, then only new tokens count toward settlement.
631
+ The Codex and Claude subscription routes reject strict mode before generation.
632
+ Omitting `strict_new_tokens` keeps estimate-based admission on those routes.
633
+
634
+ Cells that fail in a familiar way (a missing `await`, quotes nested in an f-string, a
635
+ missing module, a timeout, an empty reply) get a one-line hint with the error.
636
+
637
+ `--max-calls 0` admits no model requests. This differs from an omitted call budget,
638
+ which selects the default. In a policy, `max_tool_output_bytes: 0` explicitly
639
+ disables that output cap; `null` selects the default cap.
640
+
641
+ Contracts can use the two saved-account routes without exporting tokens. For Codex,
642
+ set the model to `{"provider":"codex","name":"MODEL","api_key_env":null,"base_url":null}`.
643
+ For Claude use provider `claude-subscription` and model name `cli:claude-code` or
644
+ `cli:claude-code?model=MODEL`, also with null key and endpoint fields. These routes
645
+ use the same signed-in accounts as the normal CLI and reject credential/endpoint
646
+ overrides. Codex contracts use the fixed Responses HTTP route. Claude runs through
647
+ the official CLI. Sign in before starting a contract; a contract never initiates login.
648
+
649
+ For inline ACP runtime contracts, use `"credential":{"account":"codex"}` or
650
+ `"credential":{"account":"claude-subscription"}` matching the contract provider.
651
+ Native API-key providers retain their explicit `api_key` and `headers` credential object.
652
+
653
+ ACP snapshots retain current-runtime `treeTotals` and additionally expose
654
+ `lifetimeTotals`, `lifetimeUsage`, and `lifetimeCoverage` for the persisted request
655
+ ledger plus current calls, deduplicated by request ID. Reopening a session reloads
656
+ these lifetime totals without consuming the new runtime's admission budget. Older
657
+ records with omitted usage fields or unknown pricing are counted in coverage;
658
+ missing usage is never presented as a complete measurement.
659
+
660
+ ## Split execution
661
+
662
+ The agent loop and its keys can stay on one machine while the tools work somewhere
663
+ else. Start a tool host beside the files:
664
+
665
+ ```sh
666
+ python -m rlmagent.toolhost --root /work # over stdio
667
+ RLM_AGENT_TOOLS_TOKEN=... python -m rlmagent.toolhost --root /work --tcp 0.0.0.0:7700
668
+ ```
669
+
670
+ Then point a session at it with `--tools-at "python -m rlmagent.toolhost --root /work"`
671
+ or `--tools-at tcp://host:7700` (with the same `RLM_AGENT_TOOLS_TOKEN`). File reads,
672
+ search, edits, patches, commands and jobs then run in the tool host. Approvals and the
673
+ git guard are decided in the harness before anything is sent; the host only runs what
674
+ it is asked, confined to its root.
675
+
676
+ ## MCP servers
677
+
678
+ List Model Context Protocol servers in `mcp.json` in the rlm-agent home, or in
679
+ `.rlm-agent/mcp.json` of a trusted project:
680
+
681
+ ```json
682
+ {"servers": {
683
+ "files": {"command": "npx", "args": ["-y", "some-mcp-server"], "env": {"TOKEN": "${MY_TOKEN}"}},
684
+ "docs": {"url": "https://example.com/mcp", "headers": {"Authorization": "Bearer ${DOCS_KEY}"}}
685
+ }}
686
+ ```
687
+
688
+ `${NAME}` is read from the environment when a server starts, so keys stay out of the
689
+ file. Servers start on first use. Cells call `await mcp_tools()` and
690
+ `await mcp(server, tool, arguments)`; the session engine has matching tools. Calls
691
+ need approval unless the server marks the tool read-only. `/mcp` lists servers,
692
+ their state and tools; `/mcp NAME` starts one.
693
+
694
+ ## Project extensions
695
+
696
+ A Python file in `.rlm-agent/extensions/` (or `~/.rlm-agent/extensions/`) with a
697
+ `register()` function is loaded at startup and by `/reload`. Project files load
698
+ only in a trusted folder. `register()` may return a mapping of names to functions,
699
+ a `ToolSpec`, or a list of those:
700
+
701
+ ```python
702
+ def word_count(path):
703
+ """Count the words in a file."""
704
+ with open(path) as handle:
705
+ return len(handle.read().split())
706
+
707
+ def register():
708
+ return {"word_count": word_count}
709
+ ```
710
+
711
+ A function becomes `await word_count(...)` in a cell, and a tool under `--engine
712
+ session`. It runs in the host with your permissions, outside the sandbox and outside
713
+ approval, so enforce any rule it needs in its own code. It cannot replace a built-in
714
+ name. `/tools` lists what is really available; in a cell, `await capabilities()`
715
+ reports the same along with the limits in force.
716
+
717
+ ## Manual harness refinement
718
+
719
+ Use `/refine` when a conversation contains a correction or procedure worth
720
+ retaining. It starts a bounded background review and returns immediately:
721
+
722
+ ```text
723
+ /refine Remember the repository's focused validation command
724
+ /refine status
725
+ /refine cancel
726
+ ```
727
+
728
+ Only one review may be pending per session. The refiner can inspect saved guidance
729
+ and stage create, update, or delete operations. It cannot execute Python, run
730
+ commands, modify project files, or replace the base system instructions. A review
731
+ may make no changes. Its limits are 12 model steps, 8 edit attempts, and 300 seconds;
732
+ the normal provider and tree budget also apply.
733
+
734
+ There are three entry kinds:
735
+
736
+ | Kind | Purpose |
737
+ | --- | --- |
738
+ | `prompt` | A focused behavioral note |
739
+ | `skill` | A Markdown workflow with YAML `name` and `description` metadata |
740
+ | `subagent` | Guidance for assigning and executing delegated tasks |
741
+
742
+ Workflow metadata must match its stable entry id. Individual entries are limited
743
+ to 32 KiB. Existing Python-function playbook skills keep their original meaning.
744
+ Installed skill files are never overwritten by refinement.
745
+
746
+ `/refine evidence` shows, per saved change in this project: when it was saved, how
747
+ many later tasks actually sent it to the model, failed tool calls per task before and
748
+ after, and your verdict from `/refine rate <change> better|same|worse`. The counts
749
+ are signals rather than proof, because tasks differ.
750
+
751
+ A proposal that changes guidance waits for you: `/refine show` lists each added,
752
+ changed or removed entry with a diff of its text, `/refine apply` saves it and
753
+ `/refine cancel` drops it. An approved proposal waits for a turn boundary before it
754
+ is saved or activated; if the session is idle it commits immediately.
755
+ `/refine status` distinguishes a running review, a proposal awaiting activation,
756
+ completion, cancellation, and failure. Beginning the next submission or finishing
757
+ the current turn services that boundary. Updated guidance then applies to the
758
+ root and newly created child agents. Running children keep their existing prompt.
759
+ Use `/refine auto review` to stage a whole-harness proposal after compaction,
760
+ `/refine auto apply` to opt in to automatic activation, or
761
+ `/refine auto off` to cancel that mode for the current session.
762
+ Notes over 400 characters appear shortened in the prompt, with the rest available
763
+ through `await guidance("entry-id")`.
764
+ Workflow names and descriptions appear in the prompt; the full procedure is
765
+ available through `await guidance("entry-id")` in Python or `/skill:entry-id`.
766
+
767
+ Saved guidance is project-scoped under
768
+ `~/.rlm-agent/harness/<project-path-hash>/state.json`, so later sessions in the
769
+ same workspace inherit it. Read/modify/write operations are locked across
770
+ processes and reject proposals based on superseded state. Invalid state is
771
+ reported rather than replaced with an empty harness. The saved history includes
772
+ the evidence, expected benefit, and edits for each committed proposal.
773
+
774
+ `/refine scope session` selects guidance inherited along the saved conversation
775
+ branch. Rewinding restores the guidance attached to that ancestry; edits in a
776
+ sibling branch stay separate. `/refine scope project` returns to shared project
777
+ guidance. `/refine rollback N` restores an archived revision while idle and records
778
+ the restoration as a new revision. `/refine off`
779
+ sets a global preference that stops further review requests and removes supplemental
780
+ guidance from subsequent model requests, including requests in other processes.
781
+ An already submitted request cannot be recalled by changing this preference.
782
+
783
+ `--no-session` keeps this harness in memory. Plan mode prevents changes, and abort,
784
+ rewind, inference-route changes, or shutdown discard pending work. Contract runs
785
+ do not load this ambient harness or enable `/refine`.
786
+
787
+ This mechanism runs only when explicitly requested. Existing `/improve` and its
788
+ automatic playbook scheduling are separate. Proposals from the automatic playbook
789
+ check are held: `/improve pending` lists them, `/improve accept N` saves one and
790
+ `/improve reject N` drops it. `--apply-auto-improve` saves them at once instead. A committed refinement means its
791
+ structure and persistence checks passed; its expected benefit has not been
792
+ established by a performance benchmark.
793
+
794
+ ## Portable sessions and delivery
795
+
796
+ `rlm-agent session export ID --format html` produces a standalone escaped HTML
797
+ transcript with tool arguments and branch and compaction summaries. JSONL keeps
798
+ the original records; `rlm-agent session import FILE` validates their references
799
+ and imports them under a fresh local identity.
800
+
801
+ `rlm-agent session share ID` previews the complete outgoing unlisted gist and its
802
+ SHA256 digest without uploading. To publish that exact payload, repeat with
803
+ `--publish --sha256 DIGEST` and a locally configured `GH_TOKEN` or `GITHUB_TOKEN`.
804
+ Unlisted links can be read by anyone who obtains them. A changed session requires
805
+ a fresh preview and digest.
806
+
807
+ The terminal copy action first tries the native clipboard locally. Over SSH or
808
+ tmux it emits OSC52, reporting delivery as unconfirmed because the terminal may
809
+ block it. Keymap overrides are validated for conflicts before they are applied.
810
+
811
+ Capability packages install into isolated stores with a resource manifest and
812
+ recorded distribution versions. Use `rlm-agent package install NAME SOURCE`,
813
+ `package update NAME --source REPLACEMENT`, and `package remove NAME`. Add
814
+ `--local` for a project store; project resources require project trust. Local
815
+ wheel installations also record their SHA256 digest.
816
+
817
+ Successful package changes automatically collect inactive cache directories older
818
+ than 30 days. Active installations, directories loaded by this process, and linked
819
+ directories are preserved. `package prune --older-than DAYS` previews eligible
820
+ directories; add `--apply` to remove them, or `--local` for the project store.
821
+
822
+ ## Managed offline releases
823
+
824
+ `rlm-agent update --manifest /path/release.json` validates and previews a local
825
+ wheel bundle. Its manifest has `format: "rlmagent.release/1"`, an exact `version`,
826
+ a `channel` (`stable`, `preview`, or `nightly`), and `artifacts`, each containing
827
+ `filename` and `sha256`. Optional `extras` selects bundled optional dependencies.
828
+ Include the matching backend wheel and every dependency; installation uses
829
+ `--no-index` and rejects direct URL dependencies.
830
+
831
+ Add `--apply` to install into a fresh virtual environment and activate it only
832
+ after health checks. `--drain --wait 60 --restart-workers` lets current worker
833
+ tasks finish, restarts them with saved settings, and holds new work until fleet
834
+ activation completes. A drain timeout leaves processes alive. Failed activation
835
+ restores the prior installation; interrupted activation is recovered on the next
836
+ managed command. `update --managed --rollback --apply` selects the previous slot.
837
+ Use `rlm-agent update --run ...` to launch the active managed installation.
838
+
839
+ Managed channels describe a supplied, verified bundle; they do not publish it.
840
+ The index updater selects final releases for `stable`, non-development prereleases
841
+ for `preview`, and development releases for `nightly`. It skips yanked releases,
842
+ empty releases and artifacts incompatible with the current Python version. Preview
843
+ and nightly installs pin the selected version. If that channel has no eligible
844
+ published release, the updater reports this and leaves the installation unchanged.
845
+
846
+ ### Execution continuity and failure handling
847
+
848
+ Each active WebAssembly kernel runs in its own Node worker. A timed-out cell
849
+ terminates that worker; sibling kernels retain their state. The default engine
850
+ keeps its interpreter across turns and conversation compaction, including imported
851
+ modules, object identities and asynchronous tasks. Resident retained children reuse
852
+ their interpreter on follow-up. Closing a session releases its interpreters.
853
+ After a process restart, recovery restores supported checkpoint values and
854
+ definitions; it cannot restore arbitrary live objects or unfinished Python tasks.
855
+
856
+ `--request-timeout SECONDS` bounds each complete model response, including nested
857
+ agent and summary requests (default 300). Contracts may set
858
+ `limits.request_timeout`; existing contracts use the same default. This is separate
859
+ from `--cell-timeout` and the whole-run `--max-seconds` limit. Invalid compaction
860
+ summaries get at most three attempts. A failed compaction keeps the original
861
+ history and does not consume the successful-compaction allowance. Session write
862
+ failures report the affected session and file instead of silently dropping records.
863
+
864
+ Execution processes inherit a small set of operating-system environment variables.
865
+ Host API-key and control variables are excluded from local kernels and shell jobs.
866
+ Approved commands and background jobs use an isolated `/workspace` mount by
867
+ default. Install Bubblewrap on Linux or in the default WSL distribution on Windows.
868
+ Use Linux executables and paths relative to the workspace for these commands.
869
+ `--shell-network` enables network access inside that workspace sandbox.
870
+ `--shell-access host` grants commands your host filesystem permissions. Contracts
871
+ can set `policy.shell_access` and `policy.shell_network`, and tool hosts accept the
872
+ same shell options. Select `--kernel local` explicitly for host Python execution.
873
+ A missing Wasm runtime stops with setup instructions.
874
+
875
+ Background job output is capped at 8 MiB on disk while the process output continues
876
+ to drain. `job_read` returns Unicode-safe byte cursors; job summaries include
877
+ stored bytes, total bytes and truncation state. Job metadata is stored under its
878
+ session, so reopening a session can recover its job records. `job_start` also
879
+ accepts `argv=[...]` for direct execution and explicit `env={...}` overrides.
880
+ Use `service_start(..., persist=True)` only for a service intentionally kept alive
881
+ after session shutdown. Reopen its owning session to read it or stop it by name
882
+ with `job_stop`. Ordinary services and jobs are stopped when their session closes.