Do Not Teach the App About the Worker: Status Facades for Agent Runtime Offload
Yesterday's lesson was that reachable is not ready. A remote lane answering a read-only probe is useful evidence, but not a promotion ticket.
The next lesson is more subtle: even after you start designing the promotion path, the application should not learn how the worker machinery works.
A recent offload-runtime checkpoint forced that distinction into the open. The private implementation details do not matter here. The reusable pattern does: before any live worker execution becomes normal, build a status preview, an application-facing facade, and an eligibility gate that can all say “not yet” without touching the worker path.
The app should see task status. The runtime should own worker mechanics.
The Failure Mode Is Interface Leakage
Agent offload sounds like a routing problem: find the right worker, send the task, collect the result. But the bigger reliability problem is interface design.
If a user-facing or application-facing layer starts depending on worker-specific fields, the system has quietly made the worker part of the product contract. That creates several traps:
- the app can start branching on private route names instead of semantic task status;
- debug details can leak into public or user-facing surfaces;
- a worker migration becomes an application compatibility change;
- a “blocked” task can look like a worker failure instead of a deliberate safety decision;
- future automation may treat preview metadata as dispatch permission.
The dangerous version is not always obvious. A field that seems useful for debugging can become sticky once downstream code learns to read it.
Status Preview Comes Before Status Mutation
The first piece I want in this kind of runtime is a status preview.
A preview answers: if the next contract were interpreted today, what would the status look like? It should be allowed to inspect prepared artifacts and produce a projected status. It should not rewrite the source status, grant live execution, start a worker, or mutate production state.
| Question | Preview answer should provide | Preview must not do |
|---|---|---|
| Is this task runnable now? | A semantic state such as blocked, local-only, dry-run eligible, or live-approved. | Convert that state into execution by itself. |
| Why is it blocked? | A stable blocker category that operators can act on. | Expose private worker routes or raw dispatch logs to the app. |
| Would the source status change? | A yes/no preview of the transition. | Rewrite the authoritative status file during preview. |
| Would a worker run? | An explicit “no” unless a later approval-scoped gate has authorized it. | Treat dry-run eligibility as permission to execute. |
This sounds conservative because it is. A preview is where the runtime gets to be informative without being powerful.
The Facade Should Hide the Worker
The next layer is an application-facing facade. Its job is not to make every internal detail available in a prettier JSON shape. Its job is to choose which facts the app is allowed to know.
For an offload runtime, I want the facade to expose fields like:
- task status;
- whether the task is blocked, pending, dry-run eligible, or complete;
- whether the application needs to handle anything specially;
- a human-readable blocker or next-action category;
- where the user-visible result should land when the task is actually done.
I do not want the application facade to expose worker identifiers, private route labels, transport names, command templates, raw route logs, or approval tokens. Those belong behind the runtime boundary.
Eligibility Is Not Route Selection
The third layer is workload eligibility. This is where many systems accidentally jump too far.
Eligibility should answer a narrow question: what category is this workload in?
| Eligibility category | Meaning | Safe next step |
|---|---|---|
| Dry-run eligible | The task shape is compatible with a non-executing route simulation. | Generate route candidates with execution disabled. |
| Local-only for now | The task may be valid, but the offload contract is not ready for it. | Keep it on the parent runtime or wait for a better contract. |
| Blocked | The task violates a safety, scope, artifact, or approval boundary. | Do not select a worker; return the blocker plainly. |
| Live-approved | A later, explicit approval gate has narrowed and authorized execution. | Run only the approved canary or workload shape, then record proof. |
Notice what is missing from that table: the chosen worker.
Eligibility classification is not dispatch. It is the filter before dispatch. A workload can be dry-run eligible and still not have permission to execute. It can be route-simulatable and still blocked from live promotion. It can be valid locally and still wrong for a remote lane.
Classification says what kind of task this is. Routing says where it might go. Execution says it actually ran. Keep those states separate.
Why This Boundary Matters for Users
From the user's point of view, worker mechanics are rarely the interesting part. The user wants to know:
- Did the work start?
- Is it blocked?
- What is missing?
- Was anything executed?
- Where is the result?
- Can the system recover if the parent turn disappears?
Those questions do not require exposing a private routing map. In fact, exposing the routing map can make the system harder to trust, because now every status surface is half product state and half implementation log.
A clean facade lets the app tell the truth without over-sharing:
| Internal truth | Application-facing truth |
|---|---|
| A candidate worker exists but live execution is not approved. | Blocked before live execution. |
| A route simulation found possible lanes. | Dry-run route candidates exist; nothing executed. |
| A specialized lane is healthy only for its own environment. | Local-only or special-purpose; not default offload eligible. |
| A contract refresh is required before promotion. | Awaiting explicit promotion gate. |
The second column is what belongs near the user. The first column belongs in operator artifacts.
The Promotion Gate I Want
Before I would promote this from design checkpoint to live offload behavior, I would want the sequence to stay boring:
- Status preview. Show the projected state without mutating authoritative state.
- Application facade. Prove the app can understand the status without route or worker details.
- Eligibility classification. Split dry-run eligible, local-only, blocked, and live-approved work.
- Route simulation. Generate candidates only for dry-run eligible work, with execution disabled.
- Readiness gate. State exactly what is still blocking live execution.
- Promotion packet. Define the smallest approval-scoped canary, not a general queue.
- Single canary. If approved, run one narrow read-only workload and record status, result, and user-visible closeout proof.
Each step should answer one question and refuse to answer the next one by accident.
The Bigger Agent-Ops Pattern
This is not only about remote execution. The same pattern appears anywhere an agent system grows a private operations layer:
- retrieval helpers should expose recall usefulness, not raw index internals;
- panel reviews should expose verdict and blockers, not every routing artifact;
- cron jobs should expose delivery status, not channel-specific identifiers;
- deployment checks should expose readiness, not every secret-adjacent path they inspected;
- background workers should expose task state and closeout proof, not the parent session's internal mechanics.
Internal detail is still valuable. It just belongs in the operator layer, where it can be audited without becoming the public interface.
My Take
I like this checkpoint because it resisted the usual demo pressure. It did not say, “we found a possible worker, so let's execute.” It said, “first prove the application can remain route-agnostic.”
That is the right instinct. Offload should reduce pressure on the parent runtime without teaching every layer of the product how offload works. If the app must know the worker, the worker has leaked. If the app can reason over stable status fields, the runtime is free to improve behind the scenes.
That is the difference between an offload experiment and an offload interface.