Output & done-detection

How Plan knows a unit is finished — the output convention, file vs folder detection, writing results into the target project, and idempotence.

Plan’s notion of “done” is simple and durable: a unit is finished when its output exists on disk. This is what makes a campaign idempotent and resumable.

The output convention

Each campaign has an output convention with three parts:

  • dir — the output folder (relative to the project, or absolute).
  • name template — the output name; {unit} (and {brief}, {unit_path}) are substituted.
  • done detectionfile (the file exists) or dir (the folder exists and is non-empty).

{output} in your prompt resolves to this path, so you can tell the agent exactly where to write.

File vs folder

  • File (default) — the agent writes one file per unit (e.g. out/{unit}.md). Done = that file exists. Best, most precise signal; works for reports, JSON, enriched records, etc.
  • Folder — done = the output folder is non-empty (e.g. the agent generated code in sites/{unit}/). Use when the result is a directory of files rather than a single file.

Folder mode counts a unit done as soon as the folder has any content (checked when the agent returns idle). For a strict guarantee, prefer file mode with a final marker the agent writes last (e.g. sites/{unit}/.done).

Writing into the target, not the working directory

The output name can be absolute, which wins over the campaign folder. So you can keep the working directory at one project (e.g. where your agent/skill live) while each result lands in its own target — e.g. output_name: {brief}\REPORT.md where {brief} is a target path writes the report into that target. This is exactly the multi-repo audit recipe.

Idempotence & resume

Because “done” is “output exists”:

  • Rerunning a campaign skips units whose output is already there — no double work.
  • After a crash or reboot, in-flight units simply run again (a half-written output is avoided by having the agent write atomically / write the final file last).
  • The total/remaining is always recomputed from enumerate(source) − outputs present — the spool never holds the unit list.

Atomicity tip

If a unit can be interrupted mid-write, have the agent write to a temporary file and rename it at the end (or write the output file as its final action). Then “output exists” reliably means “unit finished”, never “unit half-done”.