bash and python_exec node types let you mix code execution with LLM calls in the same DAG, with stdout becoming the node’s artifact that downstream nodes can reference just like any agent output.
How exec nodes fit into a DAG
Exec nodes follow the same dependency model as agent nodes. Their output (stdout) is stored as an artifact and referenced by downstream nodes via{{ node_id }}. A non-zero exit code fails the node and halts any downstream nodes that depend on it.
The code_and_llm.yaml example collects system information with bash, parses it with Python, then summarizes it with an LLM:
Any DAG that contains
bash or python_exec nodes requires the --sandbox flag. Without it, dagraph refuses to run the DAG to prevent accidental code execution.The bash node
Use bash to run shell commands. The command field is a Jinja template — you can interpolate DAG inputs and upstream node outputs just like in an agent prompt.
| Field | Default | Description |
|---|---|---|
command | required | Shell command, Jinja-rendered against inputs and dep outputs |
timeout_seconds | 300 | Fail the node if execution takes longer |
env | {} | Additional environment variables for the process |
image | null | Docker image to use (docker sandbox only) |
max_output_bytes | 1,000,000 | Truncate stdout beyond this limit |
The python_exec node
Use python_exec to run Python code inline. The code field is also Jinja-rendered, which means curly braces in Python code (f-strings, dict literals, format strings) need to be wrapped in {% raw %}...{% endraw %} to prevent Jinja from interpreting them:
{% raw %}, Jinja sees {{ collect | tojson }} as a template expression (which is correct), but it also tries to interpret {k: v for k, v in parsed.items()} as a template block and fails.
Sandbox backends
dagraph supports two sandbox backends, selected via--sandbox:
- inprocess (subprocess)
- docker (container)
Runs the command or script as a child process of the dagraph scheduler. Fast and simple — no Docker required.Use
inprocess when you own the code being executed — your own scripts, trusted utilities, or commands you’ve written yourself.Output size limit
Bothbash and python_exec nodes default to a 1 MB stdout limit. If a node’s output exceeds max_output_bytes, dagraph truncates it and fails the node with an error. Override the limit per node if you expect large outputs:
Passing exec output to an LLM
Exec node output is available in downstream agent prompts via{{ node_id }} — exactly like any other node:
Parallel agents
Run exec nodes and agent nodes in parallel waves across the same DAG.
Multi-provider fallback
Add fallback chains to the agent nodes downstream of your exec steps.