AWS Builder Center
Agents for Humans: The Delivery Gate — Why Our Agent Isn't Allowed to Say “Done”

Agents for Humans: The Delivery Gate — Why Our Agent Isn't Allowed to Say “Done”

A language model can claim a task is finished. We built a deterministic delivery gate around our Strands agent so “done” means verified artifacts, not generated prose.

Series: Agents for Humans: Building ST-Agent (3 articles)

  1. 2
    Agents for Humans: The Delivery Gate — Why Our Agent Isn't Allowed to Say “Done” This article
Every file-producing agent has two versions of reality.
There is conversational reality: the agent says, “Your files are ready.” Then there is filesystem reality: the file may be missing, stale, malformed, or impossible for the target application to read.
We built ST-Agent for the Agents for Humans hackathon. It turns story ideas into SillyTavern-ready character cards and lorebooks through one Strands agent and eight bounded tools. Early on, we made one architectural decision that shaped the entire system:
A language model's claim about the world is not a fact about the world.
So ST-Agent does not trust the model's final sentence — even when that sentence is perfectly formatted and confidently says “delivered.” Completion is an application state that only deterministic code can establish.

The dangerous last mile

In a multi-step build, the model may do everything reasonably well and still be wrong about the result. A write can be interrupted. An upstream edit can make an artifact stale. A Character Card V3 envelope can have the wrong shape. A PNG can open as an image while its embedded character payload is missing or damaged.
The model does not observe all of those facts directly. It sees tool results and conversation context. The user, however, receives the bytes on disk.
That difference creates a trust boundary: the point where generated intent becomes a deliverable. We decided to put the strongest checks there.

How the delivery gate works

Three tools form the end of ST-Agent's build sequence: check_official_sources, validate_deliverables, and finish_case.

1. Build through deterministic services

The agent chooses what to do, but it does not write arbitrary files. Its tools pass structured content to application services that serialize the character card, lorebook, and PNG package.
Case-state writes use a sibling .tmp file, flush it to disk, and then replace the target. If a run stops mid-write, recovery clears stranded temporary files and resumes from the state that actually persisted.

2. Check the current format references

check_official_sources retrieves a small allowlist of format references and compares them with expected markers in ST-Agent's local format profiles. The evidence is saved with the case. A missing, unavailable, or changed source cannot silently become a pass.
This gate is intentionally separate from generation. The model is not asked to remember whether a format rule is still current.

3. Validate the exported artifacts

validate_deliverables inspects the files requested for this case, not a draft object still inside the model's context. Among other checks, it verifies:
  • every requested output exists;
  • artifact lineage is present and not stale;
  • the Character Card V3 envelope and required fields match the local profile;
  • lorebook entries have the expected shape, supported positions, and non-empty content;
  • the PNG card can be decoded, and its embedded character data matches the source card.
Failures return structured, repairable issues. The agent can correct the content or rebuild the artifact, but it cannot talk the validator into passing.

4. Let only the gate authorize completion

finish_case runs the delivery checks again before closing the case. If any check fails, it returns a delivery-gate failure and leaves the case recoverable.
If the model skips that tool and simply returns a delivered outcome, the controller rejects the claim and changes the result to blocked. In other words, persuasive wording has no completion authority.
Only a successful finish_case records the verified export paths, closes the case, and marks that turn as eligible for delivery.

5. Render downloads from persisted state

The UI reads the closed case's recorded deliverables and creates download buttons from those paths. It does not parse the agent's prose to decide what exists.
That gives us a simple product invariant:
If ST-Agent shows a download, the application has a persisted artifact that passed the delivery gate.

What the gate caught that the model could not

We expected this architecture to catch hallucinated completion. It also catches failures between the model's intent and the final bytes: stale lineage after an edit, missing requested formats, invalid lorebook structures, corrupted PNG chunks, and semantic mismatches after packaging.
This led to a broader rule we now use throughout the project:
Validate at the trust boundary, not only at the generation boundary.
Validating model output before serialization is useful, but it cannot detect a problem introduced by serialization, packaging, promotion, or persistence. Reading back the finished artifact checks the same object the user will receive.

A better shape for failure

The gate does not make failure disappear. It changes failure from a false promise into an actionable state.
Instead of “the agent said it was done, but the file is broken,” the user gets a bounded failure with a specific reason. The case remains resumable, the last valid state stays on disk, and completion still means something.
It also keeps our demo honest. The scripted representative case runs through the same submit_turn path used by the Streamlit UI. The artifacts shown in the demo are the artifacts the validators inspected; there is no demo-only delivery path.

The reusable pattern

If your Strands agent produces files, reports, deployments, or any other external effect, consider separating these three responsibilities:
  1. let the model decide what action to attempt;
  2. let deterministic code verify what actually happened;
  3. let only verified state authorize the word “done.”
Models are excellent drivers. They should not be their own finish line.
ST-Agent is open source: github.com/Lockyer228/ST-Agent 
Next in the series: what Strands taught us about bounding an agent's authority without clipping its usefulness.
Written as part of our entry for the Agents for Humans hackathon.

Series: Agents for Humans: Building ST-Agent (3 articles)

  1. 2
    Agents for Humans: The Delivery Gate — Why Our Agent Isn't Allowed to Say “Done” This article
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article