Agent Workflows

Agent Workflows

Workflow UI is enabled by default. Start Prowl with PROWL_WORKFLOW_UI=0 to hide its UI and skill row; CLI workflow and skill commands remain available. The switch is read at process startup.

Multi-step, multi-agent orchestrations that Prowl runs and supervises for you: a workflow bundle declares the roles (the pane you start from, an agent Prowl launches, an agent you pick) and the steps (message a role, launch one, loop until a verdict, notify, close); Prowl types the instructions into the right panes, waits for each delivery, and shows the run in the toolbar. This page covers the feature end to end — files, entry points, the start sheet, the run panel, and Settings → Agents → Workflows. For the CLI commands and their JSON, see cli.md; to write or debug a workflow, an agent should load the bundled prowl-workflow skill.

Keywords:workflowworkflowsagent workfloworchestrationmulti-agentadversarial reviewrolesstepstyped statewhileifaction bundleverdictyamlprowl.workflow/v1start sheetrun workflowbindingsdon’t ask againworkflow statusrun panelneeds attentionnudgeskip stepcancel runworkflow-runssettings workflowsnew workflowcreate with agentrun historyclear historydelete run

What it is#

A workflow bundle scripts several live agents: who takes part and what happens in order. Prowl executes it — every participant is a real terminal pane you can watch — and agents take part only through the prowl CLI, so any runtime Prowl recognizes can play any role. A typical workflow: the pane you are working in writes a brief, Prowl launches a reviewer beside it from an Agent Profile, the reviewer reports findings with a verdict, and the two loop until the verdict is clean or the round cap is hit.

A .pwlworkflow directory contains workflow.yaml with schema: prowl.workflow/v1, and optional local script actions and assets. Workflow definitions are loaded from bundle directories. Roles have a source:

sourceMeaningHow it is chosen
currentthe pane the run was started fromthe pane you start from (or pick in the sheet)
launcha new agent Prowl starts from an Agent Profileremembered profile → profile matching the role’s suggest → the repository’s Recommended profile → the sheet asks
pickan existing detected agent pane in the same worktreealways chosen at start

For a launch role, omit agents by default to allow any qualifying Agent Profile. Only add a runtime allow-list for an explicit user requirement or a concrete runtime-specific capability. agents: [] allows none; any and * are not wildcard tokens. Leave suggest unset unless there is a specific preference to express; profile selection normally belongs to the user’s saved preferences and the start-sheet picker.

Steps are message (send a prompt to an idle role), launch (start a launch role with a kickoff prompt), set, nested if/else, while, break/continue, action (built-in or local script), notify, and close. A message or launch step may expect an output: the role finishes by running the exact prowl workflow deliver … command Prowl typed into its pane, with the body on stdin. The full DSL, validator rules, and authoring patterns are the prowl-workflow skill’s job (prowl skills install prowl-workflow); prowl workflow schema prints the workflow JSON Schema; prowl workflow schema --action prints the action manifest schema.

Where workflow files live#

Three sources, later ones winning for the same id:

SourceLocationNotes
Built-inProwl.app/Contents/Resources/workflows/ids prowl.* are reserved for it. Ships Handoff (prowl.handoff) and Review Loop (prowl.review-loop).
Your workflows~/.prowl/workflows/*.pwlworkflowpersonal; not tied to a repository
Repository<repo root>/.prowl/workflows/*.pwlworkflowtravels with the repo; seen only from that repository’s worktrees

A file that fails validation is never offered for a run; a file with the same id in two sources is offered once (the repository file wins over yours). A workflow is enabled by default; switch it off in Settings (below) to hide it from every entry point and refuse prowl workflow run for it.

Built-in Review Loop#

Review Loop (prowl.review-loop) reviews changes with another agent, addresses findings, and repeats. Start it from the agent that implemented the task:

prowl workflow run prowl.review-loop --role reviewer="Pi Reviewer" \
  --input min_rounds=2 --input max_rounds=4 --json

The reviewer Profile is selectable; no model or runtime is required. Prowl opens it in a right split beside the initiating agent, in the same tab, and reuses it across rounds. The initiating agent follows the returned self_initiated.line to deliver its scope, plan, and verification brief. Local changes and existing PRs are both supported. focus adds an optional single-line review instruction.

Each round includes a reviewer report and main’s disposition. Review focuses on material correctness, plan gaps, architecture, and realistic UX regressions. Every report records which files or areas the reviewer inspected. From round 2 on, the reviewer both re-verifies carried-over findings against main’s disposition and performs a fresh review of the current diff, including code added by fixes and areas earlier rounds did not inspect; new findings get new IDs. Main verifies findings, fixes worthwhile problems with regression tests where practical, and explains rejected or deferred findings. Main owns commits, pushes, and existing PR updates unless it explicitly delegates them; task restrictions still apply. The reviewer may run useful tests and otherwise leaves shared files unchanged. The workflow does not create a PR merely because it ran.

min_rounds defaults to 2, and max_rounds to 4 (each accepts 1–30). A contradictory range requests attention before reviewer launch; cancel and restart with corrected inputs. An early clean report still receives the required minimum rounds. Early exit requires both a clean reviewer report and no subsequent in-scope changes or pending follow-up from main. At the maximum, main still addresses the final findings, then summarizes unresolved issues and final fixes that have not been reviewed again.

A Completed run means the review procedure finished, not necessarily that the changes are clean. The final notification and summary state clean or not clean. Execution history retains the brief, reports, dispositions, and summary under the normal retention policy. The reviewer pane stays open. Neither agent should send its own dispatch messages or extend the loop beyond the configured maximum.

Starting a workflow#

Every start — GUI or CLI — goes through the same admission, so behavior is identical:

  • Command Palette (⌘P) → Run Workflow: — one row per runnable workflow visible to the selected worktree. → command-palette
  • Toolbar Agents capsule → the Run a workflow section — each row uses the workflow’s YAML icon and starts the workflow. Its trailing ellipsis.circle menu offers Run with Options… (which forces the start sheet) and Show Details in Settings…. Files that fail validation remain dimmed with their reason and still link to their Settings detail. Manage Workflows… opens Settings → Agents → Workflows, even when no workflows are listed. → agent-profiles
  • Active Agents → right-click a row → Run Workflow ▸ — starts it with that pane fixed as the current role’s source. → active-agents
  • CLIprowl workflow run <id|name> [source] [--role r=…] [--input k=v] [--skip step]. → cli

The start sheet#

The sheet explains the workflow and collects what the run needs before it exists. Its header shows the workflow’s icon, name, description, and the target worktree; the body is arranged in sections like the Workflow History panel:

  • Roles — one label/control row per role, laid out like a Settings form: the role’s name on the left with a small icon for the kind of pane that serves it (terminal = the pane you start from, plus = an agent Prowl launches, person = an existing agent), the choice on the right. Hovering the name shows the details: the kind of pane, the steps that address the role (Step 1 · Prepare handoff briefing), and where a launched pane opens. The control is the choice for that role:
    • current — a pane picker pre-selected from the worktree’s focused pane (fixed when started from an Active Agents row); a bare shell qualifies only while no step messages that role.
    • launch — a profile picker pre-selected by binding resolution, filtered to profiles that qualify (agents allow-list, prompt support); profiles that do not qualify are dimmed with the reason. Create profile from suggestion… appears when the role’s suggest matches no enabled profile: it creates a normal Agent Profile inline and selects it. A launch role the current options never reach (a branch that is not taken) is listed dimmed with Not used in place of its picker. If no profile qualifies, the sheet points to the role’s agent requirements and Settings → Agents → Profiles. Correct the requirements or profiles, then reopen the setup.
    • pick — a pane picker over detected agents in the worktree, excluding panes already in a run and the source pane.
  • Options — the declared inputs in the same grid, labeled by their prompt (hover for the input name and default) with defaults pre-filled; enum inputs are menus, the rest text fields. An enum without a default starts at Choose…. Required inputs without a default must be filled before Run enables.
  • Steps — the run’s steps in order with their role, so choices like “launch or save” read as “step 3 starts the receiving agent”. Steps inside an if carry a branch icon, steps inside a while a repeat icon; hover a step for what it does.
  • Optional Steps — a Skip toggle for each step whose output nothing later depends on. A skip that would end the run early is refused by admission and therefore not offered.
  • Don’t ask again (footer) — writes Run Directly When Possible (the same choice shown under Settings → Workflows → Run Setup), so the next start skips the sheet when nothing is undecided.
  • A banner blocks Run when the prowl CLI is not usable or when Prowl is not listening on its socket (participants could not deliver). Inline action per state: Install when missing, Repair for a dangling link, Reinstall for a foreign link that is not executable; a real file or folder in the slot gets no button, only the instruction to remove it (same matrix as the Workflows page banner below). A socket failure shows its reason.

A workflow with bind: auto roles, resolved bindings, no pick roles, and fully defaulted inputs starts without the sheet; the toolbar status item is the feedback.

While a run is active#

  • The toolbar’s center status item shows the selected worktree’s active run: the current step, an orange attention glyph when the run waits for you, and a count when several runs share the worktree. Hover previews the run panel; click pins it. When a run ends, the item stays for about eight seconds with the outcome — a green checkmark and completed, or the reason it stopped — and hovering it opens that run in Workflow History. No separate toast is shown; the notification pipeline still delivers the completion notice.
  • The run panel opens the same step details as Workflow History. Expand a step to inspect its output, error, and attempts. Role buttons focus available panes; the footer provides the run folder, log, and Cancel Run.
  • Needs attention is a state, not a deadline: a late delivery is still accepted. The panel offers exactly the recoveries the runner permits — Focus Pane, Nudge Again, Keep Waiting, Retry, Relaunch Role, Accept as Delivered, Accept with a declared verdict, Ask Again, Skip Step, Cancel Run.
  • Waiting is state-driven: a working agent is never interrupted; an agent whose turn ended without delivering gets one typed nudge with the completion command.
  • Completion and attention go through the bell with click-to-open run details (quiet while you are already watching that worktree). → notifications
  • Active Agents rows bound to a run show in <workflow> · <role> for the life of the run; a pane belongs to at most one run at a time.
  • Finishing or cancelling never closes a pane; only an explicit close: step does.

Inspect workflow steps after execution#

Workflow History, beside the toolbar bell, stays available after a run ends. Hover to preview; click or interact with its contents to keep it open. The default This Pane scope includes runs started from this pane and runs in which it or its identified agent session participated as a role. This Worktree and All Runs include broader history and records whose pane identity is unavailable.

The muted checklist button opens Workflow History. The run list shows each name, a tinted state icon, and project or pane attribution; completed runs use a green checkmark. The detail header puts status beside the title and start time beside elapsed time.

Select a run on the left, then click anywhere on a step row to expand it. Hover highlights the row. Recorded step duration appears at the right; a dash means no duration was saved. Checkmarks indicate completed execution; a delivery verdict such as issues does not mean execution failed. Branches not selected, skipped steps, and steps not reached before termination have separate states. Nested rounds show their complete loop path. Rounds and retry attempts retain their own recorded outputs and errors. Provisional and corrected submissions keep separate body snapshots. Failed action attempts link to their own stdout, stderr, and execution record. Step titles come from the execution, not from later YAML edits.

Message and launch steps show the target role, recorded profile or agent, and the saved prompt. A launch reports Agent started only after startup succeeds; without expect, this does not mean the agent finished its task. Targets are recorded per attempt, so a relaunch cannot change an earlier attempt’s identity.

Action steps show their action ID and resolved Input from that execution’s saved request, separate from Output. Conditions show the selected branch and recorded boolean result. Notifications show the text sent to Prowl Notifications; a declared step title takes precedence over the default notification label. Pure operations do not show an empty Output section.

Prompt and delivery previews show the first 200 characters with inline Markdown formatting and the remaining character count. JSON output uses nested, expandable fields, with single-line values and middle-truncated paths. Each level shows at most 32 fields, up to five levels deep; the complete JSON remains available externally. output is the action’s returned JSON value; output_path is the saved result.json file containing that value, not a second result.

Preview and Copy read files up to 64 MiB. Open and Reveal remain available if a preview is unavailable or a file exceeds that reader bound.

Compact icon buttons open full output, copy full content, or reveal files in Finder; hover a button for its label. Named absolute path fields also offer file actions. Opening is limited to retained workflow storage and the worktree’s .prowl/handoff/ artifacts, with link and containment checks. Diagnostics holds action stdout, stderr, and execution metadata. Missing or unreadable files get a separate message. The run’s More menu offers Export… (a complete ZIP of a finished run) and Delete Run…, which asks for confirmation and removes that finished run’s record, prompts, deliveries, and action outputs; active runs cannot be deleted. Storage totals and Clear History… remain in Settings.

A selected run stays open when it completes, without switching to another run or resetting the reading position. Only active runs offer recovery and cancellation. Roles retain their recorded agent icon after execution. An @pN link appears only while that terminal pane exists, even if its agent has exited back to the shell. Closed panes keep their role and agent icon without an inactive link.

Hovering from History to the bell switches the preview without reopening the old panel. A click pins the panel; click the other button to switch a pinned panel. Escape or an outside click dismisses it.

Every run, including workflow test-action, stores its runtime data in ~/.prowl/logs/workflow-runs/<root-name>-<root-hash>/YYYY-MM/<run-id>/. The hash identifies the canonical, symlink-resolved execution directory. Worktrees and clones have separate histories; changing a branch keeps the same identity. The creation month stays fixed. No project-local runtime files or Git-ignore rules are created. Personal and team workflow definitions keep their existing locations.

Each run contains run.json, log.md, its frozen bundle in definition/, prompts/, skills/, deliveries/, and actions/. Metadata records the original execution root. prowl workflow status <run-id> finds saved history even after that root is closed, moved, or deleted. A moved folder does not inherit the old history.

Settings → Agents → Workflows → Run History shows how many runs the archive holds and their size on disk, with Clear History…: after confirmation it deletes every finished run that is not in use, ignoring the retention window. Active runs are kept. Export (from a run’s More menu in Workflow History) creates a complete ZIP of a finished run; choose a location outside workflow history for durable results. Outputs and action artifacts inside history expire with their run.

Automatic cleanup removes finished runs three days after completion; there is no per-run protection and no user-facing retention setting. The global budget is 5 GiB, soft: older eligible runs are removed first when history exceeds it. Runs finished in the last 24 hours, live runs (including Needs Attention), occupied runs, and ambiguous or unsafe records are protected from automatic cleanup. Startup and completion trigger background cleanup with a shared five-minute rate limit. Old project-local data is neither migrated nor deleted.

Both message and launch require prompt; the retired text and instruction fields are not accepted. A message waits for an idle agent, then Prowl chooses direct single-line delivery or scoped read after rendering. Launch uses a kickoff prompt. expect controls whether either step waits for an agent delivery. Saved files in prompts/ contain the task body, without generated completion commands.

Agents retrieve assigned prompts and explicit input resources with prowl workflow read, using the run ID, invocation number, and assigned pane. Prowl owns persistence; deliver text or JSON through prowl workflow deliver - on stdin. Run paths are temporary artifact locations, not durable downstream references.

Settings → Agents → Workflows#

The global page is a compact index of Built-in and Your Workflows (~/.prowl/workflows) only. A row shows the YAML icon, name, id, description, and one effective status: Ready, Disabled, Invalid, or Superseded. Select the row to open its detail; the index itself contains no workflow-specific controls.

Repository workflows live directly in the matching Repository Settings, in a Workflows section immediately after Agents. It uses the same compact rows and the same detail page—there is no intermediate workflow page.

The detail page owns these controls and explanations:

SectionEffect
Workflowidentity, effective status, and Enabled. Disabled workflows disappear from launch surfaces and prowl workflow run refuses them with WORKFLOW_DISABLED. Repository settings are keyed by canonical repository root plus workflow id, so the same id in two repositories remains independent.
RunRun in <repository · worktree> names the actual target and follows the main window’s selection whenever the detail appears or the Settings window becomes key. Its menu lists other legal worktrees and Run with Options…. Repository workflows only list worktrees from that repository. Every choice uses the same admission path as the other GUI and CLI entry points; if that explicit worktree closes first, Prowl refuses the run instead of falling back to another target.
Rolesevery current, pick, and launch role with a plain-language behavior summary. Only a launch role has a Preferred Agent Profile menu; Choose Automatically forgets the preference and lets Prowl resolve a qualifying profile at start. Unqualified profiles remain visible with the reason but cannot be selected. Manage Agent Profiles… appears once per page.
Run SetupFollow Workflow, Always Review Before Running, or Run Directly When Possible. The last choice starts immediately only when profiles, required role choices, inputs, and validation are already resolved; otherwise the review sheet still opens.
Validationevery diagnostic as message, source location, and stable code. Saving the YAML revalidates automatically; there is no separate Validate button.
Source FileOpen Workflow uses the default YAML app; the folder button reveals it in Finder. Delete Workflow… asks for confirmation, then moves a personal or repository workflow to Trash and returns to the list. Failed deletions keep the detail open with an error. Built-ins are read-only and cannot be deleted. YAML remains the source of truth—Settings does not embed an editor.

Starting from Settings keeps the review panel in the Settings window. Cancelling returns to the same detail without bringing the main window or terminal forward.

New Workflow… opens a form: a name, an id (suggested from the name as a lowercase slug, editable, refused when invalid, reserved, or already used here), an optional SF Symbol icon, and one of two starters. Single agent is a prompt template that asks the current agent for today’s date; Multi-agent plays rock-paper-scissors between the current agent and a launched one. Both write a validated, commented <id>.pwlworkflow/workflow.yaml into the current page’s workflow folder — the comments point at this manual and the bundled skill on disk — and open it in the default YAML app. Create with Agent… (on the index and inside the form) provides a copyable prompt that points a coding agent at the bundled prowl-workflow skill and this manual. From a valid creation form, the prompt includes the selected starter and its name, ID, and icon, so the agent can adapt that draft to your task. The form describes the actual starter example and the editor handoff before you create it. Names containing punctuation or non-English text are preserved in the YAML file. The folder button reveals the current workflow folder, creating it when needed.

The page follows its source folders live, so saving, adding, deleting, or renaming YAML updates the index and an open detail automatically. If an open file disappears, its detail becomes Workflow Unavailable instead of silently switching to another workflow.

A banner mirrors start admission: Install when prowl is missing (Repair for a dangling link, Reinstall for a foreign non-executable link), or the reason Prowl is not listening on its socket. The same status appears under Settings → Agents → CLI & Skills → Connection.

Gotchas for agents#

  • Validate before handing over: prowl workflow validate <bundle.pwlworkflow> works with Prowl closed and is the static check; Settings shows the same diagnostics plus availability warnings (installed runtimes, enabled profiles) that only the app can evaluate. Errors, not warnings, make a file unrunnable — and its row says so.
  • prowl.* ids are reserved for built-ins; a user or repo file using one is invalid (reserved_id).
  • Repository workflows are visible only from that repository’s worktrees; prowl workflow list from a pane answers for that pane’s worktree.
  • A remembered binding is keyed by the role’s requirements (agents, suggest, …): editing those in the file forgets the binding; editing prompts keeps it.
  • Participants must deliver with the exact prowl workflow deliver … command Prowl typed (token included); prowl agents dispatch-complete is refused inside a workflow activation with WORKFLOW_DELIVERY_REQUIRED.
  • Nothing is closed automatically; a launched reviewer pane stays open after the run unless the workflow has a close: step.

Script actions and bundles#

Local actions live under actions/<id>/action.yaml in a .pwlworkflow bundle, with scripts, helpers, and assets beside them. Steps reference local:<id> or a registered builtin:<id>. Action inputs and results are typed JSON; validated results appear at actions.<step>.output and actions.<step>.output_path. The built-in repository context writes per-invocation artifacts. builtin:save-handoff saves a briefing and generated context under .prowl/handoff/. These actions are also distinct from shell-command Custom Actions.

Scripts have your local user permissions. In Settings > Agents > Workflows, open the bundle’s script review, inspect the source location, interpreter, entrypoint, and changed files, then approve that version. Approval does not start the workflow. CLI starts and single-action tests use the same approval; the CLI cannot grant it. Changing or moving a bundle requires review again. A run uses a fixed definition copy; changes to that copy invalidate execution.

Use prowl workflow test-action <workflow-id> local:<id> --input-json '{}' to exercise one approved action in a real run. Then run the workflow to test its agent interactions and data flow. Tests have the same side effects as normal execution. Each attempt records its request, result, metadata, bounded raw stdout/stderr, and artifacts under the run’s actions/<step>/<execution UUID>/. Retries create a fresh attempt and can repeat side effects. Cancel and timeout terminate the owned script process group; neither operation rolls back completed work.

Typed state retains values explicitly. Branch and loop iteration results leave scope on exit. Use state to carry a verdict/path to the next iteration. A loop with no cap is permitted; a loop whose condition remains true at max_iterations ends as iteration_limit_reached. In the condition, context.step.id names the loop and context.step.iteration is the completed count, starting at 0. Steps in the body use iteration numbers starting at 1. A role stays bound for the run: launch it once, then send messages for repeated work.

Install the prowl-workflow skill for bundle examples, the action manifest and JSON protocol, approval guidance, expression rules, and test commands.

When a script bundle needs approval, the workflow start screen provides Review Bundle… and keeps Run disabled. Approval returns to the same start screen; it does not start a run.

Sandbox access#

workflow read and workflow deliver use the existing Prowl Unix socket. File-read access and socket access are separate permissions. If the runtime returns SOCKET_PERMISSION_DENIED, use its native approval mechanism for the specific Prowl command or socket; do not disable sandboxing or grant home-directory access. An existing current or pick pane keeps its launch permissions. Prowl does not retrofit new sandbox grants into it. No project-local staging is automatic.

For isolated Debug acceptance, PROWL_DEBUG_DATA_DIRECTORY selects temporary settings, cache, and workflow-history storage. Use a separate Debug process and matching PROWL_CLI_SOCKET. Release builds ignore this directory override.

Fixed size limits#

ContentLimit
Action input and test-action --input-json16 MiB
Action stdout16 MiB
Action stderr4 MiB
workflow deliver body (CLI and App)16 MiB of UTF-8
workflow read page256 KiB; continue with next_offset
Complete launch prompt, including protocol text128 KiB
Frozen workflow bundle64 MiB / 8192 entries
history.json64 KiB
JSON socket frame / serialized action request96 MiB + 64 KiB, including escaping and envelope fields

Action input is measured as compact JSON; request context and JSON escaping have separate transport headroom. These are Prowl limits; an agent runtime can impose a smaller launch limit. Larger results should use action artifacts. Individual artifacts and complete runs have no hard byte cap; the 5 GiB history budget remains soft.

history.json holds bounded display and lifecycle fields, separately from full action/state data in run.json. Long workflow names are shortened only in history metadata. History scans check the record’s file identity without decoding its contents. Missing metadata or a changed record protects the run from cleanup and export until it can be inspected. Record replacement invalidates the old metadata before publishing the new pair. No old-history migration or fallback is performed.

Built-in Handoff#

prowl.handoff asks the current agent to summarize its task, saves the briefing with repository and available session context, and optionally launches a receiver in a new tab and switches focus to it. Select next=save to save only; the receiver Profile is then unnecessary and hidden in the start sheet. The default next=launch uses the normal Profile picker without a runtime restriction. Both source and receiver panes stay open.

Both modes require a source pane with a detected agent to write the briefing. A selected bare shell cannot start the run; choose another agent pane in the same worktree. With no available agent pane, start an agent first. The workflow does not create its own author. CLI admission returns AGENT_NOT_FOUND for a bare shell or SOURCE_REQUIRED for a missing source pane, before saving or launching anything.

prowl workflow run prowl.handoff --role receiver=Codex --json
prowl workflow run prowl.handoff --input next=save --json

When an agent starts the workflow itself, it must follow self_initiated.line in the response and deliver its briefing with the supplied token. The run saves nothing until that delivery passes its required sections. The receiver reads an independent packet under .prowl/handoff/archive/workflow-<run UUID>.md; later handoffs do not change that packet. current.md and context.md retain the latest handoff state for workflow inspection.

A completed workflow means the packet was saved and the selected receiver was launched. It does not certify that the receiver finished the task. A failed launch keeps the packet; retry the failed step or use the packet manually. Cancelling keeps saved material and panes. See Handoff for storage and session context details.