Skip to content

feat: add OpenClaw as an agentic workflow engine#16295

Closed
Mossaka wants to merge 1 commit into
mainfrom
feat/openclaw-engine
Closed

feat: add OpenClaw as an agentic workflow engine#16295
Mossaka wants to merge 1 commit into
mainfrom
feat/openclaw-engine

Conversation

@Mossaka

@Mossaka Mossaka commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds OpenClaw as a new experimental agentic workflow engine for gh-aw
  • OpenClaw is an agent platform using the Agent Communication Protocol (ACP) for tool orchestration
  • Follows the same patterns established by Claude, Codex, and Copilot engines
  • Marked as experimental — requires features: experimental-engines: true in strict mode

What is OpenClaw?

OpenClaw is an agent platform that supports ACP-based tool integration. It provides:

  • JSON-structured output (--json flag) for reliable log parsing
  • Timeout-based execution control (not turn-based)
  • MCP configuration via JSON format (same as Claude)
  • Integration with Anthropic and OpenAI model providers

Files Created

File Purpose
pkg/workflow/openclaw_engine.go Main engine: installation, execution, firewall, log parsing
pkg/workflow/openclaw_mcp.go MCP configuration rendering (JSON format via ACP bridge)
pkg/workflow/openclaw_engine_test.go 14 unit tests for engine behavior
pkg/workflow/compiler_openclaw_test.go 5 compilation integration tests
actions/setup/js/parse_openclaw_log.cjs JavaScript log parser for structured JSON output
actions/setup/js/parse_openclaw_log.test.cjs 42 JS tests for log parser
pkg/cli/workflows/test-openclaw-review.md Sample: PR review workflow
pkg/cli/workflows/test-openclaw-issue-triage.md Sample: Issue triage workflow
pkg/cli/workflows/test-openclaw-code-quality.md Sample: Code quality analysis
.github/workflows/smoke-openclaw.md Smoke test workflow

Files Modified

File Change
pkg/constants/constants.go Added OpenClawEngine, DefaultOpenClawVersion, env vars
pkg/workflow/domains.go Added OpenClawDefaultDomains and domain helper functions
pkg/workflow/firewall.go Added enableFirewallByDefaultForOpenClaw()
pkg/workflow/agentic_engine.go Registered OpenClaw engine in registry
pkg/workflow/compiler_orchestrator_engine.go Calls firewall auto-enable for OpenClaw
pkg/parser/schemas/main_workflow_schema.json Added openclaw to engine enum
Various test files Updated engine counts (5→6)

Usage

Simple frontmatter:

engine: openclaw

With custom agent and options:

engine:
  id: openclaw
  model: custom-agent-v2
  args: ["--verbose", "--timeout", "1800"]

Testing Done

  • 14 Go unit tests — engine properties, secrets, installation, execution, firewall, log parsing
  • 5 Go integration tests — full compilation with basic, engine object, firewall, safe-outputs, custom command
  • 42 JavaScript tests — log parser for JSON entries, tool calls, MCP events, error handling
  • 4 sample workflows compiled successfully with 0 errors
  • make fmt — passes
  • make build — passes
  • make test-unit — passes (all existing + new tests)
  • make test-js — OpenClaw tests pass (42/42); 3 pre-existing failures in unrelated safe_outputs_mcp_server_defaults tests

Test plan

  • Unit tests pass
  • JS tests pass
  • All sample workflows compile
  • Smoke test workflow compiles
  • Build succeeds
  • Formatting clean
  • Run smoke test on a real PR (after merge)

🤖 Generated with Claude Code

Add OpenClaw agent platform as a new experimental engine for gh-aw,
enabling workflows to use OpenClaw's ACP-based tool system.

New files:
- openclaw_engine.go: Main engine implementation with firewall support
- openclaw_mcp.go: MCP configuration rendering via JSON format
- parse_openclaw_log.cjs: JavaScript log parser for structured JSON output
- 14 unit tests, 5 compilation tests, 42 JS tests
- 3 sample workflows (PR review, issue triage, code quality)
- Smoke test workflow for CI validation

Modified files:
- constants.go: Version, engine name, env vars for OpenClaw
- domains.go: Default domains and domain helper functions
- firewall.go: Auto-enable firewall for OpenClaw engine
- agentic_engine.go: Engine registration
- compiler_orchestrator_engine.go: Firewall enablement call
- main_workflow_schema.json: Added openclaw to engine enum
- Updated test counts across affected test files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds OpenClaw as a new (experimental) agentic workflow engine alongside existing Claude/Codex/Copilot engines, including compiler + firewall defaults, MCP rendering, and log parsing for structured JSON output.

Changes:

  • Introduces the OpenClaw engine implementation (install, execution, firewall integration, MCP config rendering, log metrics parsing).
  • Adds a new JS log parser (parse_openclaw_log) with extensive tests and wires it into workflows.
  • Updates constants, schema, engine registry, domain allowlists, and various tests/sample workflows to include the new engine.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/workflow/openclaw_engine.go Implements the OpenClaw engine execution/install behavior, env wiring, firewall wrapping, and log metrics parsing.
pkg/workflow/openclaw_mcp.go Renders MCP server configuration for OpenClaw using the shared JSON renderer.
pkg/workflow/openclaw_engine_test.go Unit tests for OpenClaw engine properties, steps generation, constants, and log metrics parsing.
pkg/workflow/compiler_openclaw_test.go Integration tests validating compilation output for OpenClaw workflows across key scenarios.
actions/setup/js/parse_openclaw_log.cjs JS parser for OpenClaw --json logs, producing step summary markdown + structured logEntries.
actions/setup/js/parse_openclaw_log.test.cjs Vitest suite for OpenClaw log parser behavior across many log shapes and error cases.
pkg/constants/constants.go Adds OpenClaw engine constants, default version, model env vars, and engine option metadata.
pkg/constants/constants_test.go Updates expected agentic engine list to include OpenClaw.
pkg/workflow/domains.go Adds OpenClaw default domains + helper functions, and hooks it into sanitization domain computation.
pkg/workflow/firewall.go Adds OpenClaw-specific “enable firewall by default” hook mirroring existing engine behavior.
pkg/workflow/agentic_engine.go Registers the OpenClaw engine in the engine registry.
pkg/workflow/agentic_engine_test.go Updates engine registry tests to account for the additional built-in engine.
pkg/workflow/compiler_orchestrator_engine.go Enables firewall-by-default behavior for OpenClaw when network restrictions are present.
pkg/workflow/imported_steps_validation_test.go Makes strict-mode secret error assertion tolerant to OpenClaw/Claude wording ordering.
pkg/parser/schemas/main_workflow_schema.json Adds openclaw to the engine enum (string and object forms) with updated descriptions.
pkg/cli/workflows/test-openclaw-review.md Adds a sample OpenClaw workflow for PR review.
pkg/cli/workflows/test-openclaw-issue-triage.md Adds a sample OpenClaw workflow for issue triage.
pkg/cli/workflows/test-openclaw-code-quality.md Adds a sample OpenClaw workflow for code quality analysis.
pkg/cli/completions_test.go Updates engine name completion test expectations to include OpenClaw.
.github/workflows/smoke-openclaw.md Adds an OpenClaw smoke-test workflow definition.
.github/workflows/smoke-openclaw.lock.yml Generated lockfile output for the OpenClaw smoke-test workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +358 to +363
for _, line := range lines {
// Count tool calls from JSON output
if strings.Contains(line, "\"type\":\"tool_call\"") || strings.Contains(line, "\"type\": \"tool_call\"") {
// Try to extract tool name
toolName := "unknown"
if idx := strings.Index(line, "\"name\":\""); idx != -1 {

Copilot AI Feb 17, 2026

Copy link

Choose a reason for hiding this comment

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

ParseLogMetrics only detects tool calls by searching for "type":"tool_call" (and a single spaced variant). The JS parser also treats tool_use as a tool invocation, so OpenClaw runs that emit tool_use (or use tool/function fields for names) won’t be counted in Go metrics.

Consider handling both tool_call and tool_use (and extracting the tool name from name/tool/function), and using FinalizeToolCallsAndSequence/FinalizeToolMetrics to produce stable, sorted output.

Copilot uses AI. Check for mistakes.
Comment on lines +366 to +371
// Test with tool calls in JSON
logContent := `{"type":"tool_call","name":"test_tool"}
{"type":"message","content":"thinking..."}
{"type":"tool_call","name":"another_tool"}`
metrics = engine.ParseLogMetrics(logContent, false)
if len(metrics.ToolCalls) != 2 {

Copilot AI Feb 17, 2026

Copy link

Choose a reason for hiding this comment

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

TestOpenClawEngine_ParseLogMetrics exercises only the tool_call JSON shape. Since the OpenClaw log parser (JS) also supports tool_use, adding a test case for tool_use lines would ensure Go metrics stay in sync with the supported log formats.

Copilot uses AI. Check for mistakes.
Comment on lines +107 to +125
case "tool_result": {
const result = entry.result || entry.output || entry.content || "";
const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
const isError = entry.is_error || entry.error || false;
const toolUseId = `tool_result_${logEntries.length}`;

logEntries.push({
type: "user",
message: {
content: [
{
type: "tool_result",
tool_use_id: toolUseId,
content: resultStr,
is_error: isError,
},
],
},
});

Copilot AI Feb 17, 2026

Copy link

Choose a reason for hiding this comment

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

tool_result entries are emitted with a fresh tool_use_id (tool_result_${logEntries.length}), which will never match the id generated for the preceding tool_use entry. This breaks log_parser_shared.cjs pairing logic (it joins tool results to tool calls by matching tool_use_id to the tool_use id), so tool results won’t render under their corresponding tool call.

Track the most recent (or a queue/stack of) generated tool_use IDs and reuse that ID for the subsequent tool_result entry (or use an ID from the OpenClaw JSON if one exists). Also coerce is_error to a boolean (e.g., Boolean(entry.is_error || entry.error)), since entry.error can be a string.

Copilot uses AI. Check for mistakes.

expect(result.logEntries.length).toBe(2);
expect(result.logEntries[1].type).toBe("user");
expect(result.logEntries[1].message.content[0].type).toBe("tool_result");

Copilot AI Feb 17, 2026

Copy link

Choose a reason for hiding this comment

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

The tests cover parsing tool_result, but don’t assert that the generated tool_result.tool_use_id matches the preceding tool_use.id. Given the shared renderer pairs tool results to tool calls by ID, adding an assertion for correct pairing would prevent regressions in the log format mapping.

Suggested change
expect(result.logEntries[1].message.content[0].type).toBe("tool_result");
expect(result.logEntries[1].message.content[0].type).toBe("tool_result");
const toolCall = result.logEntries[0].message.content[0];
const toolResult = result.logEntries[1].message.content[0];
expect(toolResult.tool_use_id).toBe(toolCall.id);

Copilot uses AI. Check for mistakes.
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.

3 participants