Scoped Injection
History Editing (Scoped Injection)
Scoped Injection is history editing — change what happened, see what would have happened. Pause a running workflow at step boundaries, inspect and modify completed step outputs, and resume execution with the modified data. It extends history correction (hot patching) from reactive (fix after failure) to proactive (intervene during execution).
When to Use
- Debug production issues in real-time without cancelling workflows
- Modify intermediate data flowing between steps
- Test “what if” scenarios on live workflows
- Fix data issues before they propagate to downstream steps
CLI Walkthrough
1. Pause a Running Workflow
Request the run to pause at the next step boundary:
ironflow run pause run-abc123# Run run-abc123: pause_requestedThe workflow finishes its current step, then holds before the next one.
2. Inspect Paused State
View completed steps, their outputs, and which step will execute next:
ironflow run paused-state run-abc123Use --json for machine-readable output:
ironflow run paused-state run-abc123 --json{ "pause_reason": "injection", "next_step_hint": "send-notification", "steps": [ { "id": "step_001", "name": "fetch-order", "injected": false, "output": {"orderId": "123"} }, { "id": "step_002", "name": "validate-payment", "injected": false, "output": {"valid": true, "amount": 99} } ]}3. Inject Modified Output
Replace the output of a completed step:
ironflow run inject run-abc123 step_002 \ --output '{"valid": true, "amount": 50}' \ --reason "Corrected amount for partial refund test"# Injected step step_002# Previous output: {"valid":true,"amount":99}4. Resume the Workflow
Resume execution from where it paused:
ironflow run resume run-abc123Resume from a specific step:
ironflow run resume run-abc123 --from-step step_003The workflow continues with the injected data flowing to downstream steps.
SDK Configuration
Pause Behavior
When registering a function, set pauseBehavior to control what happens after injection:
"hold"(default) — The run stays paused until explicitly resumed. Use this when you want to inspect, inject multiple steps, and then resume."release"— The run automatically resumes after an injection. Use this for quick single-step fixes.
import { ironflow } from "@ironflow/node";
const myFunction = ironflow.createFunction( { id: "process-order", triggers: [{ event: "order.created" }], pauseBehavior: "hold", // or "release" }, async ({ event, step }) => { const order = await step.run("fetch-order", async () => { return db.orders.find(event.data.orderId); });
await step.run("send-notification", async () => { return notifications.send(order.customerId, order); }); },);var ProcessOrder = ironflow.CreateFunction(ironflow.FunctionConfig{ ID: "process-order", Triggers: []ironflow.Trigger{{Event: "order.created"}}, PauseBehavior: "hold", // or "release"}, func(ctx ironflow.Context) (any, error) { // ...})Client Methods
import { createClient } from "@ironflow/node";
const client = createClient({ serverUrl: "http://localhost:9123" });
// Pause a running workflowawait client.pauseRun("run_abc123");
// Inspect paused stateconst state = await client.getPausedState("run_abc123");for (const step of state.steps) { console.log(step.name, step.output, step.injected);}console.log("Next step:", state.nextStepHint);
// Inject modified outputconst result = await client.injectStepOutput( "run_abc123", "step_xyz", { corrected: true }, "Manual correction");console.log("Previous output:", result.previousOutput);
// Resumeawait client.resumeRun("run_abc123");client := ironflow.NewClient(ironflow.ClientConfig{ServerURL: "http://localhost:9123"})
// Pause a running workflowstatus, err := client.PauseRun(ctx, "run_abc123")
// Inspect paused statestate, err := client.GetPausedState(ctx, "run_abc123")for _, step := range state.Steps { fmt.Printf("Step %s: injected=%v\n", step.Name, step.Injected)}
// Inject modified outputprevOutput, err := client.InjectStepOutput(ctx, "run_abc123", "step_xyz", json.RawMessage(`{"corrected": true}`), "Manual correction",)
// Resumerun, err := client.ResumeRun(ctx, "run_abc123", "")Dashboard
The run detail page shows scoped injection controls:
- Pause — Click the pause button on a running workflow
- Inspect — View all completed steps and their outputs in the timeline
- Inject — Click a step to edit its output JSON, enter a reason, and save
- Resume — Click the resume button to continue execution
Injected steps are visually marked in the timeline so you can see which outputs were modified.
Advanced Usage
Injecting into Failed Steps
You can also inject corrected output into FAILED steps. This transitions the step to COMPLETED and allows the run to resume past the failure point — a powerful recovery mechanism for production incidents.
ironflow run inject run-abc123 step_003 \ --output '{"recovered": true}' \ --reason "Recovered from external API timeout"Idempotency
Calling PauseRun on a run that is already pause-requested returns success without error. If a run is already paused (e.g., from a sleep/wait yield), calling PauseRun upgrades the pause reason to injection.
Audit Trail
Every injection is recorded as a step.injected audit event with:
- The step ID and name
- Previous and new output values
- The reason provided
- Timestamp and actor
Query injection history via the audit CLI:
ironflow audit trail <run-id> --type step.injectedWhat’s Next?
- Debugging — Hot patching, TUI debugger, VS Code DAP
- Error Handling — Retry policies and non-retryable errors