Skip to main content

Workflow Spec To OpenClaw Execution Mapping

Issue: #63

This document maps Bloom's declarative workflow concepts to OpenClaw execution concepts for the M9 orchestration-runtime pilot and later migration paths. It depends on the boundary decision in OpenClaw Orchestration Runtime Design: Bloom keeps the product control plane, while OpenClaw may execute selected work behind a runtime adapter.

Mapping Principles

  • The workflow spec remains the source of truth for nodes, edges, triggers, state fields, and reducers.
  • Bloom persists RunState; OpenClaw does not become the workflow state store.
  • Bloom evaluates business invariants and GitHub coordination rules.
  • OpenClaw executions are correlated to Bloom thread, job, event, and node ids.
  • Unsupported behavior falls back to the built-in runtime.
  • Human and agent ownership rules remain GitHub/Bloom semantics, not OpenClaw session semantics.
  • One implementation issue still maps to one branch and one PR.

Node Mapping

Bloom node typeCurrent behaviorOpenClaw mappingM9 stance
agentOrchestrator dispatches to a typed Bloom agent, which calls the configured LLMProvider and returns structured writes.OpenClaw can run an agent turn with the node prompt, resolved input, tool allowlist, and expected structured output schema. Bloom validates and applies the returned writes.Supported for pilot after adapter and correlation are in place.
toolOrchestrator executes a concrete integration action such as GitHub, Telegram, deployment, or CI.OpenClaw can execute only explicitly approved tool actions. Bloom still owns action policy, credentials, and side-effect idempotency.Read-only tools first. GitHub-mutating tools stay built-in until proven safe.
humanBloom sends a prompt through Telegram and suspends until a later inbound message resumes the run.OpenClaw may prepare prompt text, but Bloom should own delivery, suspension, resume binding, and account/session routing.Keep built-in for M9.
event_waitBloom parks the run until a webhook, scheduled tick, or message job resumes it.OpenClaw should not own third-party webhook waits in M9. It may receive a resumed execution after Bloom's job runner claims the event.Keep built-in for M9.
routerBuilt-in engine applies passthrough writes and evaluates guarded edges.Bloom should evaluate edge guards because it owns state reducers and business invariants.Keep built-in unless later proven pure and portable.
passthroughOrchestrator applies deterministic node-specific state updates.Keep in Bloom unless the node is proven pure and side-effect-free.Built-in by default.
mapBuilt-in engine iterates items, runs the body node, and writes one collected result batch.OpenClaw can run mapped body executions as child sessions/tasks, but Bloom must collect results and apply the reducer once.Supported later, but not first pilot for side-effecting bodies.
terminalBuilt-in engine marks the run done.Bloom marks completion in RunState.Keep built-in.
subworkflowNot used by the MVP workflow and not implemented in the built-in engine.No OpenClaw mapping until Bloom defines subworkflow semantics.Unsupported, fallback or reject.

Current Bloom SDLC Node Classification

Safe initial candidates for future expansion:

  • requirement_discovery: agent, non-mutating outside Bloom state.
  • milestone_planning: agent, writes milestone plan only.
  • ticket_generation: agent, writes ticket plan only.
  • review_one_pull_request: agent, advisory until Bloom publishes review output through GitHub.
  • gather_feedback: post-MVP agent, state-only.

Current M9/M10 pilot:

  • track_progress: GitHub read tool; currently allowlisted by default when BLOOM_ORCHESTRATION_RUNTIME=openclaw_pilot is enabled.
  • prd_authoring: agent, writes only the prd state field (M10-5, issue #86). Chosen over requirement_discovery as the first piloted agent node because it is strictly state-only in a stronger sense: its only write target is prd (one field, merge reducer), it never appends to conversation or sets inbound_message, and its output never reaches the user directly - the downstream request_prd_approval human node (built-in, never routed through OpenClaw) is the only thing that turns prd.summary_for_user into an outbound message, and only after Bloom's own approval-gate semantics apply. requirement_discovery writes conversation (which feeds the next turn's LLM context) and interacts more directly with the human-approval loop, so it stays built-in for now and remains a candidate for a later pilot expansion. prd_authoring is opt-in and disabled by default - BLOOM_OPENCLAW_ORCHESTRATION_PILOT_AGENT_NODES must name it explicitly, and it must also appear in OpenClawGatewayNodeExecutor's own DEFAULT_NODE_AGENT_MAP allowlist (bloom/workflow/openclaw_executor.py) before it ever executes through OpenClaw - the same double-allowlist pattern track_progress uses for tool nodes.

Keep built-in at first:

  • ask_clarification: human, requires Telegram delivery and resume binding.
  • request_prd_approval: human, approval gate owned by Bloom.
  • freeze_prd: passthrough, business invariant.
  • sync_milestones: GitHub-mutating tool.
  • sync_tickets: map over a GitHub-mutating body.
  • create_issue_for_ticket: GitHub-mutating tool.
  • notify_planning_ready: Telegram tool.
  • await_project_event: event_wait, webhook-owned.
  • review_pull_requests: map; later candidate after child correlation works.
  • notify_review: Telegram/GitHub notification side effects.
  • deploy: post-MVP side-effecting tool.
  • run_tests: post-MVP CI-triggering tool.

State And Reducer Mapping

Bloom's reducers are part of the workflow contract. OpenClaw should return node results, not mutate Bloom state directly.

ReducerBloom meaningOpenClaw handling
replaceNew value replaces the old field.OpenClaw returns a candidate value. Bloom applies replace.
appendNew value is appended to an array.OpenClaw returns the item or batch. Bloom applies append.
mergeObject values are shallow-merged into existing object state.OpenClaw returns an object patch. Bloom applies merge.
addNumeric additive update.OpenClaw returns a numeric delta. Bloom applies add.
unionArray-like set union without duplicates.OpenClaw returns values. Bloom applies union.

For map, Bloom should preserve the current batch semantics: child results are collected and written once to the target field so reducers see one fan-out batch, not a stream of individually applied writes.

Edge And Branch Mapping

Bloom should evaluate workflow edges in M9.

Reasons:

  • Guard expressions read Bloom state.
  • Predicate escapes such as post_mvp_enabled are host-owned policy.
  • Edge selection must be deterministic across built-in and OpenClaw runtimes.
  • Keeping edges in Bloom makes rollback straightforward.

OpenClaw can receive only the selected node execution request. It does not need to know the full graph for the first runtime adapter.

Trigger Mapping

Bloom triggerCurrent sourceOpenClaw role
messageTelegram webhook job handled by Bloom.None before job claim; possible node execution after Bloom resumes.
webhookGitHub webhook job handled by Bloom.None before job claim; possible read-only execution after Bloom resumes.
scheduleBloom scheduler enqueues project_tick.None before job claim; possible node execution after Bloom resumes.
manualFuture host-triggered work.Possible adapter input after Bloom authorizes it.

Webhook acknowledgment, event routing, account gating, and job enqueue stay in Bloom.

Tool Mapping

OpenClaw tool execution must be allowlisted by integration and action.

Initial tool posture:

  • Allow read-only advisory tools first, such as reading project status.
  • Keep Telegram sends, GitHub mutations, deployment triggers, CI triggers, PR publication, and merge-related operations in Bloom.
  • Require idempotency keys for any future side-effecting tool routed through OpenClaw.
  • Never pass raw secrets in node config or workflow spec metadata.

M10-6 Capability Policy

Issue #87 adds a centralized capability policy (bloom/workflow/openclaw_policy.py) that enforces the classification in this document as code, not just documentation: node type, side-effect posture (integration/action), the exact M10 node set, the operator-configured allowlist, and declared output/writes are all checked before a node ever reaches OpenClaw. See Capability Policy And Safety Gates for the full check order and Exact M10 Routable Node Set for the definitive allowed-vs-built-in-only node list at the end of M10.

Unsupported Or Built-In-Only Behavior

The OpenClaw runtime adapter should reject or fall back to the built-in runtime for:

  • human and event_wait nodes.
  • subworkflow nodes.
  • GitHub-mutating tools until side-effect idempotency is implemented.
  • Telegram notification tools until delivery fencing is implemented.
  • Host predicates not expressible as pure workflow guards.
  • Any node with unresolved refs or unknown output assignment targets.
  • Any node that requires credentials not explicitly provisioned to the runtime.

Fallback should be explicit in logs and tests, not silent.

Runtime Request Shape

An OpenClaw execution request should contain only the bounded node context:

{
"threadId": "123:1",
"jobId": "987",
"eventKey": "gh:pr:opened:12:abc123",
"workflowId": "bloom-sdlc",
"workflowVersion": "0.8",
"nodeId": "requirement_discovery",
"nodeType": "agent",
"input": {},
"outputSchema": {},
"toolAllowlist": [],
"sessionKey": "bloom:project:123:1:node:requirement_discovery"
}

The request should not include full project state unless the node reads it. It should not include credentials directly.

Session Key Mapping

OpenClaw session keys should be stable, namespaced, and derived from Bloom data:

bloom:project:<thread_id>:node:<node_id>

For fan-out child executions:

bloom:project:<thread_id>:node:<map_node_id>:item:<stable_item_key>

The stable item key should come from a PR number, ticket id, issue number, or a hash of the item payload when no natural key exists.

Test Expectations

Issue #63 was documentation-only, so no unit tests were required there. The M9 implementation issues added tests for the runtime seam, fallback decisions, correlation keys, persistence, health surface, and the track_progress pilot. Later expansion issues should continue adding tests for:

  • node-to-runtime capability classification,
  • reducer preservation,
  • fallback decisions,
  • correlation key generation,
  • map child session key generation,
  • unsupported node rejection.