Feature Request: $LOOP_PREV_OUTPUT variable for loop nodes
Problem
loop: nodes in DAG workflows have no way to inject the previous iteration's output into the next iteration's prompt when fresh_context: true. The variable lastIterationOutput is computed in executeLoopNode at the end of each iteration but is immediately discarded — it is never exposed to the prompt substitution system.
- Experienced by anyone authoring
loop: nodes that use fresh_context: true and need the AI to know why the previous pass failed (e.g. QA failure summaries, validation errors, review feedback) without carrying the full conversation history forward.
- Comes up in every retry-on-failure pattern: implement→validate loops, review→fix loops, generation→evaluation loops.
Proposed Solution
Add a $LOOP_PREV_OUTPUT substitution variable populated from the previous iteration's cleaned output, available inside loop.prompt from iteration 2 onward. On iteration 1 it substitutes to an empty string. When fresh_context: false the variable still works but is redundant since session history already carries the context.
Implementation touches two places:
executor-shared.ts — add loopPrevOutput?: string parameter to substituteWorkflowVariables
dag-executor.ts (executeLoopNode) — pass lastIterationOutput (already computed at line 1751) into the substitution call on each subsequent iteration
User Flow
Before (current)
loop:
prompt: |
Implement the plan, then run `bun run validate`.
If checks fail, fix them and retry.
[!] No way to reference why the previous iteration failed —
[!] the agent starts each fresh-context iteration blind.
When all checks pass output: <promise>QA_PASS</promise>
until: QA_PASS
fresh_context: true
max_iterations: 3
After (proposed)
loop:
prompt: |
Implement the plan, then run `bun run validate`.
[+] Previous iteration output (empty on first pass):
[+] $LOOP_PREV_OUTPUT
Use the above to understand what failed last time (if anything)
and focus your fixes there. When all checks pass output: <promise>QA_PASS</promise>
until: QA_PASS
fresh_context: true
max_iterations: 3
Alternatives Considered
| Alternative |
Pros |
Cons |
Why not chosen |
fresh_context: false (thread session) |
Zero engine changes; model has full history |
Full conversation grows with every iteration — higher cost and context pressure; not suitable when a clean slate is intentional |
Doesn't solve the case where fresh context is explicitly desired |
Write output to $ARTIFACTS_DIR manually |
Works today, no engine changes |
Requires prompt boilerplate in every workflow; agent must remember to write the file; reading it back adds another tool call |
Too much friction for a common pattern |
Pass failure summary via until_bash side-channel |
Deterministic |
until_bash is an exit-condition check, not a data channel; would require abusing its semantics |
Wrong abstraction |
Scope
- Package(s) likely affected:
workflows
- Breaking change? No —
$LOOP_PREV_OUTPUT substitutes to empty string when absent/first iteration; existing prompts that don't reference it are unaffected
- Database changes needed? No
- New external dependencies? No
Security Considerations
- New permissions/capabilities? No
- New external network calls? No
- Secrets/tokens handling? No —
$LOOP_PREV_OUTPUT reflects AI-generated output from within the same workflow run, same trust boundary as all other $nodeId.output substitutions
Definition of Done
Feature Request:
$LOOP_PREV_OUTPUTvariable for loop nodesProblem
loop:nodes in DAG workflows have no way to inject the previous iteration's output into the next iteration's prompt whenfresh_context: true. The variablelastIterationOutputis computed inexecuteLoopNodeat the end of each iteration but is immediately discarded — it is never exposed to the prompt substitution system.loop:nodes that usefresh_context: trueand need the AI to know why the previous pass failed (e.g. QA failure summaries, validation errors, review feedback) without carrying the full conversation history forward.Proposed Solution
Add a
$LOOP_PREV_OUTPUTsubstitution variable populated from the previous iteration's cleaned output, available insideloop.promptfrom iteration 2 onward. On iteration 1 it substitutes to an empty string. Whenfresh_context: falsethe variable still works but is redundant since session history already carries the context.Implementation touches two places:
executor-shared.ts— addloopPrevOutput?: stringparameter tosubstituteWorkflowVariablesdag-executor.ts(executeLoopNode) — passlastIterationOutput(already computed at line 1751) into the substitution call on each subsequent iterationUser Flow
Before (current)
After (proposed)
Alternatives Considered
fresh_context: false(thread session)$ARTIFACTS_DIRmanuallyuntil_bashside-channeluntil_bashis an exit-condition check, not a data channel; would require abusing its semanticsScope
workflows$LOOP_PREV_OUTPUTsubstitutes to empty string when absent/first iteration; existing prompts that don't reference it are unaffectedSecurity Considerations
$LOOP_PREV_OUTPUTreflects AI-generated output from within the same workflow run, same trust boundary as all other$nodeId.outputsubstitutionsDefinition of Done
substituteWorkflowVariablesinexecutor-shared.tsaccepts and substitutes$LOOP_PREV_OUTPUTexecuteLoopNodepasseslastIterationOutput(empty string on iteration 1) tosubstituteWorkflowVariableson every iteration$LOOP_PREV_OUTPUTdocumented alongside$LOOP_USER_INPUTinCLAUDE.mdvariable referencearchon-compose-plan-implement-qa.yamlupdated to demonstrate the variable in its prompt$LOOP_PREV_OUTPUTis empty on iteration 1, equals previous output on iteration 2+$LOOP_PREV_OUTPUTare unaffected