Skip to content

Harness owns env_vars; rlm harness keeps only sandbox-plumbing defaults#1161

Draft
rasdani wants to merge 1 commit intomainfrom
feat/rlm-default-env-vars
Draft

Harness owns env_vars; rlm harness keeps only sandbox-plumbing defaults#1161
rasdani wants to merge 1 commit intomainfrom
feat/rlm-default-env-vars

Conversation

@rasdani
Copy link
Copy Markdown
Contributor

@rasdani rasdani commented Apr 16, 2026

Summary

Restructures how harness-level env vars reach the sandbox so there's one source of truth per concern:

  1. `Harness` dataclass gains `env_vars: dict[str, str]` — harnesses declare their own defaults instead of downstream envs re-declaring them.

  2. `ComposableEnv.build_env_vars` merges `harness.env_vars` with lowest precedence (via `setdefault`), so values passed via `CLIAgentEnv(environment_vars=...)` or by the task still win.

  3. `rlm_harness(env_vars=...)` accepts overrides and bakes the resulting dict into the returned `Harness`.

  4. `DEFAULT_RLM_ENV_VARS` shrinks to only what the harness genuinely needs to set:

    • `OPENAI_API_KEY=intercepted` — sandbox plumbing (routes through interception tunnel).
    • `RLM_MAX_TURNS=100` — rlm's internal default is 30 (dev placeholder); 100 is the SWE-appropriate default we were already shipping.
    • Dropped `RLM_SYSTEM_PROMPT_VERBOSITY=heavy` (rlm never read it — dead).
    • Dropped `RLM_MAX_TURNS_IN_CONTEXT=-1` (matches rlm's own default — redundant).

    Other rlm-side knobs (`RLM_EXEC_TIMEOUT`, `RLM_ENABLED_TOOLS`, ...) are now left to rlm's own defaults. Callers override via `rlm_harness(env_vars={...})`.

Motivation

Before this PR, `rlm-swe` re-declared its own `DEFAULT_RLM_ENV_VARS` and passed the merged dict via `environment_vars=` — a second plumbing path parallel to the harness. With the `Harness.env_vars` field, there's one source per concern: rlm's defaults inside rlm, sandbox-plumbing inside the harness, user overrides in a single pass-through.

See matching research-environments#282 which becomes a thin pass-through once this lands.

Test plan

  • `ruff check` / `ruff format --check` — clean
  • `pytest tests/test_rlm_composable_env.py` — 6/6 pass (existing tests still green with `env_vars` field added)
  • `pytest tests/test_composable_env.py` — 30/30 pass (harness field additive)

Adds an ``env_vars: dict[str, str]`` field to ``Harness``; ComposableEnv
merges ``harness.env_vars`` into the sandbox env with the lowest
precedence, so values passed via ``CLIAgentEnv(environment_vars=...)``
or by the task still win. The rlm harness now owns its sandbox defaults
(``OPENAI_API_KEY=intercepted``, ``RLM_MAX_TURNS``) via this field and
exposes an ``env_vars`` override kwarg to ``rlm_harness(...)``. The
former ``RLM_SYSTEM_PROMPT_VERBOSITY=heavy`` default is dropped (rlm
never read it) as is the redundant ``RLM_MAX_TURNS_IN_CONTEXT=-1``
(matches rlm's own default). Remaining rlm-side knobs (exec timeout,
enabled tools, …) stay with rlm's own defaults and are set only when
the caller explicitly overrides them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rasdani rasdani force-pushed the feat/rlm-default-env-vars branch from 27cf9d3 to 8416ab8 Compare April 16, 2026 23:36
@rasdani rasdani changed the title rlm harness: export DEFAULT_RLM_ENV_VARS Harness owns env_vars; rlm harness keeps only sandbox-plumbing defaults Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant