LLM Key Propagation and Diagnostics
We resolved an issue in the LLM client layer where validated API keys were not being passed correctly to LiteLLM. Diagnostics have also been improved to surface sanitized provider error details when an API call fails.When an LLM provider call fails, diagnostic rendering now displays the provider’s underlying error details with API-key material masked.
- Fixed API key handling to ensure the validated key is reliably forwarded to LiteLLM during model invocations.
- Enhanced error handling to surface explicit provider error text in diagnostic failure outputs.
Updated Default Models
pflow’s existing automatic model selection now targets newer released models for each supported provider.Highlights- Updated the Anthropic default from
anthropic/claude-sonnet-4-5toanthropic/claude-sonnet-5. - Updated the Google default from
gemini/gemini-3-flash-previewtogemini/gemini-3.5-flash-lite. - Updated the OpenAI default from
openai/gpt-5.2toopenai/gpt-5.6-luna. - Updated the discovery and filtering fallback from Sonnet 4.5 to Sonnet 5.
Durable Workflow Resumption and Non-TTY Gates
We introduced a workflow resumption engine that continues failed or interrupted runs from the failed top-level step while restoring completed upstream outputs. Human approval gates now work in non-interactive (non-TTY) environments by saving execution state to the streamable trace file and issuing durable tokens that can be answered later.Completed upstream steps are restored rather than rerun. The failed step itself starts again, so a partially completed side effect may fire twice; interactive resumes ask for confirmation and non-interactive resumes require
--force. Resuming by execution ID is independent of the current directory, but the original workflow file must still exist at its recorded path and match the saved content hash.- Added the
pflow resumeCLI command to continue failed or interrupted runs (such as those halted by Ctrl+C or SIGKILL) from the failed node. - Added durable pause state tracking that outputs a resume token and writes paused execution parameters cleanly to the trace file when a gate triggers in non-TTY environments.
- Implemented the
pflow resume listsub-command to scan and display pending unanswered gates awaiting response. - Added direct option mapping for the
--chooseparameter, converting numeric selections or label strings into structured gate resolutions inside the execution loader. - Fixed attempt-chain tracking to prevent dead or interrupted runs from wedging resumption sequences when running
pflow resumeagainst a workflow path. - Fixed candidate execution scans to ensure only attempts that successfully executed novel work supersede older resumable runs.
Unified Agent Nodes and AI-Assisted Development
We unified our autonomous coding nodes into a single, cohesive execution block. The legacyclaude-code node has been replaced by a unified agent node that supports both Anthropic Claude and OpenAI Codex backends via a clean parameter contract, reducing compilation overhead and aligning schema definitions.- Introduced the unified
agentnode, allowing workflows to toggle between Claude and Codex behaviors using thebackend: claude|codexparameter. - Implemented strict parameter-shape checking inside
schema_validation.pyto enforce shared parameters and catch configuration anomalies before runtime. - Improved the
agentnode to raise a structuredPflowErrorfor parameter validation issues, ensuring failed setups abort early during execution preparation. - Added support for inspecting local workflow files inside
pflow describe, letting developers review structural parameters without loading or generating execution history.
Interactive Web UI, Approval Bridges, and Voice Narration
The browser visualizer is now a full control center. You can answer paused gates or trigger workflow resumptions directly from the browser canvas. We also launched agent voice narration, bringing stateful point-and-say commentary and automated walkthrough pacing to the UI.- Added the Web-UI Approval Bridge: rendering interactive Yes/No callout panels on paused nodes and Resume controls on failed nodes inside
pflow ui. - Added playback beacons (
started,blocked, andendedevents) that report real-time audio playback state from the browser back to the UI server. - Added Agent Voice Narration, enabling workflows to synthesize voice messages via Gemini TTS using a custom
[bracket]tag format. - Implemented a closed-loop CLI pacing system (
_await_narration_turn) that polls the UI server’s playback queues to align text narration with physical speech pacing. - Added
pflow settings llm set-tts-modelandpflow settings llm set-tts-voicecommands to configure global text-to-speech preferences. - Added visual trace indicators to the UI selector, displaying the execution path lineage (
⤷ resumed from <id>) under resumed attempts.
Windows Compatibility and Execution Robustness
We added Windows support while preserving one portable shell contract: shell steps use POSIXsh semantics on every platform, with Git Bash supplying the runtime on Windows. This release also strengthens schema validation, MCP guidance, and trace handling across platforms.- Added Windows compatibility support, establishing Git Bash as the native POSIX shell emulator across win32 environments.
- Added Win32-specific pipe detection using Windows file-type handles to support UTF-8 CLI inputs in non-TTY terminals.
- Added automatic stdio stream re-encoding, forcing Windows consoles to communicate using byte-exact UTF-8 pathways.
- Fixed trace corruption at the LiteLLM integration boundary by deep-copying messages before sending requests to remote providers.
- Fixed local LLM schema validation, throwing immediate validation errors and following error-routing paths instead of caching invalid JSON outputs.
- Fixed MCP tool output guidance to expose declared nested paths under the canonical
result.*namespace. - Fixed transient Windows file locks while saving MCP server configuration by retrying atomic replacements.
- Fixed the MCP node to strip system sidecar tracking fields (
_source_lineand_prompt_source_line) from forwarded tool parameters.
Breaking changes
Breaking changes
Claude Code Node Removed
Theclaude-code node has been completely removed from the registry. All workflows employing autonomous development agents must migrate to the new agent node and declare their target backend:use_api_key: true. The default fails closed unless Codex has recognized account authentication.Interactive Web UI and Live Overlay
We launched an interactive visualizer and control center. Using thepflow ui command, you can render your entire workflow structure dynamically using an ELK-layout canvas, launch detached execution runs directly from your browser, pre-fill parameters using past-run history, and watch execution progress live via an SSE overlay.- Added the
pflow uicommand, introducing a web UI using React Flow and ELK layout engines. - Added a live execution overlay that tails execution traces and lights up running, cached, successful, or failed nodes dynamically.
- Implemented an interactive execution launcher on the canvas with auto-generated input forms, past-run parameter pre-filling, and detached runner spawning.
- Added a stateful agent-to-browser interaction channel (“Point & Watch”) with CLI commands
focus,frame,clear-focus, anduser-activity. - Added an output-node panel to inspect resolved inputs, outputs, costs, and token usages per node directly from live execution files.
- Fixed multi-tab browser connection limits by releasing connection pooling boundaries for Server-Sent Events (SSE).
- Improved UI server robustness with auto-reconnection filters and automatic viewer-tab reuse.
- Redesigned UI run selection by git-bucketing histories, grouping runs under local git repositories.
Declarative Stateful Loops and Human Approval Gates
Workflows now support stateful loops and interactive verification steps. You can declare condition-terminated iterations that thread variable states across sequential iterations without side effects, or insert human-in-the-loop steps that pause execution for approval.- Added human-in-the-loop approval gates via the
approval: requiredmodifier, pausing execution for interactive YES/NO confirmations. - Added agent-raised escalation gates, allowing
agentorcodesteps to pause execution usingresult.escalationblocks. - Added the
--auto-approve=<node-id>repeatable CLI flag and an equivalent MCPauto_approveexecution option. - Implemented the
loop:node modifier withwhile:anduntil:conditions, backed by a robust engine-reentry compiler pattern. - Added the
carry:state-mapping block ({ input_key: ${loop-node.output} }) to thread outputs sequentially across loop iterations. - Added support for settable node-level retry configurations with configurable max attempts, initial wait times, and linear/exponential backoff.
- Fixed empty-input batches to output a non-degrading advisory message rather than raising a false
DEGRADEDwarning. - Added a loop iteration indicator (
⟳badge) and self-edge representations to workflow visual layouts.
Streamable Traces and Content Interning
Execution traces are now written incrementally as each node completes, protecting run diagnostics from crash termination. These traces are compressed automatically by interning string blobs at the file boundary and canonicalizing LLM-producing node parameters.Because streamable traces use raw JSONL entries, pflow can read incomplete runs. If a run crashes, the system can reconstruct trace logs up to the failure point while gracefully dropping dangling sub-workflow nodes.
- Rebuilt tracing as an incremental JSONL streaming transport, flushing execution events to disk line-by-line during runtime.
- Added content interning at the disk boundary, replacing the legacy
blobstrailer with inline-first-occurrence blob keys. - Shrink trace footprint by canonicalizing LLM prompts and systems, stripping redundant template resolutions and raw parameters.
- Added prewarm-batch prompt optimization, capturing shared prefixes as cache blocks to prevent duplicate prompt storage.
- Fixed the
--onlyexecution flag to restore a frozen snapshot of historical upstream inputs instead of re-firing side-effecting steps. - Added support for reporting true input token counts and agent execution calls in output summaries.
- Added cache-aware API-equivalent cost estimates for Codex agent calls when workflows declare a LiteLLM-priced
model. - Added best-effort trace writing, allowing runs to execute safely even under disk-full or read-only filesystem environments.
LLM Control and Execution Refinements
We adjusted default execution settings, upgraded the?? coalesce operator to support JSON literals, and added type coercion capabilities to Claude Code output schemas.- Flipped memoization defaults: only
llmnodes cache by default; all other node types require explicit- cache: true. - Added support for JSON literals (
string,number,boolean,null) inside??template coalesce operations. - Improved the
??operator to fall through on absent sub-fields and unexecuted branches without raising validation errors. - Added self-healing schemas to
agentoutputs, enabling scalar type coercion and resume-retries on schema soft-failures. - Added pre-execution validation for LLM model IDs, throwing validation errors before initiating live provider calls.
- Unified reasoning budget parameter mappings (
reasoning_effortandreasoning_max_tokens) across LLM providers. - Added support for shielding
${...}templates in flow-style YAML, preventing unquoted inline maps from parsing incorrectly. - Fixed
code-nodetype validations, allowing outputs of typelist[T]to satisfy parameters expectinglist[str]. - Added a redirection helper for CLI users typing
pflow validate <wf>orpflow check <wf>, suggesting the correct--validate-onlycommand. - Added calendar validation for task scripts, rejecting impossible dates like leap-year boundary failures.
Breaking changes
Breaking changes
Caching Defaults Flipped
Non-LLM nodes (such ascode, shell, and http) no longer cache execution results by default. Workflows relying on memoization for these steps must explicitly set - cache: true.Mermaid Command Renamed
Thepflow visualize command has been renamed to pflow mermaid.Storage Mode Removed
Thestorage_mode parameter has been deleted entirely.Agent API-key opt-in
use_api_key is now one shared strict permission on agent nodes. In false/default mode,
Claude blanks ANTHROPIC_API_KEY; Codex removes OPENAI_API_KEY / CODEX_API_KEY, requires
recognized account auth from codex login status, and pins the OpenAI provider selector.
Existing Codex workflows that intentionally use API-key or configured-provider billing must
add use_api_key: true or they now fail before the model call. This guard controls the named
key and ordinary provider paths; account credits, auto-reload, overage, custom proxies/base
URLs, and administrator policy remain provider/user controls.MCP Result Access
MCP nodes no longer copy top-level result fields into${node.field} or create a {server}_{tool}_result alias. Access tool output through the canonical ${node.result.field} path instead.Declarative prompt caching and pflow analyze-cache
We introduced provider-level prompt caching as a declarative workflow surface. By defining a top-level ## Cache section and declaring chunks on your LLM nodes, prompt prefixes are cached directly at the provider level (such as Anthropic and Gemini), dramatically reducing costs and latency for repetitive system instructions and context.pflow analyze-cache command performs static and trace-driven analysis of your workflow. It estimates cacheable tokens, models per-call cost projections, and provides actionable, headline-led recommendations without executing live model calls.- Added the top-level
## Cachemarkdown section to parse declarative, reusable prompt chunks. - Added the
prompt_cacheandprewarmproperties to LLM nodes to control cache inclusion and gate automatic batch-prefix caching. - Implemented the
pflow analyze-cacheCLI command (and matching MCP tool) with Greenfield, Steady-state, Trace-driven, and Already-optimal analysis modes. - Added a 22-entry warning catalog to flag cache misalignments, prompt shadow duplicates, and missing shared references.
- Implemented dynamic cache TTL translation for Gemini models (
cachedContents) alongside Anthropic native controls. - Added support for multi-breakpoint prompt caching for Anthropic models.
- Implemented synthetic cache warmup capabilities and detailed cost telemetry in trace formats.
- Fixed prewarm diagnostics to correctly account for declared
prompt_cachechunks.
Native structured outputs for Claude Code
We replaced Claude Code’s prompt-injected and regex-extracted structured output system with native JSON Schema support usingclaude_agent_sdk’s native structured output capabilities. This ensures guaranteed schema compliance without competing system instructions or fragile string parsing.Claude Code structured output failures are now treated as “soft failures.” If the session fails to comply with the schema, the raw text is preserved, a
_schema_error is set, and the run continues in a DEGRADED status rather than raising a hard error that aborts your workflow.- Upgraded the Claude Code node to use
ResultMessage.structured_outputvia the native SDK, requiring a minimum ofclaude-agent-sdk>=0.2.82. - Added preflight and static validation to enforce that Claude Code output schemas define a top-level
type: object. - Added a strict constraint requiring
max_turns >= 2when an output schema is defined to allow planning and output turns. - Implemented warning rehydration inside the persistent memoization cache, ensuring that cached soft-failures correctly replay as
DEGRADEDrather than passing as successful. - Narrowed exception handling within Claude Code sessions to
ProcessErrorto allow actionable SDK remediation messages (like installation and doctor checks) to bubble up. - Aligned the Claude node’s output parsing by linking the “Outputs” parse-hint with the accepted
sourcekey, and stripped runtime-internal vocabulary from agent error messages.
LiteLLM integration and offline pricing
We rebuilt our LLM execution layer, replacing the existing integration with a pflow-owned adapter backed natively by LiteLLM. This migration unifies over 100 model providers under a single, robust seam with unified exception mapping and cost tracking.- Replaced the
llmpackage with a lazy-imported LiteLLM wrapper, improving overall CLI startup performance. - Added a typed exception hierarchy under
LLMCallErrorto provide structured discriminators (UnknownModelError,MissingApiKeyError,LLMTransientError) for downstream retry and fallback routing. - Redesigned tracing to use a
shared["__trace_collector__"]save/restore context, fixing a thread-boundary bug where literal prompt captures were silently omitted. - Added a deterministic offline pricing map for LiteLLM models to ensure accurate cost estimation when pricing metadata is missing from local snapshots.
- Added automatic bare model name prefixing (e.g.,
gpt-4onormalized toopenai/gpt-4o) to ensure correct routing. - Fixed a pricing bug where
cost_usdwas left unpopulated for newer LLM models released after our bundled LiteLLM snapshot. - Upgraded the default LiteLLM engine version and fixed
reasoning_effortmapping for Anthropic Claude 3 Opus.
CLI usability and parser refinement
We refined our CLI output, added more helpful diagnostics to failing pipelines, and improved the core Markdown parser to handle complex YAML block structures.Highlights- Added support for dotted paths inside CLI output destination flags (e.g.
-o data.nested.field). - Added walk-to-failure hints to the terminal output on workflow failures to assist agents in debugging sequence halts.
- Implemented a more compact summary representation for large batch node executions.
- Fixed linting for shell nodes without template inputs to offer both available cache resolutions in the warning text.
- Fixed the markdown parser to preserve blank lines inside multi-line YAML block scalars, preventing layout corruption of templates and prompts.
Breaking changes
Breaking changes
Claude Code Python-alias schemas removed
Legacy Python-alias type names (str, int, list, dict) are no longer supported inside Claude Code output_schema blocks. All schemas must use standard JSON Schema types and declare a top-level type: object.Claude Code Turn minimums
Workflows declaring a Claude Code node with anoutput_schema must set max_turns to 2 or greater. Workflows specifying max_turns: 1 will fail validation.AdapterResponse shape changes
The internal response object from LLM calls no longer carrieserror or status fields. Failure states now consistently raise a subclass of LLMCallError. Downstream steps catching custom exceptions should catch LLMCallError and read structured attributes (kind, reason).LiteLLM package pinning and model names
- Simon Willison’s
llmCLI and its associated provider plugins are no longer used. Environment variables (likeOPENAI_API_KEY) are read directly from the shell or viapflow settings. - LLM nodes require provider-prefixed model names (e.g.
openai/gpt-4oinstead ofgpt-4o). Bare names are auto-prefixed based on common naming conventions, but unknown bare names will pass through unchanged.
Caching flag behavior
The--no-cache CLI flag now only bypasses local pflow memoization reads. It does not disable LLM provider-level prompt caching.Execution previews and planning
We introduced a high-fidelity execution planner via the--dry-run flag. It provides historical LLM cost and duration estimates without invoking side effects, using the same cache-key and template-resolution logic as the live engine to ensure zero drift.The planner now supports full per-item recursion for batch sub-workflows, allowing you to see exactly which items in a large parallel run would execute and which would serve from cache.
- Added the
--dry-runflag to provide execution plans with historical cost ($USD) and duration estimates. - Implemented recursive batch planning that aggregates child summaries into a single synthetic plan, correctly handling parallel vs. sequential durations.
- Added a
cost_basisindicator (upper_boundvsexact) to dry-run summaries to help agents gate high-cost operations. - Fixed dry-run recursion for batch sub-workflows to prevent false validation errors on
${item}-backed child inputs.
Modernized CLI and guidance
The CLI has been flattened into a focused, top-level surface, and the monolithic agent instructions have been replaced bypflow guide—a topic-scoped system that delivers framework and node-specific guidance at runtime.- Flattened the CLI surface:
pflow workflow <verb>andpflow registry <verb>are now top-level commands likepflow list,pflow describe, andpflow probe. - Added
pflow guide, a content delivery system that composes help topics based on requested scope or auto-detected workflow features. - Improved non-interactive output routing: live progress now streams to
stderrin real-time, while node data is routed strictly tostdoutfor clean piping tojq. - Added an exception boundary to the MCP server via a
FastMCPsubclass to provide structured diagnostics to agents. - Consolidated
pflow trace reportinto the flattenedpflow reportcommand. - Added confidence-based guidance and runnable command hints to the
pflow findoutput.
Type safety and native diagnostics
We refactored the workflow type vocabulary to use canonical JSON Schema names and moved the validation engine to produce structuredDiagnostic objects natively. This ensures that typos and contract violations are caught early with rich, actionable “Did you mean?” suggestions.Highlights- Refactored the type vocabulary to 7 canonical names:
string,integer,number,boolean,array,object, andany. - Upgraded the validator to produce
Diagnosticobjects natively, enabling numbered lists, fuzzy suggestions, and source-line tracking in all validation errors. - Implemented a strict parent-to-child input boundary for sub-workflows that rejects undeclared inputs at both parse-time and runtime.
- Added validate-time type checking for Python code-node input and result/next annotations.
- Unified the
??coalesce operator to correctly distinguish between nodes that were skipped and nodes that failed. - Fixed workflow and template validators to short-circuit on structural errors, preventing cascades of redundant messages.
Rich Mermaid visualization
The Mermaid visualization system has been transformed into a full data-flow engine. It now renders sub-workflow boundaries, external IO subgraphs, and data-provenance edges derived from template references.- Added support for “External IO” wrappers that render sub-workflow inputs and outputs as dashed subgraphs outside the primary pipeline.
- Added data-flow edges that trace the actual provenance of data through
${node.field}template references. - Implemented the Mermaid
procsshape (stacked rectangles) to visually communicate batch parallelism. - Added
--descriptionssupport to the visualizer to include node-level documentation in the rendered output. - Improved layout logic to connect top-level inputs directly to their nearest consumer, preventing long-range edges from distorting the diagram.
Reliability and invariants
This release addresses several critical execution invariants, particularly how the shared store handles node failures and how batch results are filtered.Highlights- Fixed the failed-node invariant: data from failed nodes now moves to
shared["__failures__"]instead of leaking intoshared[node_id], preventing downstream nodes from accidentally reading partial or failed results. - Updated batch processing to exclude failed items from the
resultsarray, ensuring downstream nodes receive only successful data. - Added protection against
__dunder__parameter names to prevent workflows from accidentally overwriting internal framework state. - Implemented a
_ProgressPartialLineFilterto preventlogger.warningmessages from corrupting live progress lines. - Added automatic node registry refreshing when source files change on disk.
- Fixed on-error recovery reporting to correctly reflect a
DEGRADEDstatus instead of a falseSUCCESS.
Breaking changes
Breaking changes
Flattened CLI commands
The hierarchicalworkflow and registry namespaces have been removed.pflow workflow save→pflow savepflow workflow history→pflow historypflow registry run→pflow probepflow instructions→pflow guidepflow mcp tools→pflow mcp list
Type vocabulary refactor
Python type aliases (str, int, list, dict) are no longer supported in ## Inputs or ## Outputs.- Use
stringinstead ofstr. - Use
integerinstead ofint. - Use
arrayinstead oflist. - Use
objectinstead ofdict. - Use
anyfor wildcards.
Sub-workflow input strictness
- The
workflow_irinline-IR escape hatch has been removed. Use file references instead. - Sub-workflows now reject undeclared inputs. Any parameter passed from a parent must be explicitly declared in the child’s
## Inputssection.
Failed-node data location
Data from failed nodes is no longer available atshared[node_id]. It is archived in shared["__failures__"][node_id]. Standard template references to failed nodes will now correctly trigger “node did not execute” errors unless the coalesce operator (??) is used.Batch result filtering
Whenerror_handling: continue is used, the results list in the batch output no longer contains None or error objects for failed items; it only contains successful results.Execution core and iteration speed
We rebuilt the execution core with a standalone orchestration engine that compiles workflows once per batch, dropping compilation overhead to near zero. A new SQLite-backed memoization cache lets you iterate rapidly by re-using results for unchanged nodes.The memoization cache is automatically propagated to all nesting levels, meaning unchanged sub-workflows and nodes safely serve cached results without re-executing.
- Redesigned the execution core to compile sub-workflows once per batch, yielding a ~7x speedup for large parallel iterations.
- Added a persistent memoization cache system with
--onlyand--no-cacheCLI flags for precise, rapid iteration control. - Added per-node cache opt-out support via the
cache: falseproperty. - Fixed concurrent mutation issues in the workflow executor during compilation.
- Fixed an intermittent bug where zombie threads caused stream corruption (
I/O operation on closed file) in Python code nodes.
Execution reports and traces
The trace system has been redesigned from flat JSON snapshots to a tree-structured format. You can now generate navigable Markdown reports that display exact rendered prompts, outputs, and LLM costs for every node.- Added the
--reportflag to generate a directory of Markdown files detailing execution, including input/output token breakdowns and rendered templates. - Upgraded trace format to 2.0.0: uses tree-structured events that correctly nest batch items and sub-workflows without truncating data.
- Added smart anomaly detection in reports to flag empty outputs (like dropped HTTP bodies) and provide template fix suggestions.
- Cross-cutting infrastructure keys and LLM costs now propagate correctly through deeply nested sub-workflows.
- Added LLM parameters (temperature, reasoning effort, system prompt) to node metadata in reports.
- Fixed cache invalidation for sub-workflow changes and eliminated phantom cost reporting in traces.
File references and workflow bundling
Code block parameters can now reference external files directly. To support this safely,pflow workflow save now bundles workflows and their file dependencies into self-contained directories.- Code-block parameters (
prompt,code,command,batch,output_schema) can now reference external files. The system auto-detects paths, reads the files, and resolves templates inside them at compile time. pflow workflow savenow packages workflows as folders containing the entry point and all referenced dependencies, preserving relative directory structures.- Added per-item parameter overrides in batch nodes — each item can set its own
model,reasoning_effort, or any other node parameter, so a single batch can mix providers or effort levels. - Added the
inputsparameter as template context for all node types, not just code nodes. - Fixed relative path resolution so sub-workflow dependencies always resolve against the sub-workflow’s directory, not the current working directory.
- File references in sub-workflows are now fully resolved before validation.
Validation and diagnostics
We rebuilt the CLI error output pipeline and validation engine. Every error now renders in a single diagnostic format — title, location, context block, and fix suggestion (e.g., “Did you mean ‘file_path’?”) — consistent across text and JSON output. The parser catches deeper structural issues before execution begins.- Added the
pflow visualizecommand to generate Mermaid flowcharts of workflow topologies. - Unified diagnostic rendering into a single, structured format with self-describing exceptions for both CLI text and JSON outputs.
- Added recursive sub-workflow validation at parse time to catch structural errors, unknown node types, and missing required inputs before execution.
- Added a 120-second default timeout to LLM nodes to prevent workflows from hanging indefinitely on stalled API calls.
- LLM nodes now catch
JSONDecodeErrorwhenoutput_schemafails, preserving the raw text in the response and returning a soft error. - Improved the markdown parser to detect orphaned content, duplicate section headings, and provide actionable errors for unquoted colons in YAML parameters.
- Fixed a bug where type annotations in Python code YAML inputs (e.g.,
text: str = ${ref}) were incorrectly parsed as literal values. - Unified output auto-detection across CLI, JSON, and MCP interfaces.
- Added a CLI hint suggesting
pflow mcp syncwhen a registry search returns no results but matching MCP servers exist. - Fixed an issue where the registry cache would not refresh after a package upgrade.
- Fixed issues with template deduplication, double validation, raw string parsing in single-line YAML, and bash syntax correctness.
- Fixed missing error details in JSON output, dead code in error display paths, and redundant template resolution.
Under the hood
This release includes a major structural overhaul: 18,000 lines of production code removed across 16 refactoring PRs. The PocketFlow framework was replaced with a standalone orchestration engine, the exception hierarchy was consolidated under a single base class, and the CLI, compiler, and runtime were each decomposed into focused modules. These changes don’t add features directly — they’re what made the compile-once optimization, unified diagnostics, and shared execution pipeline possible.Breaking changes
Breaking changes
Workflow save format
Workflows are now saved as folders (~/.pflow/workflows/{name}/{name}.pflow.md), not flat files. This change enables proper file dependency bundling but will break existing symlinks for published skills.Unknown parameters block execution
Unknown parameter detection was promoted from non-blocking warnings to blocking validation errors to catch typos early. Typos like- path: instead of - file_path: will now prevent execution.Unified JSON error shape
All error paths in the CLI now produce a single, unified JSON shape.Batch error handling
- Batch nodes now abort with a
RuntimeErrorwhen all items fail anderror_handling: continueis set, rather than returning garbage data. - Batch nodes no longer swallow compilation errors under
continuemode. - When
continuemode recovers from partial failures, it now returns a"default"action and sets aDEGRADEDstatus instead of returning an"error"action that halts the workflow. - Sub-workflow error actions and permissive batch template errors are now properly propagated and detected in batch processing.
Removal of internal nodes
The experimentalgit, github, test, and echo nodes have been completely removed from the registry and documentation.Workflow termination
The engine now recognizes"end" and error-only successors as intentional workflow terminations rather than validation failures.Trace format and LLM calls
The parallel__llm_calls__ accumulator was removed. Trace events are now the single source of truth for LLM costs. Trace format has been bumped to 2.0.0, removing all value truncation and replacing full-store snapshots (shared_before/shared_after) with focused per-node parameters.Branch convergence
Workflows now support branch convergence. When downstream nodes need to reference “whichever branch ran” after a conditional split, you can use the new coalesce operator (??) or optional inputs in code nodes to handle skipped branches.- Added the
??coalesce operator for template syntax (${a.stdout ?? b.stdout}). The resolver tries each operand left-to-right and skips branches that did not execute. - Coalesce is supported in all template contexts: inline strings, shell commands, LLM prompts, input dicts, workflow output sources, and batch items.
- Python code nodes now accept
Optional[T]orT | Noneinput annotations. If the source branch didn’t execute,Noneis injected automatically instead of raising a runtime error.
Nested workflows
Workflow nodes now look and behave like every other node type. You pass parameters as regular inputs, and child outputs are exposed via the standard namespace system.Child workflow inputs are validated before execution starts. If you miss a required input or provide the wrong parameter name, the parent workflow fails immediately with an error listing the child’s declared inputs.
- Unified
workflowparameter handles both file paths and saved workflow names. - Non-reserved parameters become child inputs.
- If the child workflow declares
## Outputs, they are exposed to the parent via standard dot notation (${node_id.output_name}). - Fixed relative path resolution so
./child.pflow.mdalways resolves from the parent workflow’s directory, even across deep nesting levels. - The template validator now statically resolves child workflow outputs to catch typos during compilation.
LLM reasoning and cost tracking
You can now control reasoning and thinking depth across all LLM providers using a unified interface. pflow translates your settings to the provider-specific parameters — Anthropic’sthinking_budget, OpenAI’s reasoning_effort, Gemini’s thinking config.- Added
reasoning_effort(xhigh, high, medium, low, minimal, none) andreasoning_max_tokens(direct token budget) to the LLM node. - Added a
model_optionsparameter to the LLM node as an escape hatch for provider-specific fields. - Unified LLM cost access:
${node.llm_usage.cost_usd}now works in workflow templates for both standard LLM and Claude Code nodes. - LLM costs are computed at execution time, making
cost_usdavailable in the shared store immediately after each node runs. - The Claude Code node’s redundant
_claude_metadataoutput was removed; all metadata is consolidated intollm_usage.
Validation and execution robustness
Several compile-time and runtime edge cases around batch processing, validation depth, and parallel execution have been fixed.Highlights- The template validator now infers the internal structure of batch items based on the upstream batch source, catching invalid
${item.field}references at compile time with “did you mean?” suggestions. - Validation now recurses into nested dictionaries and lists (such as the
inputsdict on code nodes) to catch typos and non-existent forward references. - Required workflow inputs now strictly fail validation when provided as empty strings.
- Batch nodes now return an “error” action on partial failures when
error_handling: continueis set, enabling properon-errorrouting for partial batch failures. - Fixed a bug where the validator blocked batch processing entirely on nested workflow nodes.
- Resolved a
_thread.RLockpickle error that caused parallel batch processing to crash at runtime.
- Added
--timeoutand--sse-timeoutflags topflow mcp addso custom timeout values are preserved in config files.
Breaking changes
Breaking changes
Removal of planning module and repair system
The built-in natural language planning module and auto-repair systems have been removed (~40,000 lines of code). AI agents handle planning directly — pflow provides the runtime, validation, and execution primitives they compose.- Removed CLI flags:
--trace-planner,--planner-timeout,--planner-model,--auto-repair,--cache-planner,--save/--no-save,--no-update, and--generate-metadata. - Component and workflow discovery features have been preserved as plain functions for agents to query available resources.
Nested workflow API
- The
workflow_refandworkflow_nameparameters have been consolidated into a singleworkflowparameter. param_mappingandoutput_mappinghave been removed entirely. Pass arguments directly as inputs, and access outputs via standard dot notation.isolatedandscopedstorage modes have been removed.
Unresolvable output errors
When a workflow output source references a node that didn’t execute (e.g., a branch not taken) and no?? coalesce operator is used, it now raises an OutputResolutionError with a precise diagnostic message. Previously, these unresolvable outputs were silently dropped, causing confusing downstream failures in nested workflows.Removed registry run timeout flag
The--timeout flag on the pflow registry run command has been removed as it was redundant. Timeouts can be passed directly as a per-node parameter (e.g., timeout=30).Conditional branching and loops
Workflows now support conditional routing. You can branch based on errors, make data-driven routing decisions in Python code nodes, and create retry loops directly in your.pflow.md files.To prevent infinite loops, an automatic loop guard tracks node visits and raises a
MaxNodeVisitsError if a single node is executed 100 times (configurable via PFLOW_MAX_NODE_VISITS).- Added
- next:,- on-error:, and- next: endsyntax for static and error routing. - Python code nodes support a
nextvariable for dynamic, data-driven routing. - Caching is now automatically invalidated when a node is revisited in a loop, ensuring exit conditions are correctly re-evaluated.
flow.run()is now always wrapped to ensure visit counts reset correctly between executions.- Topological sorting now uses position-based edge filtering to allow valid data dependencies while preventing cycle errors on backward loop edges.
Guaranteed structured JSON
The LLM node now accepts anoutput_schema parameter for guaranteed structured JSON responses. It uses the constrained decoding APIs of model providers (Anthropic, Gemini, OpenAI) instead of prompting for JSON and hoping the model complies.yaml output_schemacode blocks pass JSON Schema dicts directly to thellmlibrary.- The API response is parsed and stored as a
dict, avoiding downstream string parsing. - Code block stripping is safely skipped when a schema is set, since the API returns clean JSON.
Stateful MCP servers and error reporting
MCP servers are no longer restarted for every node in a workflow. A background event loop now acts as a connection pool, keeping server sessions alive across workflow steps. This fixes silent failures where stateful servers (like Playwright browsers or database clients) lost all state between step executions.Highlights- Persistent connection pool keeps both
stdioandhttpMCP sessions alive across nodes. - Automatic crash recovery evicts and retries sessions once if a transport error (like a broken pipe) occurs.
- MCP error reporting now un-wraps internal
ExceptionGrouptask failures to show the actual HTTP error (e.g., “Authentication failed” instead of a raw 40-line traceback). - Fixed a logging bug that prepended “MCP tool failed:” twice.
- Node output formatter correctly detects
errorkeys so MCP failures show as “failed” instead of “succeeded”.
Breaking changes
Breaking changes
Explicit branch target routing
Nodes reached via explicit routing (branch targets) used to silently fall through to the next node in document order. This silent, input-dependent bug has been fixed via parse-time validation. Any node targeted by an action edge must now explicitly declare its next step.Dynamic routing validation
If a Python code node assigns a variable tonext (e.g., next = target_var instead of a literal "node-id"), you must explicitly declare - next: in the markdown step parameters so the parser can build the execution graph.ReadFile outputs raw content
TheReadFile node previously prepended line numbers (N: ) unconditionally to every line it read. This corrupted file content for downstream LLM prompts, templates, and configurations. It has been completely removed; the node now returns raw, unmodified file content.Python code node results
Theresult output variable is now optional in Python code nodes as long as next is declared.First public release on PyPI. pflow is a CLI workflow engine — AI agents
write Highlights
View the full v0.8.0 changelog with PR references on GitHub →
.pflow.md files that chain shell commands, LLM calls, HTTP requests,
and Python code through a shared data store. Workflows run the same way
every time, without burning tokens on repeated tool calls.Agent skills
You can now publish workflows as native skills for AI agents. Thepflow skill
command symlinks your saved workflows to the configuration directories for
Claude Code, Cursor, GitHub Copilot, and Codex.pflow skill saveenriches workflows with usage sections and metadata for the agent.- Support for multiple targets:
--cursor,--copilot,--codex, and--personal. pflow workflow historyshows execution stats and last-used inputs.- Improved discovery matching by including input names and node IDs in the context.
Data integrity
LLM nodes no longer discard prose when extracting JSON. Previously, if a response contained a JSON block, the node threw away the surrounding text. Now, the full response is stored as a string, and JSON parsing happens on-demand via the template system.Highlights- LLM nodes preserve prose explanations alongside code blocks.
- JSON fields are still accessible via dot notation:
${node.response.field}. - Numeric strings (like Discord IDs) declared as
type: stringare no longer coerced to integers. - Batch node error messages now correctly list available outputs for inner items.
- Workflow frontmatter tracks average execution duration for performance monitoring.
Developer experience
Runtime errors in Code nodes now point to the exact line number in your.pflow.md file, rather than the temporary Python script. We also improved
environment variable handling in MCP configurations to support dynamic URLs.Highlights- Code node errors show
LocationandSourcefields with correct line mapping. - MCP server configs now expand environment variables in URLs and
settings.json. - Markdown parser specifically detects and explains nested backtick errors.
Package name
Package name
The PyPI package is
pflow-cli, not pflow (that name was already taken).
This is the first PyPI release — if you installed from git before, switch to:Workflows are documentation
Workflows have moved from JSON to a custom Markdown format (.pflow.md). The
file is the documentation — H1 headers become titles, prose becomes descriptions,
and code blocks define execution logic. Comments and formatting are preserved
when saving, so your notes survive round-trips through the CLI.The internal parser produces the exact same IR structure as before, so
execution logic is unchanged. The migration is purely about authoring
experience and LLM readability.
- New
.pflow.mdextension with YAML frontmatter for metadata. - Line-by-line error reporting with context, replacing JSON syntax errors.
- “Save” operations update the file in place, preserving your comments.
pflow workflow saveextracts the description directly from the document prose.
Native Python execution
The newcode node runs Python in-process, passing native objects (lists,
dicts) between steps without serialization overhead. Unlike the shell node,
it doesn’t need jq to parse inputs — inputs are injected directly as local
variables.- Zero-overhead data passing for heavy transformations.
- Required type annotations catch type mismatches before execution.
stdout/stderrcapture for debugging, with configurable timeouts.
Unix piping and validation
You can now chain workflows using standard Unix pipes. Mark an input withstdin: true, and pflow will route piped data to that specific parameter.
Validation has also been unified: the checks that run during --validate-only
now run before every execution, catching errors like invalid JSON string
templates before any steps run.stdin: trueinput property for explicit pipe routing.- FIFO detection prevents hangs when no input is piped.
- Unified validation logic ensures
--validate-onlymatches runtime behavior. - Improved error messages for unknown node types (no more stack traces).
disallowed_toolsparameter on Claude Code nodes to block specific tools in agentic workflows.- Fixed nested template validation for
${item.field}inside array brackets.
Breaking changes
Breaking changes
Workflow format
JSON workflow files (.json) are no longer supported. Existing workflows
must be converted to the .pflow.md format. The CLI will reject JSON files
with a migration error.Stdin handling
The${stdin} shared store variable has been removed. You must now explicitly
mark an input parameter to receive piped data.CLI changes
pflow workflow saveno longer accepts--description. It extracts the description from the Markdown content (text after the H1 header).- Metadata is now stored in YAML frontmatter rather than a
rich_metadatawrapper.
Batch processing
Need to classify 50 commits with an LLM, or fetch 200 URLs? Add abatch
config to any node and pflow handles the fan-out. Works with every node
type — LLM, shell, HTTP, MCP, all of them.- Sequential and parallel execution with configurable concurrency (
max_concurrent). error_handling: continuekeeps going when individual items fail — you get partial results instead of nothing.- Progress indicators in the CLI so you can see where a 200-item batch is at.
- Access results with
${node.results}, individual items with${node.results[0].response}.
Smarter templates
Template variables like${node.stdout.items[0].name} now parse JSON
automatically. If a shell command outputs a JSON string, you can access
nested fields directly — no more jq extraction steps between every shell
node and the thing that consumes it.Highlights${node.stdout.field}resolves through JSON strings without an intermediate node.- Inline object templates preserve types correctly — no more double-serialization when passing dicts.
- Dicts and lists auto-coerce to JSON strings when mapped to string-typed parameters.
- Optional inputs without defaults resolve correctly instead of erroring.
Before and after
Before and after
Previously you needed an extraction step between a shell command and
anything that wanted its output as structured data:
Shell node fixes
Shell nodes now surfacestderr even when the exit code is zero. Tools
like curl and ffmpeg write diagnostics to stderr on success, and those
warnings were getting lost.Highlightsstderrvisible on successful commands, not just failures.- Trailing newlines stripped from
stdoutby default (disable withstrip_newline: false). - Pipeline-aware error detection for
grep | sedchains where only the last exit code was visible. - Fixed
SIGPIPEcrashes when a subprocess closed its input early.
Breaking changes
Breaking changes
Explicit data wiring
Nodes can no longer silently read from the shared store by key name. All data must be wired through${variable} templates. This prevents a class
of bugs where a node ID collided with a parameter name and got the wrong
value.Claude Code node
task→promptworking_directory→cwdcontextremoved — include it directly in the prompt
Validation that helps you fix things
When something goes wrong, pflow now tells the agent exactly what to do instead of printing a stack trace. Wrong template path? It shows every available output with its type and suggests the correct one.Validation runs automatically before every execution — no separate step
needed. The
--validate-only flag lets agents check a workflow without
running it.- Template references checked against actual node outputs before execution starts.
- “Did you mean?” suggestions for misspelled node names and output paths.
- Type mismatch warnings when connecting incompatible outputs to inputs.
--validate-onlyflag for CI pipelines and agent pre-checks.
Agent tooling
The CLI now has discovery commands so agents can find the right building blocks without knowing what’s available ahead of time.registry discover
takes a natural language description and returns matching nodes.Highlightspflow registry discover "fetch API data and send to Slack"returns matching nodes ranked by relevance.pflow registry run node-type param=valuetests individual nodes outside of a workflow — output is pre-filtered for agents, showing structure without data.pflow instructions usagegives agents a complete guide to pflow’s commands and patterns.- Allow/deny filtering via
pflow settingsto control which nodes are available.
Example: agent discovery flow
Example: agent discovery flow
MCP server improvements
Connecting external tools got more reliable. Server configs now expand environment variables everywhere (URLs, headers, auth fields), and sync only runs when something actually changed.Highlights- Environment variables expanded in all MCP config fields, not just API keys.
- Smart sync skips re-scanning when server configs haven’t changed (~500ms saved on warm starts).
- HTTP transport support for remote MCP servers alongside stdio.
- Better error messages when MCP servers fail to start or authenticate.
Workflow engine
Write a.pflow.md file, run it from the terminal. Steps execute top to
bottom, data flows between them through template variables. Save it with
pflow workflow save and it becomes a command you can run from anywhere.- Run from file path (
pflow workflow.pflow.md) or by name (pflow my-workflow). - Templates reach into nested objects and arrays —
${node.result.data.users[0].email}. - Execution traces saved to
~/.pflow/debug/with per-node inputs, outputs, and timing. - Pipe workflows together:
pflow -p workflow-a | pflow -p workflow-b.
Built-in nodes
Eight node types that cover the common building blocks. MCP bridges to anything else — GitHub, Slack, databases, whatever has an MCP server.Highlightsshell— run commands with dangerous-pattern blocking and timeouts.code— inline Python with native object passing (no serialization overhead).llm— any model via Simon Willison’s llm library, with token tracking.http— all methods, auth, request bodies, automatic JSON parsing.file— read, write, copy, move, delete.mcp— bridge to any MCP server over stdio or HTTP transport.agent— delegate agentic subtasks to Claude Code or Codex.git/github— common operations without shell scripting.
MCP server
pflow itself runs as an MCP server, so agents in Claude Desktop, Cursor, or any MCP-compatible environment can build and run workflows programmatically.Highlights- 11 tools covering workflow execution, node discovery, and registry inspection.
- Structure-only output mode — agents see schema types without actual data, keeping context windows small.
- Works alongside CLI usage. Same workflows, same registry, different interface.
Quick start
Quick start
1
Install pflow
2
Set up an LLM provider
3
Run your first workflow
pflow instructions usage — it gets
everything it needs to discover, build, and run workflows.What's next
What's next
Batch processing for fan-out patterns, smarter template resolution, and
shell node reliability improvements. See the Roadmap.

