Skip to content

[3/3] Add OpenClaw adapter (RFC 005)#391

Merged
Darktex merged 3 commits intofeature/issue-385-harness-environmentfrom
feature/issue-385-openclaw-adapter
Feb 19, 2026
Merged

[3/3] Add OpenClaw adapter (RFC 005)#391
Darktex merged 3 commits intofeature/issue-385-harness-environmentfrom
feature/issue-385-openclaw-adapter

Conversation

@Darktex
Copy link
Contributor

@Darktex Darktex commented Feb 17, 2026

Summary

Stacked on #390 (HarnessEnvironment).

Adds the first concrete HarnessAdapter implementation for OpenClaw, validating the adapter abstraction works with a real harness.

OpenClawAdapter

  • Process lifecycle: Starts OpenClaw via asyncio.create_subprocess_exec, terminates on stop
  • MCP tool injection: Writes mcpServers.openenv entries to .openclaw/openclaw.json, merges with existing config
  • Communication: JSON-line protocol over stdin/stdout (sends {"message": "..."}, reads JSON response)
  • Event extraction: Parses tool_calls from JSON responses into HarnessEvent objects
  • Streaming: send_message_streaming() yields events from the turn
  • Error handling: Session timeout detection, plain-text response fallback

Stack

#387  RFC 005: Agentic Harness Integration
  └── #389  Foundation types (HarnessConfig, HarnessAdapter, HarnessEvent, etc.)
       └── #390  HarnessEnvironment (multi-turn, trajectory)
            └── This PR: OpenClaw adapter

Test plan

  • 18 unit tests with mocked subprocess (no OpenClaw binary required)
  • Config file injection tested with real filesystem (tmp_path)
  • 87 total harness tests pass
  • Lint clean

Part of #385

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Meta Open Source bot. label Feb 17, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Greptile Summary

Adds the first concrete HarnessAdapter implementation for OpenClaw, validating RFC 005's adapter abstraction with a real harness.

Key Changes:

  • Process lifecycle: Manages OpenClaw subprocess via asyncio with stdin/stdout pipes
  • MCP tool injection: Writes mcpServers.openenv entries to .openclaw/openclaw.json, merges with existing config
  • Communication: JSON-line protocol over stdin/stdout, parses responses with tool call extraction
  • Event extraction: Maps OpenClaw responses to HarnessEvent objects for trajectory tracking
  • Error handling: Implements session timeout detection and plain-text response fallback

Testing:

  • 18 unit tests with mocked subprocess (no OpenClaw binary required)
  • Config file injection tested with real filesystem operations
  • Lifecycle, streaming, and integration with HarnessEnvironment covered

Alignment:

  • Respects dual API boundary (no agent access to reset/step)
  • Follows MCP as universal standard for tool injection
  • Maintains container isolation via working directory constraints
  • Implements RFC 005 design as specified

Confidence Score: 4/5

  • Safe to merge with one minor style improvement recommended
  • Implementation correctly follows RFC 005 design, includes comprehensive test coverage (18 tests), properly handles edge cases (timeouts, plain text responses, config merging). Only minor style issue with nested import. All system invariants respected (dual API boundary, agent isolation, MCP standard).
  • No files require special attention

Important Files Changed

Filename Overview
src/openenv/core/harnesses/adapters/init.py Exports OpenClawAdapter - clean, standard module init
src/openenv/core/harnesses/adapters/openclaw.py OpenClaw adapter with subprocess management, MCP tool injection, JSON-line communication - minor style issue with nested import
tests/core/test_harnesses/test_openclaw_adapter.py Comprehensive test suite (18 tests) covering lifecycle, tool injection, messaging, streaming with mocked subprocess

Sequence Diagram

sequenceDiagram
    participant HE as HarnessEnvironment
    participant OCA as OpenClawAdapter
    participant OC as OpenClaw Process
    participant LLM as LLM Endpoint

    Note over HE,LLM: Initialization Phase
    HE->>OCA: inject_tools(tools)
    OCA->>OCA: Write .openclaw/openclaw.json
    Note right of OCA: Merge with existing config<br/>Add mcpServers.openenv entry
    
    HE->>OCA: start(working_directory)
    OCA->>OC: create_subprocess_exec()
    Note right of OC: Process started with<br/>stdin/stdout/stderr pipes

    Note over HE,LLM: Conversational Turn (step)
    HE->>OCA: send_message("Fix the bug")
    OCA->>OC: stdin.write({"message": "..."})
    Note right of OCA: JSON-line protocol
    
    OC->>LLM: LLM inference request
    LLM-->>OC: Response with tool_calls
    
    OC->>OC: Execute tool calls<br/>(read_file, write_file, etc)
    
    OC-->>OCA: stdout: {"response": "Done", "tool_calls": [...]}
    Note right of OCA: Parse JSON response<br/>Extract tool events
    
    OCA-->>HE: HarnessResponse(events, done)
    Note left of HE: Returns observation<br/>with trajectory events

    Note over HE,LLM: Cleanup Phase
    HE->>OCA: stop()
    OCA->>OC: terminate()
    alt Graceful shutdown
        OC-->>OCA: Process exits (returncode 0)
    else Timeout
        OCA->>OC: kill()
    end
Loading

Last reviewed commit: 00f509b

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@Darktex Darktex force-pushed the feature/issue-385-harness-environment branch from bf89368 to 37a0876 Compare February 17, 2026 15:57
@Darktex Darktex force-pushed the feature/issue-385-openclaw-adapter branch from 00f509b to d3e405c Compare February 17, 2026 15:58
@Darktex Darktex force-pushed the feature/issue-385-harness-environment branch from 37a0876 to d8b1362 Compare February 17, 2026 21:50
@Darktex Darktex force-pushed the feature/issue-385-openclaw-adapter branch from 45200fe to 878a930 Compare February 17, 2026 21:50
@Darktex Darktex changed the title Add OpenClaw adapter (RFC 005) [4/4] Add OpenClaw adapter (RFC 005) Feb 17, 2026
Concrete HarnessAdapter for the OpenClaw agentic platform:

- Process lifecycle: start/stop via asyncio subprocess
- MCP tool injection: writes mcpServers config to openclaw.json,
  merges with existing config entries
- Communication: JSON-line protocol over stdin/stdout
- Event extraction: parses tool_calls from responses into HarnessEvents
- Streaming: yields events from turn response
- Error handling: timeout detection, plain-text fallback

18 tests covering imports, config injection, process lifecycle,
message sending with JSON/plain-text responses, tool call extraction,
streaming, and HarnessEnvironment integration.

Part of #385
- Fix critical bug: env vars now merge with parent env (os.environ)
  instead of replacing it, preserving PATH, PYTHONPATH, etc.
- When no env_vars or api_key configured, pass None to inherit parent
- Add test for parent env inheritance with custom env vars
- Add test for None env when no overrides configured
- Add test for kill path when terminate times out
- Add test for send_message timeout handling
- Add test for corrupted config file handling
- Add subprocess pipe parameter assertions to start test
@Darktex Darktex changed the title [4/4] Add OpenClaw adapter (RFC 005) [3/3] Add OpenClaw adapter (RFC 005) Feb 18, 2026
@Darktex Darktex force-pushed the feature/issue-385-harness-environment branch from d8b1362 to f9f77c6 Compare February 18, 2026 07:06
@Darktex Darktex force-pushed the feature/issue-385-openclaw-adapter branch from 878a930 to fa3c139 Compare February 18, 2026 07:06
@Darktex Darktex merged commit 41a3062 into feature/issue-385-harness-environment Feb 19, 2026
1 check passed
Darktex added a commit that referenced this pull request Feb 19, 2026
* Add HarnessEnvironment with multi-turn support (RFC 005)

Implements HarnessEnvironment, which wraps an external agentic harness
with OpenEnv's Gym-style API:

- reset() stops any running harness, injects MCP tools, starts fresh
- step(HarnessAction) sends one conversational turn to the harness
- Harness maintains conversation context across step() calls
- done signal propagated from harness to observation
- Trajectory accumulated across turns, accessible via .trajectory
- close() cleans up harness process

26 tests covering reset, multi-turn step, trajectory accumulation,
state management, close behavior, and MCP tool injection.

Part of #385

* Address review feedback: fix async context manager and logging

- Fix broken async context manager in _get_mcp_tool_definitions:
  use single async function with 'async with' instead of separate
  run_async_safely calls for __aenter__/__aexit__
- Add warning log on MCP tool extraction failure instead of
  silently swallowing exceptions

* [3/3] Add OpenClaw adapter (RFC 005) (#391)

* Add OpenClaw adapter implementation (RFC 005)

Concrete HarnessAdapter for the OpenClaw agentic platform:

- Process lifecycle: start/stop via asyncio subprocess
- MCP tool injection: writes mcpServers config to openclaw.json,
  merges with existing config entries
- Communication: JSON-line protocol over stdin/stdout
- Event extraction: parses tool_calls from responses into HarnessEvents
- Streaming: yields events from turn response
- Error handling: timeout detection, plain-text fallback

18 tests covering imports, config injection, process lifecycle,
message sending with JSON/plain-text responses, tool call extraction,
streaming, and HarnessEnvironment integration.

Part of #385

* Address review feedback: move import os to top of file

* Fix env variable bug and add missing test coverage

- Fix critical bug: env vars now merge with parent env (os.environ)
  instead of replacing it, preserving PATH, PYTHONPATH, etc.
- When no env_vars or api_key configured, pass None to inherit parent
- Add test for parent env inheritance with custom env vars
- Add test for None env when no overrides configured
- Add test for kill path when terminate times out
- Add test for send_message timeout handling
- Add test for corrupted config file handling
- Add subprocess pipe parameter assertions to start test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant