Skip to content

v0.2.2

Latest

Choose a tag to compare

@github-actions github-actions released this 14 Jul 08:32
300da53

[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: 0 disables 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.