feat: terse persona prompt, bash+ipython default tools, actionable compaction handoff - #142
Merged
Conversation
Replace the "general purpose agent / break down into sub-tasks" role framing
and the long IPYTHON_CONTROL_PROMPT ("long-lived notebook ... assign results
to named variables") with a terse coding-agent persona plus one factual
%%bash/project-env line.
Motivation: a 9-model x 8-arm interface/prompt ablation on SWE-rebench (32
tasks/arm, kimi-k3) found the verbose notebook framing - not the ipython
interface, not %%bash syntax - triggers heavy per-turn deliberation in some
models (kimi-k3: 327 reasoning tok/turn and 0.53 solve under the stock prompt
vs 209 tok/turn and 0.73 solve with this persona style, same tools, same
tasks; -20% output tokens). Frontier models were insensitive to the change.
…tion handoff - New native `bash` builtin tool (one command per call, fresh subshell, git guard, output clipping). Default tool set is now bash + ipython (RLM_BUILTIN_TOOLS overrides, e.g. "ipython" for a REPL-only agent). - `edit` builtin skill enabled by default (RLM_SKILLS="" disables). - System prompt names each capability in one line (persona style); the %%bash control line only renders for REPL-only configs, replaced by the project-env rule otherwise. - CHECKPOINT_COMPACTION_PROMPT now demands an actionable handoff: exact repro/test commands and pending edits as fenced code blocks + numbered next steps (validated to make post-compaction resumption concrete: 0 -> ~4 command blocks per handoff, solve-rate neutral-to-positive). Motivation: 32-task interface ablations (kimi-k3) show the bash+ipython+edit-skill config is the best balanced setup (reasoning cost 2nd-lowest of 9 arms tested, full REPL powers retained); tool-availability is otherwise solve-neutral across 9 models. Tests: 112 passed.
- EditTool joins the native tool set; default RLM_BUILTIN_TOOLS = bash, edit, ipython - bash skill added; default RLM_SKILLS = bash, edit — both actions callable from the REPL too (`await bash(...)`, `await edit(...)`) for mixing with Python in one cell or avoiding shell quoting - prompt names each route in one line; edit-skill line reframed as the in-REPL alternative (multiline/quote-heavy payloads) rather than the preferred path Dual-route ablation (32 tasks, kimi-k3): native tools win revealed preference 99:1, solve 0.74 / 199 reasoning tok/turn (best tier); the skill calls that do occur are rational (quoting escape, output separation, py-text-to-shell). Keeping skills registered costs nothing and covers that tail.
"The ipython kernel is an isolated venv without the project's packages — never import project modules there. Everything that executes project code (tests, repros, imports) goes through bash with the project's interpreter." kimi-k3 was importing project modules into the rlm kernel (~25 attempts / 32 rollouts, ~1 in 5 hitting ModuleNotFoundError) despite the old softer wording. Probes (8 tasks x 2 per arm): mechanism-explaining variants drop kernel project-imports 5 -> 0 with zero ImportErrors and no reasoning inflation (157-186 tok/turn vs 182 baseline). This wording is the config-agnostic variant (no skill names or activity examples).
create_subprocess_shell runs through /bin/sh (dash on debian images), so
bashisms — process substitution <(...), [[ ]], etc. — failed in the skill
while working in the bash tool (observed: `sh: Syntax error: "(" unexpected`).
Exec ["bash", "-c", command] explicitly, exactly like tools/bash.py.
Extract run_bash() in tools/bash.py (empty-command check, git-history guard, bash -c, timeout, exit-code + clip) and call it from both BashTool.execute and the bash skill — one execution path, byte-identical semantics. The skill also adopts the harness exec timeout (RLM_EXEC_TIMEOUT, fallback 300) as its default and now enforces the git guard it previously bypassed. Tests for both.
One knob selecting how shell/edit are exposed: - dual (default): native bash+edit tools AND bash+edit REPL skills - tools: native tools only (REPL stays, no bash/edit skills) - skills: REPL-only; bash+edit as skills, with the validated triple-quote shell guidance rendered automatically in the prompt RLM_BUILTIN_TOOLS / RLM_SKILLS remain as expert overrides on top. 128-task ablation (kimi-k3): the three modes converge on solve (0.69-0.72) and total reasoning (~7k); tools is cleanest (0.9% error turns), skills is fewest turns (29.8), dual within noise of both — hence dual as default. GLM-5.2/5.3 partials favor dual on robustness.
snimu
pushed a commit
that referenced
this pull request
Aug 26, 2026
…145) ## Summary Adds a built-in `bash` skill (enabled via `RLM_SKILLS`): `await bash(command=...)` runs a shell command from the REPL and returns combined stdout/stderr as a string (exit code appended when nonzero, output clipped at 30k chars). Why: lets the agent mix shell with Python in one cell — capture output as a value, parse it programmatically, or sidestep shell-quoting by building commands as triple-quoted Python strings. Implementation note: executes via `["bash", "-c", command]` explicitly rather than `create_subprocess_shell`, which resolves to `/bin/sh` (dash on debian images) and rejects bashisms — we hit `sh: Syntax error: "(" unexpected` on process substitution in ablation runs before pinning this down. A parity test (`cat <(echo ...)`) guards it. Tests: 4 new (output capture, bashism parity, exit-code reporting, stderr merging); suite green except 6 pre-existing `test_acp.py` failures that also fail on clean main in this environment. Extracted from #142 so it can ship independently. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Introduces arbitrary shell execution from the REPL; mitigated by shared git-history blocking and timeouts, but still expands the agent’s command surface. > > **Overview** > Adds a **`bash` built-in skill** (enable with `RLM_SKILLS`) so agents can **`await bash(...)`** from IPython and get shell output as a string instead of only using separate shell tools. > > The new `rlm.skills.bash` module runs **one command per call** via **`bash -c`** (not `/bin/sh`), merges stdout and stderr, appends **`[exit code N]`** on failure, honors **`RLM_EXEC_TIMEOUT`** (default 300s), and applies the same **`find_blocked_command` / git-history guard** as other shell paths. Registration in `_BUILTIN_SKILLS` wires it into the existing session stub / pre-import flow like `edit`. > > Tests cover echo output, bash-specific syntax (process substitution), nonzero exits, stderr, git guard behavior, timeouts, and that **`enable_builtin_skills(["bash"], ...)`** writes the expected re-export stub. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit bab8cf6. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
samsja
force-pushed
the
feat/terse-persona-prompt
branch
from
August 26, 2026 19:13
234948b to
9b607b0
Compare
snimu
marked this pull request as ready for review
August 26, 2026 20:10
snimu
previously approved these changes
Aug 26, 2026
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9b607b0. Configure here.
snimu
self-requested a review
August 26, 2026 20:16
…paths to cwd run_bash now threads allow_git through to find_blocked_command (previously the guard followed only RLM_ALLOW_GIT, diverging from the ipython tool which honors the execution policy); EditTool resolves relative paths against context.cwd like BashTool does, instead of the process working directory. Reported by cursor bugbot on #142.
Member
Author
|
Both fixed in the latest commit — run_bash threads allow_git from ToolContext into find_blocked_command (matching the ipython tool's policy-over-env behavior), and EditTool now resolves relative paths against context.cwd like BashTool. Tests added for both. |
The kernel environment is sanitized (#134), so RLM_EXEC_TIMEOUT and RLM_ALLOW_GIT never reached the kernel — the bash skill silently fell back to its 300s default timeout and always-blocked git policy, diverging from the harness execution policy that the bash/ipython tools honor. IPythonREPL now takes exec_timeout/allow_git from the engine and exports them in kernel startup, so skills see the same policy as tools. Kernel-policy test added. Same drift family as the earlier bugbot findings (parallel paths, one policy).
snimu
approved these changes
Aug 26, 2026
samsja
added a commit
that referenced
this pull request
Aug 28, 2026
## Summary Two default changes: | setting | before | after | disable/override | |---|---|---|---| | `summarize_at_tokens` | `None` (compaction off) | **256,000** | `RLM_SUMMARIZE_AT_TOKENS=""` or `"0"` | | `max_depth` | 0 (no sub-agents) | **1** | `RLM_MAX_DEPTH=0` | ## Why - **Compaction on by default**: without it, long trajectories die at the model context limit. 256k is a safety-net threshold — typical rollouts never touch it (SWE medians are ~10-30k), but the rare monster trajectory compacts and survives instead of failing. Compaction behavior (handoff quality, post-compaction recovery via the surviving kernel + conversation log) has been validated in the ablations backing #142; at-threshold rollouts solved at 0.75-0.88 with the improved handoff prompt. - **`max_depth=1` by default**: one level of `await rlm('sub-task')` is available out of the box, matching how the harness is deployed in practice. ## Notes - Empty/`0` env values for `RLM_SUMMARIZE_AT_TOKENS` now mean "disabled" (previously "" meant unset->off; unset now means the 256k default). - With `max_depth>=1` the engine owns a `SessionTreeSupervisor`; embedders using the sync `close()` inside an event loop must switch to `await engine.aclose()` (the idempotency test now pins `max_depth=0` for that reason — it tests retries, not recursion). - Tests: 130 passed; the 6 `test_acp.py` failures are pre-existing on clean main in this environment. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Behavior changes for all deployments that relied on implicit defaults (compaction off, no sub-agents); long runs may compact unexpectedly and recursive `rlm()` is enabled unless env overrides are set. > > **Overview** > **Default execution policy** now turns on context compaction at **256,000** tokens and allows **one level** of sub-agent recursion (`max_depth=1`), including matching env defaults for `RLM_MAX_DEPTH`. > > **`RLM_SUMMARIZE_AT_TOKENS` parsing** changes semantics: omitting the variable applies the 256k threshold; **`""` or `"0"`** explicitly disables compaction (replacing the old “unset/empty means off” behavior). `_summarize_at_tokens` encodes that logic and invalid positives still raise. > > **Tests** assert the new defaults, cover disable-via-empty/zero, switch async engine teardown from **`close()`** to **`await aclose()`** (needed when recursion/supervisor is on), and pin **`max_depth=0`** on the compaction/idempotency test so it stays focused on retries rather than sub-agents. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c37848a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
The rlm harness, rebuilt on evidence from a k3-focused ablation campaign (9 models, up to 128 tasks/arm, SWE-rebench-V2):
RLM_TOOLINGpreset —dual(default) |tools|skills— one knob for how shell/edit are exposedbash -c, git-history guard, harness timeout); output-clipping removedThe starting point: something was wrong
kimi-k3 on stock rlm vs a plain bash+edit agent, same tasks:
Ablations isolated the cause: the verbose prompt (not the ipython interface, not
%%bashsyntax). Same tools, persona prompt: 209-232 tok/turn, solve 0.62-0.75. Frontier models are insensitive either way; kimi-k3 and opus-5 are prompt-sensitive (~2x reasoning inflation under the stock prompt).Final ablation: the three
RLM_TOOLINGpresets (128 tasks, kimi-k3, same seeded set)toolsskills(with triple-quote guidance)dualConverged on solve and total reasoning (~8k tok).
toolsis cleanest,skillsfewest turns (REPL cells batch multiple actions),dualwithin noise of both.The skills preset needed two fixes, each isolated on the same 32 tasks:
bash -c)The bugfix bought the turns; the prompt line bought the errors. The
skillspreset auto-renders the validated line: "Run shell without = await bash(\'\'\'command here\'\'\')— always triple-quote the command so shell quotes and multi-line scripts never need escaping..."Cross-model check (GLM-5.3 @32):
tools0.61/1.3% err,skills0.63 but 2.4x the reasoning tokens and 3.7% err,dual0.59/0.6% err — skills-only is kimi-validated, not universal; hencedualas default (never the outlier on any model; both alternatives one env var away).Kernel-isolation line
kimi imported project modules into the rlm kernel (~25 attempts/32 rollouts, 1 in 5 hitting ModuleNotFoundError). The line "The ipython kernel is an isolated venv without the project's packages... everything that executes project code goes through bash" drops kernel project-imports 5 -> 0, ImportErrors -> 0, at lower reasoning (161 vs 182 tok/turn on the probe set) — informational phrasing, no prohibition cost.
Compaction
CHECKPOINT_COMPACTION_PROMPTnow demands runnable handoffs (exact repro/test commands + pending edits as fenced code blocks, numbered next steps): validated 0 -> ~4 command blocks per handoff, compacted-rollout solve 0.75-0.88 vs 0.53 under the stock prompt. Also checked: advance compaction notice in the system prompt is unnecessary (models stash state naturally; the at-compaction REPL note suffices; an explicit stash line doubles state-keeping but buys no solve).Notes
_selected()in the tool registry,RLM_SKILLSdefault now preset-aware inRuntimeConfig.from_env).test_acp.pyfailures are pre-existing on clean main in this environment. Ruff clean.Note
Medium Risk
Changes default tooling, prompts, and compaction handoffs that directly steer agent behavior; bash/edit run on the host cwd with file writes, though git guards and timeouts are centralized.
Overview
Default agent surface moves from IPython-only to native
bash,edit, andipythontools, withRLM_TOOLING(dual|tools|skills) andRLM_BUILTIN_TOOLSto override. WhenRLM_SKILLSis unset, skills now follow the preset viapreset_skills()instead of an empty list.rlm.tools.bashadds sharedrun_bash(guardedbash -c, cwd,allow_git) used byBashTool,EditTool, and thebashskill; the IPython kernel getsRLM_EXEC_TIMEOUT/RLM_ALLOW_GITat startup from engine policy.System prompt is shorter and tool-aware: coding-agent role lines per active tool, kernel-isolation guidance (
PROJECT_ENV_PROMPT), conditional bash-skill triple-quote hints, and trimmed IPython/edit copy. CompactionCHECKPOINT_COMPACTION_PROMPTnow requires fenced repro commands, pendingeditcalls, and numbered next steps.Reviewed by Cursor Bugbot for commit 41e2698. Bugbot is set up for automated code reviews on this repo. Configure here.