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.
- rlmagent/__init__.py +1 -0
- rlmagent/__main__.py +8 -0
- rlmagent/acp/__init__.py +1 -0
- rlmagent/acp/runtime.py +71 -0
- rlmagent/acp/server.py +598 -0
- rlmagent/acp/updates.py +128 -0
- rlmagent/agentnet.py +237 -0
- rlmagent/agents/__init__.py +1 -0
- rlmagent/agents/approval.py +90 -0
- rlmagent/agents/bridge.py +109 -0
- rlmagent/agents/budget.py +212 -0
- rlmagent/agents/child_handles.py +46 -0
- rlmagent/agents/child_mailbox.py +30 -0
- rlmagent/agents/kernel_api.py +156 -0
- rlmagent/agents/output.py +34 -0
- rlmagent/agents/patch.py +107 -0
- rlmagent/agents/prompts.py +156 -0
- rlmagent/agents/trace.py +290 -0
- rlmagent/agents/tree.py +682 -0
- rlmagent/agents/wasm_api.py +105 -0
- rlmagent/agents/workspace.py +357 -0
- rlmagent/autopilot.py +447 -0
- rlmagent/backend.py +946 -0
- rlmagent/backend_context.py +74 -0
- rlmagent/cli/__init__.py +5 -0
- rlmagent/cli/config_cmd.py +177 -0
- rlmagent/cli/health.py +156 -0
- rlmagent/cli/main.py +1194 -0
- rlmagent/cli/update.py +188 -0
- rlmagent/clipboard.py +63 -0
- rlmagent/config/__init__.py +37 -0
- rlmagent/config/config.py +297 -0
- rlmagent/config/loader.py +119 -0
- rlmagent/config/prompts.py +124 -0
- rlmagent/config/secure_input.py +213 -0
- rlmagent/config/store.py +275 -0
- rlmagent/context/__init__.py +47 -0
- rlmagent/context/budget.py +557 -0
- rlmagent/contract.py +311 -0
- rlmagent/contract_run.py +232 -0
- rlmagent/conversation.py +2547 -0
- rlmagent/cron.py +77 -0
- rlmagent/directives.py +893 -0
- rlmagent/discovery.py +356 -0
- rlmagent/execution_log.py +66 -0
- rlmagent/factory.py +189 -0
- rlmagent/factory_graph.py +413 -0
- rlmagent/harness/__init__.py +63 -0
- rlmagent/harness/contracts/__init__.py +1 -0
- rlmagent/harness/contracts/stream.py +129 -0
- rlmagent/harness/contracts/tooling.py +127 -0
- rlmagent/harness/contracts/transcript/__init__.py +68 -0
- rlmagent/harness/contracts/transcript/_base.py +29 -0
- rlmagent/harness/contracts/transcript/diagnostics.py +52 -0
- rlmagent/harness/contracts/transcript/entries.py +180 -0
- rlmagent/harness/contracts/transcript/segments.py +64 -0
- rlmagent/harness/contracts/values.py +6 -0
- rlmagent/harness/driver.py +397 -0
- rlmagent/harness/engine.py +489 -0
- rlmagent/harness/mending.py +153 -0
- rlmagent/harness/provider/__init__.py +1 -0
- rlmagent/harness/provider/base.py +27 -0
- rlmagent/harness/provider/wire.py +189 -0
- rlmagent/harness/py.typed +0 -0
- rlmagent/harness/session/__init__.py +5 -0
- rlmagent/harness/session/index.py +218 -0
- rlmagent/harness/session/lease.py +66 -0
- rlmagent/harness/session/records.py +118 -0
- rlmagent/harness/session/replay.py +165 -0
- rlmagent/harness/session/store.py +155 -0
- rlmagent/harness/session/summary.py +46 -0
- rlmagent/hints.py +47 -0
- rlmagent/history.py +92 -0
- rlmagent/hooks/__init__.py +1 -0
- rlmagent/hooks/hooks.py +1 -0
- rlmagent/instructions.py +157 -0
- rlmagent/job_runner.py +117 -0
- rlmagent/jobs.py +365 -0
- rlmagent/kept_agents.py +397 -0
- rlmagent/kernel/__init__.py +5 -0
- rlmagent/kernel/session.py +205 -0
- rlmagent/kernel/wasm.py +169 -0
- rlmagent/logs.py +208 -0
- rlmagent/managed_release.py +368 -0
- rlmagent/mcp.py +411 -0
- rlmagent/mcp_oauth.py +213 -0
- rlmagent/model/__init__.py +29 -0
- rlmagent/model/_claude/__init__.py +1 -0
- rlmagent/model/_claude/courier.py +117 -0
- rlmagent/model/_claude/emitter.py +378 -0
- rlmagent/model/_oai/__init__.py +1 -0
- rlmagent/model/_oai/helpers.py +256 -0
- rlmagent/model/_oai/normalize.py +263 -0
- rlmagent/model/_oai/parsers.py +317 -0
- rlmagent/model/_oai/payloads.py +226 -0
- rlmagent/model/_oai/transport.py +127 -0
- rlmagent/model/claude.py +552 -0
- rlmagent/model/copilot.py +142 -0
- rlmagent/model/correlation.py +21 -0
- rlmagent/model/deadline.py +19 -0
- rlmagent/model/discovery.py +181 -0
- rlmagent/model/external/__init__.py +11 -0
- rlmagent/model/external/acp.py +202 -0
- rlmagent/model/external/acp_install.py +109 -0
- rlmagent/model/external/cli.py +248 -0
- rlmagent/model/external/textcalls.py +57 -0
- rlmagent/model/failover.py +129 -0
- rlmagent/model/google.py +199 -0
- rlmagent/model/limits.py +46 -0
- rlmagent/model/oai_compatible.py +414 -0
- rlmagent/model/preferences.py +56 -0
- rlmagent/model/py.typed +0 -0
- rlmagent/model/registered_oauth.py +195 -0
- rlmagent/model/scripted.py +55 -0
- rlmagent/model/settings.py +271 -0
- rlmagent/model/subscription.py +398 -0
- rlmagent/model/token_bounds.py +15 -0
- rlmagent/model/transport/__init__.py +1 -0
- rlmagent/model/transport/backoff.py +87 -0
- rlmagent/model/transport/client.py +87 -0
- rlmagent/model/transport/faults.py +65 -0
- rlmagent/model/transport/responses_socket.py +223 -0
- rlmagent/model/vertex.py +93 -0
- rlmagent/network.py +123 -0
- rlmagent/packages.py +246 -0
- rlmagent/planning.py +84 -0
- rlmagent/playbook/__init__.py +1 -0
- rlmagent/playbook/apply.py +106 -0
- rlmagent/playbook/digest.py +63 -0
- rlmagent/playbook/improver.py +272 -0
- rlmagent/playbook/plan.py +99 -0
- rlmagent/playbook/store.py +67 -0
- rlmagent/plugins.py +327 -0
- rlmagent/policy.py +105 -0
- rlmagent/prompt_refs.py +57 -0
- rlmagent/prompts.py +331 -0
- rlmagent/prune.py +60 -0
- rlmagent/py.typed +0 -0
- rlmagent/reasoning.py +135 -0
- rlmagent/refinement/__init__.py +1 -0
- rlmagent/refinement/controller.py +448 -0
- rlmagent/refinement/engine.py +220 -0
- rlmagent/refinement/evidence.py +131 -0
- rlmagent/refinement/scoped.py +90 -0
- rlmagent/refinement/store.py +193 -0
- rlmagent/refresh.py +202 -0
- rlmagent/routing.py +52 -0
- rlmagent/runtime.py +575 -0
- rlmagent/safety.py +267 -0
- rlmagent/session_html.py +57 -0
- rlmagent/session_import.py +52 -0
- rlmagent/session_share.py +55 -0
- rlmagent/sessions.py +249 -0
- rlmagent/shell_sandbox.py +88 -0
- rlmagent/skillset.py +320 -0
- rlmagent/steering.py +148 -0
- rlmagent/stops.py +62 -0
- rlmagent/subscriptions.py +219 -0
- rlmagent/tasks.py +98 -0
- rlmagent/toolhost.py +310 -0
- rlmagent/tools/__init__.py +56 -0
- rlmagent/tools/_shared.py +210 -0
- rlmagent/tools/files.py +462 -0
- rlmagent/tools/kernel.py +93 -0
- rlmagent/tools/patch_tool.py +68 -0
- rlmagent/tools/search.py +188 -0
- rlmagent/trust.py +383 -0
- rlmagent/tui/__init__.py +1 -0
- rlmagent/tui/adapter.py +506 -0
- rlmagent/tui/app.py +711 -0
- rlmagent/tui/approval_screen.py +57 -0
- rlmagent/tui/choice_screen.py +47 -0
- rlmagent/tui/completions.py +116 -0
- rlmagent/tui/components.py +25 -0
- rlmagent/tui/composer.py +40 -0
- rlmagent/tui/factory_view.py +86 -0
- rlmagent/tui/inspect.py +193 -0
- rlmagent/tui/messages.py +215 -0
- rlmagent/tui/model_screen.py +307 -0
- rlmagent/tui/prompt.py +98 -0
- rlmagent/tui/question_screen.py +52 -0
- rlmagent/tui/replay.py +141 -0
- rlmagent/tui/rlm_agent.tcss +405 -0
- rlmagent/tui/search_box.py +91 -0
- rlmagent/tui/sidebar.py +182 -0
- rlmagent/tui/status.py +49 -0
- rlmagent/tui/steps.py +283 -0
- rlmagent/tui/suggest.py +778 -0
- rlmagent/tui/transcript.py +172 -0
- rlmagent/tui/trust_dialog.py +58 -0
- rlmagent/tui/worker_attach.py +141 -0
- rlmagent/ui/__init__.py +1 -0
- rlmagent/ui/render.py +211 -0
- rlmagent/undo.py +109 -0
- rlmagent/utils/__init__.py +1 -0
- rlmagent/websearch.py +75 -0
- rlmagent/worker.py +1275 -0
- rlmagent/worker_service.py +203 -0
- rlmness_cli-0.2.0.dist-info/METADATA +882 -0
- rlmness_cli-0.2.0.dist-info/RECORD +203 -0
- rlmness_cli-0.2.0.dist-info/WHEEL +4 -0
- rlmness_cli-0.2.0.dist-info/entry_points.txt +2 -0
- 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.
|