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 type | Current behavior | OpenClaw mapping | M9 stance |
|---|---|---|---|
agent | Orchestrator 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. |
tool | Orchestrator 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. |
human | Bloom 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_wait | Bloom 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. |
router | Built-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. |
passthrough | Orchestrator applies deterministic node-specific state updates. | Keep in Bloom unless the node is proven pure and side-effect-free. | Built-in by default. |
map | Built-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. |
terminal | Built-in engine marks the run done. | Bloom marks completion in RunState. | Keep built-in. |
subworkflow | Not 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-MVPagent, state-only.
Current M9/M10 pilot:
track_progress: GitHub readtool; currently allowlisted by default whenBLOOM_ORCHESTRATION_RUNTIME=openclaw_pilotis enabled.prd_authoring:agent, writes only theprdstate field (M10-5, issue #86). Chosen overrequirement_discoveryas the first piloted agent node because it is strictly state-only in a stronger sense: its only write target isprd(one field,mergereducer), it never appends toconversationor setsinbound_message, and its output never reaches the user directly - the downstreamrequest_prd_approvalhuman node (built-in, never routed through OpenClaw) is the only thing that turnsprd.summary_for_userinto an outbound message, and only after Bloom's own approval-gate semantics apply.requirement_discoverywritesconversation(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_authoringis opt-in and disabled by default -BLOOM_OPENCLAW_ORCHESTRATION_PILOT_AGENT_NODESmust name it explicitly, and it must also appear inOpenClawGatewayNodeExecutor's ownDEFAULT_NODE_AGENT_MAPallowlist (bloom/workflow/openclaw_executor.py) before it ever executes through OpenClaw - the same double-allowlist patterntrack_progressuses fortoolnodes.
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-mutatingtool.sync_tickets:mapover a GitHub-mutating body.create_issue_for_ticket: GitHub-mutatingtool.notify_planning_ready: Telegramtool.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-effectingtool.run_tests: post-MVP CI-triggeringtool.
State And Reducer Mapping
Bloom's reducers are part of the workflow contract. OpenClaw should return node results, not mutate Bloom state directly.
| Reducer | Bloom meaning | OpenClaw handling |
|---|---|---|
replace | New value replaces the old field. | OpenClaw returns a candidate value. Bloom applies replace. |
append | New value is appended to an array. | OpenClaw returns the item or batch. Bloom applies append. |
merge | Object values are shallow-merged into existing object state. | OpenClaw returns an object patch. Bloom applies merge. |
add | Numeric additive update. | OpenClaw returns a numeric delta. Bloom applies add. |
union | Array-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_enabledare 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 trigger | Current source | OpenClaw role |
|---|---|---|
message | Telegram webhook job handled by Bloom. | None before job claim; possible node execution after Bloom resumes. |
webhook | GitHub webhook job handled by Bloom. | None before job claim; possible read-only execution after Bloom resumes. |
schedule | Bloom scheduler enqueues project_tick. | None before job claim; possible node execution after Bloom resumes. |
manual | Future 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:
humanandevent_waitnodes.subworkflownodes.- 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.