Skip to content

Tool Flows

A tool flow lets the model run several tool calls inside one short Python-subset script. When one call’s result feeds the next call’s arguments, a normal conversation needs a round trip per call: the model requests a tool, waits for the result, then requests the next tool. A tool flow collapses that sequence into a single tool_flow call. The model writes the script, Polytoken runs it against the tools you approved, and Polytoken returns the flow’s result in a single response.

A tool flow fits work whose sequence the model already knows: read a file, search its contents, fetch a page named in the results, then combine everything. The model decides the logic up front and the script carries it out without further model involvement.

Independent calls that share nothing do not need a flow. The model can batch those in one turn already, and a flow would only add a script between the model and its tools.

A tool_flow call carries the code, a name for the flow, and the list of tools the script may call. Two optional settings tune the run: timeout_seconds (twenty minutes by default) and background.

readme = file_read(path="README.md")
hits = grep(pattern="tool_flow", path="rs")
print(hits["text"][:200])
{"readme": readme["text"][:200], "matches": hits["text"]}

Each requested tool becomes a function in the script. Polytoken wraps plain-text tool output in an object with a text field and parses JSON tool output into data. The example indexes readme["text"] to work with the file content as a string. Polytoken uses the registry name when it is a valid Python identifier and otherwise creates a valid, unique alias. Call tools with keyword arguments, use print() for diagnostic output, and leave the value you want returned as the trailing expression. That final expression becomes the flow’s result. The Python subset provides access only through the approved tools: it does not offer direct filesystem, shell, network, or process-spawning APIs.

A finished flow returns a JSON envelope with six fields:

  • status: the script outcome (ok or error).
  • prints: captured output from print().
  • result: the value of the script’s trailing expression.
  • calls: a log of the tool calls the script made.
  • stats: the call count, print-output bytes, and execution time.
  • truncation: a marker that reports whether Polytoken shortened output.

Polytoken shortens large output so the envelope fits the conversation. If the envelope still overflows, Polytoken returns only status and truncation. The truncation marker reports trimmed prints, a shortened result, or omitted call-log entries. Each entry in calls keeps only the tail of a long result, but that shortening does not set the marker. Polytoken keeps the fuller content in the expanded tool card.

Polytoken requests approval for a flow’s exact script and tool set before starting the flow. That approval never applies to a later flow with different code or different tools.

Nested calls follow the active permission mode. In standard and autonomous modes, deny rules and hard secret-protection denies produce catchable errors inside the script. The flow’s approval satisfies secret-file reads that would otherwise require your approval, while Polytoken still filters search results that would surface a secret. Bypass skips permission rules and secret protections. Bypass+ retains explicit deny rules but skips secret protections. A .agentblock entry blocks nested file access in every mode and produces a catchable error. Nested calls never pause the flow for further approval prompts.

A flow can call only the tools named in its tools list. Eligible built-in tools opt in explicitly: the file reading, file searching, web fetching, web searching, and decision tools today. MCP tools are eligible unless daemon.tool_flow.mcp_tools_deny denies them; each deny entry is a shell-style glob such as mcp__github__*. Shell, planning, subagent, todo, and facet tools are never callable from a flow, and a flow cannot call tool_flow itself. Polytoken validates the whole tools list before running the script and rejects the flow call if the list contains a missing, ineligible, or denied tool. These validation failures do not become errors inside the script.

daemon.tool_flow.max_timeout_seconds caps a flow’s time budget. The daemon.tool_flow.max_calls setting limits how many tool calls one flow may make.

Set background: true to run a flow in the background, or press Ctrl+B while it runs in the foreground. Polytoken returns a job handle immediately, named after your flow, and the flow keeps running while you continue the conversation. Use the standard job controls to inspect, retrieve, or cancel the flow, like any other background job.