Observation
packages/dev-workflow/run.ts line 160:
```ts
const result = await executor.run(updatedInput);
```
This blocks until the entire workflow completes. A 5-step workflow hitting codex for plan (30s) + build (5-10min on a non-trivial feature) + test (5-10min) + verify (30s) + ship (10s) takes 10-30min real time. During that window the operator sees zero output — is it hung, working, silently errored? No way to tell.
What exists
@ageflow/executor exports executor.stream(input) → AsyncGenerator<WorkflowEvent, WorkflowResult>. Events include:
workflow:start
task:start { taskName, input }
task:finish { taskName, output, tokensIn, tokensOut, costUsd }
task:error { taskName, error }
workflow:finish { metrics }
What's missing
run.ts should use executor.stream() and print each event:
```ts
const gen = executor.stream(updatedInput);
for await (const ev of gen) {
switch (ev.type) {
case "task:start":
console.log([${ev.taskName}] starting…);
break;
case "task:finish":
console.log([${ev.taskName}] ✓ (${ev.costUsd?.toFixed(3) ?? "0.000"} USD, ${(Date.now() - ev.startedAt) / 1000}s));
break;
case "task:error":
console.error([${ev.taskName}] ✗ ${ev.error});
break;
}
}
const result = gen.return; // or drain to end
```
Bonus:
- Running cost counter (
[total] 2.34 USD / 5.00 cap)
- Budget warning at 80%
- Colors (green ✓, red ✗) — chalk is already in deps via cli package
Severity
High DX. Without this, "first live run" is an anxiety-driven stare at a terminal. With this, the operator knows what's happening + can abort intelligently.
Observation
packages/dev-workflow/run.tsline 160:```ts
const result = await executor.run(updatedInput);
```
This blocks until the entire workflow completes. A 5-step workflow hitting codex for
plan(30s) +build(5-10min on a non-trivial feature) +test(5-10min) +verify(30s) +ship(10s) takes 10-30min real time. During that window the operator sees zero output — is it hung, working, silently errored? No way to tell.What exists
@ageflow/executorexportsexecutor.stream(input)→AsyncGenerator<WorkflowEvent, WorkflowResult>. Events include:workflow:starttask:start { taskName, input }task:finish { taskName, output, tokensIn, tokensOut, costUsd }task:error { taskName, error }workflow:finish { metrics }What's missing
run.ts should use
executor.stream()and print each event:```ts
const gen = executor.stream(updatedInput);
for await (const ev of gen) {
switch (ev.type) {
case "task:start":
console.log(
[${ev.taskName}] starting…);break;
case "task:finish":
console.log(
[${ev.taskName}] ✓ (${ev.costUsd?.toFixed(3) ?? "0.000"} USD, ${(Date.now() - ev.startedAt) / 1000}s));break;
case "task:error":
console.error(
[${ev.taskName}] ✗ ${ev.error});break;
}
}
const result = gen.return; // or drain to end
```
Bonus:
[total] 2.34 USD / 5.00 cap)Severity
High DX. Without this, "first live run" is an anxiety-driven stare at a terminal. With this, the operator knows what's happening + can abort intelligently.