v0.21.0
v0.21.0
Released 2026-04-10
Two things in this release. PyO3 was bumped from 0.27 to 0.28, which required touching every #[pyclass] in the codebase to opt into the new FromPyObject model. And potato-spec now supports loading task prompts from files — the prompt field in a TaskSpec accepts either an inline string or a { path: "..." } map.
Breaking changes
PyO3 0.28: FromPyObject no longer auto-derived for #[pyclass] types
PyO3 0.28 removed the implicit FromPyObject impl for #[pyclass] structs and enums. Every type that needs to cross the Python→Rust boundary now requires an explicit from_py_object attribute. Types that are output-only (passed Rust→Python but never back) use skip_from_py_object.
This does not change the Python API. If you're consuming potato_head from Python, nothing breaks. If you have downstream Rust code that wraps or re-exports #[pyclass] types from this crate, you need PyO3 0.28 to compile.
TaskSpec.prompt is now PromptRef, not String
The prompt field on TaskSpec changed type from String to a PromptRef enum. Inline specs are backward-compatible at the YAML level — prompt: "some text" still deserializes correctly. If you're constructing TaskSpec values directly in Rust code, the field type changed and your code will not compile without updating.
What's new
File-based prompts in potato-spec
TaskSpec.prompt now accepts a { path: "..." } map in addition to an inline string. When a path is provided, the loader reads the YAML file at that location and constructs the Prompt from it — model, provider, and messages all come from the file rather than the task spec.
# Before: inline only
tasks:
- id: t1
agent: worker
prompt: "Summarize the input."
# After: file reference also works
tasks:
- id: t1
agent: worker
prompt:
path: "./prompts/summarize.yaml"The prompt file format:
model: gpt-4o
provider: OpenAI
messages:
- "Summarize the input."One concrete consequence: agents with no model_override in the spec can now run DAG tasks, as long as the prompt file specifies the model. Previously, a missing model would produce a SpecError::WorkflowBuild at load time. A file prompt that omits both model and provider will still fail — the error is SpecError::PromptLoad.
Paths are resolved relative to where they appear in the YAML at load time, not the working directory. Dotdot components (../) are allowed. Absolute paths work as-is.
PyO3 types now bidirectionally usable from Python
The from_py_object annotations added throughout potato-type, potato-agent, potato-provider, potato-util, and potato-workflow mean that any type annotated this way can now be passed back into a Rust function from Python. Before this release, many types were Rust→Python only. Output-only types (WorkflowResult, PyWorkflow, PyAgentResponse, AnthropicUsage) are marked skip_from_py_object and remain one-directional.
Upgrading from v0.20.0
- Update your PyO3 dependency to
0.28.*if you have downstream Rust crates that depend onpotato-typeor otherpotatoheadcrates directly. - If you construct
TaskSpecin Rust: changeprompt: String→prompt: PromptRef::Inline(...)orPromptRef::File(...). - YAML specs using inline
prompt: "..."strings require no changes.
Contributors
Full changelog: v0.20.0...v0.21.0