You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
[0.2.2] — 2026-07-14
⚠️ Breaking — migration required
reduce.from + {previous.output} now aggregates all sources. A reduce phase's {previous.output} previously resolved to only the last completed dependency. It now resolves to all completed from[] outputs in from-array order: one completed input → its raw output; multiple → ### <id>\n\n<output> sections joined by \n\n---\n\n. join: "any" includes only completed branches (skipped/failed omitted). Explicit {steps.ID.output} refs are unchanged. If your reduce task used {previous.output} expecting only the last dep, it now receives every from[] output — switch to explicit {steps.ID.output} refs to address individual sources. This fixes a long-standing dogfood issue where reducers silently lost inputs.
Resume now accepts only failed or paused runs. Attempts to resume completed or blocked runs are rejected before a fork is created. To execute completed work again, start a fresh run; to refresh a changed phase and its stale downstream frontier, use recompute.
MCP serverInfo.name is now host-specific. Clients that asserted the former generic "taskflow" name must accept "taskflow-codex", "taskflow-claude", "taskflow-opencode", or "taskflow-grok" for the corresponding adapter. Tool names and protocol behavior are unchanged.
Added
Configurable idle watchdog (idleTimeout). New flow-level and phase-level DSL field idleTimeout (ms). A positive value (≥ 1000) overrides the host default (300000 ms): if a subagent produces no output for this long it is killed as stalled. idleTimeout: 0disables the watchdog — but validation then requires a finite wall timeout (≥ 1000) on every agent-running phase that can use it, so a flow can never hang forever (critical invariant). Per-phase overrides flow-level. Threaded into RunOptions.idleTimeoutMs on both the imperative and event-kernel paths; included in cache identity/fingerprints automatically via the FlowIR definition hash (so changing it invalidates cross-run cache).
Prompt-size diagnostics. Every agent call's resolved prompt now records durable PhaseState.promptStats: exact UTF-8 byte count, character count, and a conservative approximate token estimate (ceil(chars/4), not a real tokenizer). A warning is appended when a prompt crosses a conservative threshold (~32K est. tokens). reduce phases also record reduceInputs aggregate stats (count + total bytes/chars/estTokens over the from[] inputs). Mirrored on the event-kernel path.
Hierarchical (tree) reduce. Opt-in via reduceStrategy: "tree" + batchSize (integer ≥ 2) on a reduce phase. Tree reduction batches the aggregated from[] inputs, runs intermediate reducer calls using the same agent/model/options/timeout/idleTimeout, and reduces round outputs until one remains — useful when the aggregated input would exceed a single prompt. Failures/usage/retry/budget behavior is preserved (each intermediate call reuses the phase's runOne wrapper), with a hard cap of 256 actual reducer attempts (including retries) even when no budget is declared. Default remains one-shot. reduceStrategy: "tree" forces the imperative runtime (the event kernel falls back via kernelUnsupportedReason); the corrected {previous.output} aggregation always applies regardless of strategy.
Shorthand cwd (dogfood issue 2). Top-level + per-step cwd for shorthand specs ({task} / {tasks} / {chain}). A top-level cwd is the default working directory for every step; a per-step cwd overrides it. Single and chain shorthand propagate cwd to each Phase.cwd (full workspace-keyword lifecycle — temp/dedicated/worktree). Parallel tasks honor each branch's own literal cwd, including mixed values across branches (a branch without a cwd falls back to the shared phase cwd); per-branch workspace keywords are rejected at validation time (the workspace lifecycle is per-phase — use the phase-level cwd for isolation).
Build/host identity (dogfood issue 4). New exported getBuildInfo() API (packageVersion, gitCommit, schemaVersion, buildTime). Package version is read from package metadata; the git commit is stamped at build time into dist/build-info.json (gitignored) — git is never invoked at runtime (deterministic "unknown" fallback in source/dev checkouts; PI_TASKFLOW_BUILD_COMMIT env override). RunState now carries optional packageVersion/gitCommit/host/schemaVersion/parentRunId; index entries preserve host/packageVersion/parentRunId. Pi runs stamp host=pi; MCP runs stamp the bound host (codex/claude/opencode/grok). New Pi action=version + MCP taskflow_version tool; the MCP initialize serverInfo name reflects the host (taskflow-codex, …).
Resume overrides + immutable history (dogfood issue 5). Resume now forks a new run (new runId + parentRunId) — the original run file is never mutated or overwritten. A ResumeOverrides API (phaseId + optional task/model/timeout/idleTimeout; at least one override required) re-runs exactly one phase with the overrides applied to the child's def only (the parent def is untouched); the target + its transitive downstream are cleared so they re-run, while completed unaffected phases are reused (within-run cache hits). Without overrides, ordinary resume forks a new run and re-runs the non-done phases. Validated, testable helpers (forkRunForResume / applyResumeOverrides / validateResumeOverrides / transitiveDownstream) live in taskflow-core/resume.ts; forkRunForResume fails closed for an invalid stored definition or invalid overrides. Pi action=resume accepts phaseId + resumeTask/resumeModel/resumeTimeout/resumeIdleTimeout; new MCP taskflow_resume tool; resume rendering reports the new run id + parent run id.
Output source attribution (dogfood issue 6).RuntimeResult / EventKernelResult now carry outputSourcePhaseId — the id of the phase whose output actually supplied finalOutput (the fallback final phase, or the blocking gate/approval phase for a gate/budget prefix; undefined when no phase output is available). Final-phase selection/fallback and the no-output default are unified between the imperative runtime and the event kernel via a shared resolveFinalOutput helper (taskflow-core/final-output.ts). Pi finalResult and MCP taskflow_run/taskflow_resume rendering now label the actual source phase — never the designated skipped/failed final phase.
Fixed
First-run trace regression guard. A FileTraceSink created before the per-flow run directory exists now has integration coverage proving the first run immediately records a readable, non-empty trace.
Timeout closure.race is now covered by idle-watchdog validation, and flat ctx_spawn descendants inherit the parent phase's idle watchdog, wall timeout, retry, tracing, budget, cwd, and workspace policy through the shared runOne path.
Tree-reduce cache, supervision, and attempt accounting. Tree reductions now consult a compact, stable pre-execution cache key that includes explicit and transitive step outputs, so completed work is reusable without stale hits. Intermediate reducer calls drain ctx_spawn children through the normal timeout/retry/budget/workspace path and fold their reports and usage into the tree. The 256-call ceiling counts actual runner attempts (including retries) without losing the final admitted attempt's usage; prompt diagnostics retain each reducer/child attempt once; budget truncation is explicit, preserves untouched inputs, is never cached, and aborts fail instead of masquerading as completion.
Budgeted fan-out supervision. Budgeted parallel/map phases publish each completed sibling's cumulative usage before draining its spawn intents. One atomic call may cross the ceiling, but no ctx_spawn child or sub-flow is admitted after that overshoot; pending intents are still drained deterministically.
Cwd and resume hardening. Every phase cache key now includes the canonical effective invocation cwd, including the default cwd, preventing a resume from mixing outputs produced in different roots. Parallel branch cwd values are resolved/canonicalized before both cache lookup and execution, and branches[].cwd on race/tournament is rejected instead of silently ignored. Resume deep-clones retained state, preserves workspace provenance, accepts only failed/paused runs, allows an override to re-run an already-completed upstream phase plus its downstream, and uses one host-neutral validation contract so an override can repair an invalid stored definition before execution. Children stamp the current build and host identity.
Event-kernel prompt accounting. Reduce/gate/loop/tournament retries now append one prompt diagnostic per actual runner attempt, matching the imperative runtime.
Release identity and discovery metadata. Pi's tool description and the Codex/Claude/Grok marketplace manifests now advertise all 12 phase types and all 15 MCP tools, including resume/version. stamp-build-info --check is read-only and rejects stale/malformed build stamps instead of rewriting them before validation.