Skip to content
Pocket Grove
Developer blog

Define What Done Means for an Agent Workflow

Published · 6 min read

By · Pocket Grove

Original research brief: . Sources reviewed: .

Quick answer: Define completion through recorded outcomes: every required task has a known result, its artifact exists, acceptance checks refer to that artifact, and the requested delivery is confirmed. Keep worker execution, accepted work, and delivery separate so a restart can reconcile them before repeating anything.

A coding agent can finish its message while a build continues. A worker can exit successfully after producing an incomplete file. A reviewed patch can exist locally while the requested delivery remains unfinished.

Each event tells you something useful. A workflow needs to specify which combination satisfies the user's request. Otherwise the word “done” becomes a different promise depending on which component says it.

The example here is a fictional documentation update with two parallel workers. The records are a design exercise; no workflow was executed to produce them.

Write the completion contract before dispatch

Suppose the assignment is to update an installation guide and its command reference, reconcile their shared examples, and deliver a reviewable candidate.

Define three logical tasks: installation, command-reference, and integration. The first two may run in parallel. Integration depends on both accepted inputs. Completion requires a recorded candidate containing the combined changes and the agreed review evidence.

That definition deliberately names the requested delivery. If the user asked for a local candidate, publication is outside this contract. If publication is authorized and requested, the workflow needs another step with evidence from the destination.

Make the definition short enough to consult during recovery. A useful contract names the expected tasks, dependencies, required artifacts, acceptance criteria, delivery target, and the person or component responsible for accepting each result.

Keep three state dimensions

A single status field can conceal too much. For each task, record execution separately from acceptance and delivery:

Dimension Example states Question it answers
Execution Pending, running, succeeded, failed, cancelled, unknown What happened to the attempt?
Acceptance Pending, accepted, rejected, invalidated Does the recorded result satisfy the task?
Delivery Not required, pending, confirmed, unknown Did the required destination receive it?

These are proposed application states, not a standard every agent runtime implements. An execution can succeed while acceptance is rejected. Delivery can remain unknown after a connection drops, even if the destination applied the change.

The distinction is familiar outside agents. HTTP 202 Accepted means processing was accepted but has not completed; its status alone does not establish the eventual outcome. RFC 9110 makes that boundary explicit.

Join the work you started

When dispatching parallel work, retain an inventory of task identities and execution handles. Before integration, account for every required task. A timeout belongs in the inventory as an unresolved or failed observation; it must not quietly disappear from the expected set.

Use the runtime's joining mechanism where one exists. For example, Python's asyncio.TaskGroup waits for its tasks when the context exits and propagates failures according to its documented rules. It gives a program a concrete boundary for related execution. Python's task-group documentation describes that behavior.

An execution join still needs application acceptance. Check that the installation worker produced the requested file and that the command-reference worker covered the intended commands. “Both workers returned” is an intermediate fact in this workflow.

For external workers, define how their status is queried and how long the coordinator waits. If one becomes unreachable, preserve its task identity and last observation. Starting a replacement while the original can still write needs a coordination rule that prevents competing writes.

Give accepted work a durable receipt

Here is a compact illustrative record. Names such as candidate-A are placeholders for actual immutable artifact identifiers:

{
  "task_id": "installation",
  "attempt_id": "installation-attempt-2",
  "input_artifact": "brief-revision-3",
  "result_artifact": "candidate-A",
  "execution": "succeeded",
  "acceptance": {
    "state": "accepted",
    "criteria_revision": "guide-checklist-2",
    "evidence": "review-record-A"
  },
  "delivery": "not_required"
}

The logical task stays stable across retries. The attempt identifies one execution. The artifact identifies what was produced, while the evidence explains why it was accepted.

Store the receipt where the next coordinator can retrieve it independently of the conversation. Save the artifact before marking its receipt accepted, and confirm that the stored reference resolves. If the artifact and receipt use different storage systems, record intermediate states and reconcile partial writes; do not assume they commit together.

Keep enough detail to detect stale acceptance. If the input brief changes, or the artifact is replaced, the earlier review may no longer apply. Our guide to verifying the exact code an agent will ship develops that identity check for source and build evidence.

Reconcile before resuming

Imagine the coordinator restarts with these observations:

Logical task Recorded evidence Next decision
Installation Accepted artifact and matching input revision Reuse that accepted result
Command reference Attempt started; no final receipt Query the worker and artifact store
Integration Never started Wait for both accepted dependencies

The missing receipt does not prove the command-reference worker did nothing. It may have saved a result before losing contact. Reconcile the artifact and execution status before dispatching again.

If its result exists, run the defined acceptance step and record the outcome. If the attempt is conclusively absent or failed, create a new attempt for the same logical task. If the outcome remains unknown, retain that state and choose an operation-specific recovery path.

Use stable task identities instead of positions such as “second worker launched.” Concurrent execution order is a poor definition of which work a result belongs to. A resumed coordinator should compare expected tasks with durable records, including their dependency revisions.

Handle repeated external effects separately

A completion receipt records what the workflow knows. Preventing a duplicate external effect requires support where that effect is applied.

For an API with an idempotency contract, reuse the operation's identifier on a retry and honor its scope, retention, and parameter rules. Amazon's discussion of idempotent APIs explains why caller-provided request identity matters and why recording identity must be coordinated with the mutation.

Do not assume identical arguments express the same intent: someone may legitimately request two identical resources. Conversely, a new network attempt should not automatically become a new business operation.

Where the destination offers no suitable deduplication or read-back contract, an uncertain outcome needs explicit handling. The recovery guide for stopped agents explains how to preserve that uncertainty before retrying or undoing work.

Review the final completion claim

Before reporting completion, check that:

  • Every required logical task has an accounted-for outcome.
  • All dependencies used by the final candidate are identified.
  • Accepted artifacts exist and match their recorded review evidence.
  • Replaced inputs or artifacts have invalidated stale acceptance.
  • Required delivery has a destination receipt or an explicit unresolved state.
  • The final message describes the outcome and any remaining limitation.

A small workflow can keep this information in a short file. A larger service may need a transactional job store. Start with the smallest record that lets a fresh coordinator answer: what is accepted, what remains uncertain, and what may run next?

Apps from the studio

All apps

These practices come from shipping Pocket Grove's active apps. If you came here looking for something to install, start with one of these.

Related guides