Skip to main content

M10 - OpenClaw Concrete Executor, Agent-Node Pilot, and Safety Gates

Status: delivered.

M9 proved the orchestration-runtime seam and piloted one read-only node (track_progress) through a fake executor. M10 (issues #82- #88) replaces the fake executor with a real, gateway-backed one; extends the pilot to one state-only agent node; adds a centralized, code-owned capability policy so config alone can never widen what OpenClaw may execute; and adds the machine-checkable flip-readiness gate operators run before switching a real environment onto the pilot.

Result​

  • Concrete executor (M10-1..M10-4, issues #82-#85): OpenClawGatewayNodeExecutor and OpenClawExecutorGatewayClient (bloom/workflow/openclaw_executor.py) implement the pilot's POST /tools/invoke contract against a real OpenClaw Gateway. create_app wires the concrete executor whenever BLOOM_OPENCLAW_ORCHESTRATION_EXECUTOR_BASE_URL is configured, falling back to UnavailableOpenClawNodeExecutor otherwise; Settings fails fast if fail_closed is selected without that config. An integration harness (bloom/workflow/openclaw_track_progress_harness.py) proves track_progress end to end through the real code path - request shape, idempotency/cached-success reuse, validated writes, and Bloom's own reducer application - offline by default, with an opt-in live-gateway check.
  • Second pilot node (M10-5, issue #86): prd_authoring, a state-only agent node that writes only prd and never messages the user directly, routed through a separate, empty-by-default BLOOM_OPENCLAW_ORCHESTRATION_PILOT_AGENT_NODES allowlist. Explicit by node id, never inferred from node.type == "agent" alone.
  • Capability policy and safety gates (M10-6, issue #87): OpenClawCapabilityPolicy (bloom/workflow/openclaw_policy.py) is a third, code-owned gate above the operator-configured allowlists and below the executor's own tool/agent maps. It rejects any node that is not a tool/agent node, is side-effecting (Telegram sends, GitHub mutations, deploy/CI triggers, PR review publication, merge decisions), falls outside its own hard-coded node set, or declares writes outside what that node id is allowed to write. Policy rejection follows the same fallback/fail-closed semantics as an executor failure and is always logged (openclaw_policy.rejected), never silent. /health's orchestration.policy field exposes a secret-safe summary.
  • Flip-readiness command and runbook (M10-7, issue #88, this milestone's closing issue): bloom.workflow.openclaw_readiness (run via uv run python -m bloom.workflow.openclaw_readiness) is a machine-checkable gate that verifies Settings construction, the configured allowlists against the policy's hard-coded node set, /health, concrete-executor availability, correlation-store health, capability-policy wiring, and an offline run of the track_progress execution harness - entirely in-process, no live OpenClaw gateway required by default - plus an optional, explicitly-marked local-gateway-only live harness check. See docs/deployment.md for the full rollout runbook and docs/design/openclaw-orchestration-runtime.md for the design reference.

Exact M10 Routable Node Set​

At the end of M10, exactly these two nodes may ever route through OpenClaw, and only when also present in the operator's configured allowlist:

  • track_progress (tool): read-only GitHub status refresh, writes only progress.
  • prd_authoring (agent): state-only PRD draft, writes only prd.

Every other node in workflows/bloom-sdlc.workflow.json - human, event_wait, map, router, passthrough, and every side-effecting tool node (GitHub mutations, Telegram sends, deploy/CI triggers) - remains built-in-only, enforced by the capability policy regardless of any future config change. Widening this set requires a deliberate, separately-reviewed change to openclaw_policy.py and its tests, never a runtime config value alone.

Retained In Bloom​

Unchanged from M9 - Bloom still owns product state and persisted RunState, workflow graph traversal and reducers, GitHub coordination semantics, account/session state, Telegram and GitHub webhook routing, durable job enqueue and event dedupe, GitHub and Telegram side effects, Product Owner review and merge gates, and milestone closure.

Out Of Scope​

M10 does not:

  • remove the built-in runtime,
  • route any node beyond track_progress/prd_authoring through OpenClaw,
  • enable any side-effecting node through OpenClaw,
  • move webhook routing, account/product state storage, or business invariants into OpenClaw,
  • automatically flip any real environment's BLOOM_ORCHESTRATION_RUNTIME - the flip-readiness command is a check operators run manually before that decision, not an automated gate.

Not started. The recommended next candidate - noted in Pilot Path Recommendation - is one additional read-only or advisory node (e.g. a status/monitoring answer path, or a pre-publication specialist-review draft), added through the same double-allowlist-plus-capability-policy pattern this milestone established, only after the M10 pilot has run in production behind the flip-readiness check for a full soak period.