Skip to main content
Agent commands. Your AI agent uses this node in workflows. You don’t configure it directly.
The code node runs Python in-process with direct access to input data as native objects. Use it when the logic is deterministic — filtering, reshaping, merging, computing values. If you can write a Python expression for it, there’s no reason to burn tokens on an LLM call.

Parameters

ParameterTypeRequiredDefaultDescription
codestrYes-Python code with type-annotated inputs and a result variable
inputsdictNo{}Variable name to value mapping (template variables go here)
timeoutintNo30Maximum execution time in seconds
requireslistNo[]Package dependencies (documentation-only, not enforced)

Output

KeyTypeDescription
resultanyValue of the result variable after execution
stdoutstrCaptured print() output
stderrstrCaptured stderr output
errorstrError message (only on failure)

Type annotations

Every input variable and the result variable must have a type annotation. pflow uses these to validate inputs before your code runs — so a wrong type gets caught immediately with a fix suggestion, not as a cryptic Python error mid-workflow.
data: list            # required for every input
limit: int            # required for every input
result: dict = {}     # required on result too
Use object as the type when you don’t know or care what the input type is — it skips validation entirely.
AnnotationPython typeNotes
intint
floatint, floatIntegers are accepted where float is declared
strstr
boolbool
listlistGeneric params like list[dict] check outer type only
dictdictGeneric params like dict[str, Any] check outer type only
setset
tupletuple
bytesbytes
objectSkips type validation entirely
Only the outer type is checked — list[dict] validates that the value is a list, but doesn’t check whether the elements are dicts.

Template placement

Templates go in inputs, never in the code block. The code block is literal Python — ${var} isn’t valid Python syntax, so putting templates there causes a parse error.
### transform

Filter active users from the API response.

- type: code
- inputs:
    data: ${fetch.response}

```python code
data: list

result: list = [u for u in data if u['active']]
```
Templates in the inputs dict get resolved before your code runs. By the time Python sees data, it’s already a native object — no parsing needed.

Inputs are native objects

Upstream JSON is auto-parsed before your code runs. If the source node produced a JSON string, declare dict or list, not str — you get real Python objects, not strings.
Upstream outputDeclare asYou get
JSON string '{"a": 1}'dict{"a": 1}
JSON array '[1, 2, 3]'list[1, 2, 3]
Plain textstrThe text string
Numberint or floatThe number

Examples

Simple transformation

### filter-active

Filter users to only active accounts.

- type: code
- inputs:
    users: ${fetch-users.response.data}

```python code
users: list

result: list = [u for u in users if u['status'] == 'active']
```

Multiple inputs

### merge-sources

Combine data from two upstream nodes.

- type: code
- inputs:
    api_data: ${fetch-api.response}
    db_records: ${query-db.result}

```python code
api_data: list
db_records: list

merged = api_data + db_records
result: dict = {
    'items': merged,
    'count': len(merged),
}
```
Access fields downstream: ${merge-sources.result.items}, ${merge-sources.result.count}.

No inputs

### generate-range

Generate a sequence with no external inputs.

- type: code

```python code
result: list = list(range(1, 11))
```

Using subprocess

### get-git-log

Fetch recent git history.

- type: code
- timeout: 60

```python code
import subprocess

output = subprocess.run(
    ['git', 'log', '--oneline', '-10'],
    capture_output=True, text=True, check=True
).stdout
result: str = output.strip()
```

Imports

Standard library imports work without restrictions — json, re, subprocess, pathlib, datetime. Third-party packages work too, but they need to be installed in pflow’s environment.
pflow runs in an isolated environment, so pip install pandas won’t work. How you add packages depends on how you installed pflow:pipx (simpler — additive, doesn’t touch existing packages):
pipx inject pflow-cli pandas
uv tool (replaces the full environment — list existing extras first):
# Check what's already installed so you don't lose it
uv tool list --show-with

# Include ALL extras — both new and existing
uv tool install --with pandas --with llm-openrouter pflow-cli
uv tool install is not additive — it recreates pflow’s environment from scratch. If you previously installed with --with llm-openrouter and now run --with pandas alone, you’ll lose llm-openrouter. Always run uv tool list --show-with first and include all existing --with flags.
A simpler way to manage code node dependencies is coming in a future release.
### parse-dates

Parse and sort date strings.

- type: code
- inputs:
    raw_dates: ${fetch.response.dates}

```python code
from datetime import datetime

raw_dates: list

parsed = [datetime.fromisoformat(d) for d in raw_dates]
parsed.sort()
result: list = [d.isoformat() for d in parsed]
```

Security

Code runs directly in the pflow process via exec() without sandboxing. It has full access to your filesystem, network, and standard library — same as running a Python script yourself. Sandboxed execution is planned for a future release.
You’re in control. Your agent asks before running workflows, and you can open any .pflow.md file to see exactly what code will run. To disable this node entirely: pflow settings deny code.

Error handling

Errors include line numbers, the actual source line, and a suggestion for how to fix it. For example, a type mismatch looks like:
Input 'data' expects list but received dict

Suggestions:
  - Change the type annotation to: data: dict
  - Or convert the input value to list
ErrorCauseWhat you see
Missing annotationInput or result has no type annotationWhich variable needs an annotation
Type mismatchInput value doesn’t match declared typeExpected vs actual type, with fix suggestion
NameErrorUndefined variableVariable name, suggestion to add to inputs
ImportErrorModule not installedModule name, install command
TimeoutCode exceeded time limitCurrent timeout, suggestion to increase
SyntaxErrorInvalid PythonLine number from Python parser
Runtime errorAny other exceptionException type, line number, source line
The node doesn’t retry — code execution is deterministic, so retrying the same code produces the same result.