Organizing Execution
The Agent Task Contract
How to turn a vague request into a bounded, verifiable task contract for an agent, naming the goal, sources, scope, invariants, permissions, evidence and…
"Fix the import bug" sounds like a task, but it does not say which error the user should no longer see, which import is the source of the problem, what may be changed or how the result should be confirmed. If the implementer guesses wrong, they can do a great deal of work and still not solve the problem. If, on the other hand, the instruction dictates every file and every function in advance, it can rule out a better way of implementing the change that the author does not yet know about.
In Implementing a Vertical Slice, the short working brief was just one step in carrying a slice all the way through. Here we focus on the task itself: how to connect the desired result with the current state of the repository, the sources of requirements, the boundary of permitted work, the evidence and the authority to make decisions. This continues the themes of product requirements, clarifying requirements and acceptance criteria, but does not replace them: the contract points to the existing specification and defines what exactly the implementer does with it in a specific working copy. Coordinating several implementers is covered in more detail in Codex subagents and orchestration. The contract names the repository and the environment needed; Worktrees and Isolated Environments explains separately what a Git worktree, a container and test data really isolate and what remains shared.
Learning outcome. After this unit the reader can turn a vague request into a verifiable, bounded task; tell a goal from the means of reaching it; name the sources and permissions needed; agree on the evidence of completion; and stop correctly when a precondition or the scope has changed.
All the names of people, companies and systems, the data and the results in the teaching scenarios below are invented. The public Python example is marked as real and described from verified material.
A contract is an agreed boundary of work
"Contract" here means a working agreement between the person delegating the work and the agent carrying it out. It is not a separate format standard and not a special property of a language model. The agreement answers the questions: what result is expected, what the task is based on, where its boundary lies, by what actions it may be achieved, what evidence must be provided and what to do about the unknown.
An ordinary conversation can be a sufficient contract for a small, obvious edit in a safe repository. A change to authorisation, a data schema or a public interface needs more precise sources, criteria and boundaries. So it is more useful to think not of a lengthy universal template but of proportionality: the more expensive a mistake and the more that is unknown, the more of the agreement needs to be made explicit.
A contract is neither a wish to "do it well" nor a script of every keystroke. It contains enough specifics for two people to understand an acceptable result in the same way, but it leaves room for professional choice in the implementation. The author defines what must change and which conditions must not be violated; the implementer explores the code and proposes how best to achieve it.
This is close to Ryan Singer's advice in Shape Up: shape the problem, the "appetite" (how much time the team is willing to invest in the work), an outline of the solution, the risky unknowns and deliberate "no-gos", meaning things that are outside the work. Appetite constrains the shape of the solution; it is not an estimate of how long an already defined implementation will take, and it is not an arbitrary deadline. The outline should give the implementers a direction and a boundary, not pretend that every implementation detail is known in advance. This is Basecamp's method, not a mandatory process for every team. For agent-based development, two ideas from it are worth borrowing: name the excluded scenarios explicitly, and do not hide risky assumptions (Shape Up: Write the Pitch, Shape Up: Risks and Rabbit Holes).
What a workable task is made of
In a specific task, the fields can be short or can point to an existing document. Their purpose is not to fill in a form but to remove ambiguity that would affect decisions.
Goal and value
Describe the change the user or operator should experience, and why it is needed. "Add a button" names a piece of interface work; "the operator can rerun a failed import without losing records that were already accepted" names the result and the property that must be preserved.
The result does not have to be a business metric the agent can measure itself. If the expected impact is a hypothesis, label it as a hypothesis. A finished implementation does not yet prove that customers have used the feature or that costs have fallen. Distinguishing the goal from the activity helps avoid the situation where a file has been created but the required behaviour is missing.
Current state and sources
Record enough context for the implementer to know exactly which system they are changing: the repository, the target branch, the base revision or commit, the observed behaviour, related tasks and the environments that matter. If a particular field goes stale quickly, it is better to ask for it to be checked before editing than to treat an old description of the repository as its current state.
Alongside this, name the authoritative sources: for example, an agreed requirement, an Architecture Decision Record (ADR), an application programming interface (API) contract, the repository's rules or the vendor's official documentation. Link to a specific section or version where possible. There is no need to paste in a whole document if a link and a short explanation of why it matters are enough.
If sources contradict one another, do not paper over the conflict with "follow all the requirements". Name it and say who can decide which source takes priority. The existence of two documents does not mean they agree.
Boundaries and invariants
Describe which behaviours are part of the task, which are explicitly excluded and which properties must remain true. "Don't change adjacent pages" can be a useful boundary, but a list of files does not, by itself, describe how the system should behave. Sometimes code has to change in several places for one behaviour to work consistently.
An invariant is a rule that must hold in every acceptable implementation. For example: "re-importing the same file does not create a duplicate" or "an access refusal does not change someone else's record". An invariant usually matters more than a preference such as "keep the function in this class". A dependency, migration or neighbouring scenario that is not named in the scope does not automatically become permitted just because the agent noticed it while working.
Acceptance criteria and evidence
A criterion should describe an observable condition. "Tests pass" is incomplete if it is not clear which checks, at which revision and which property they confirm. For each important criterion, name the corresponding evidence: a check, a review of the diff, a log entry, a request to a test environment or another observation.
It is convenient to distinguish four evidence states. This is a recommended reporting vocabulary, not a protocol shared by agent products:
| Status | What it means |
|---|---|
| PASS | The check was run, and the result matches the criterion. |
| FAIL | The check was run, but the result contradicts the criterion or revealed a defect. |
| BLOCKED | The check cannot be completed under current conditions because of a specific missing precondition or access; name what exactly is blocking it. |
| NOT RUN | The check was not run, although it was available or was deliberately postponed; give the reason. This is not evidence of a pass. |
"Not run because there is no test account" is not a PASS, and not necessarily a defect in the code. It is an unperformed check with a specific blocker, which the responsible owner can remove or accept as residual risk. An old result does not carry over to a new revision if the code or the preconditions have changed in between.
Permissions, preconditions and the stopping boundary
Separately from the desired result, state which actions are permitted: reading files, local changes, running checks, creating a branch or a pull request, reading or using secrets, access to production accounts, writing to an external system, merging, deploying or spending money. Permission to write code does not mean permission to read secrets, change production data, send messages to customers, use a paid resource or merge changes.
The text of the task explains the intent, but it does not grant technical rights. Real capabilities depend on the tools, the isolation and the approval settings of the specific environment. For example, OpenAI's documentation distinguishes the boundaries of the execution environment from permission controls, while Claude Code has its own system of rules that allow, ask about or deny tool actions. These are different products and configurations; the behaviour of one cannot be assumed for the other (OpenAI: Agent approvals & security, Anthropic: Configure permissions, checked 26 September 2026).
Name the preconditions that must be met before the work starts: the required schema, a test environment, the current revision of the contract, the owner's approval or valid credentials. Say which local assumptions the agent may make and when it should stop. A good rule: if the uncertainty changes product behaviour, security, public compatibility, the scope or the right to take an external action, record the fact and hand the choice to the owner; small, reversible implementation details can be decided independently and described in the report.
Resources and the expected report
If duration, budget, the number of iterations, the number of implementers, the owner of shared files, a ban on parallel changes or side effects matter, name them. For a specific scheme of delegating to several agents, see Codex subagents and orchestration. Do not invent a deadline that supposedly follows from a technical estimate. If a fixed time budget in the spirit of Shape Up applies, explain what can be narrowed to stay within it and which correctness requirements cannot be relaxed.
Finally, define the form of the report. What is needed is not just a list of commands or "done", but:
- what changed, where and why;
- which base and final revisions were considered;
- which criteria and checks got PASS, FAIL, BLOCKED or NOT RUN;
- which unknowns, risks and decisions remain;
- what next step is needed from the owner.
Anthropic advises giving the agent a way to verify its result and to show evidence, such as test or build results. In its guidance on Codex Goals, OpenAI likewise ties the completion of work to a clear outcome, a way of checking it and explicit stopping conditions. These are vendors' recommendations for their own products, not a guarantee of correctness and not proof that a single optimal format for delegation exists (Anthropic: Best practices for Claude Code, OpenAI: Using Goals in Codex, checked 26 September 2026).
A complete example: "fix the booking problem"
Situation. The product owner says: "Customers can't reschedule bookings; fix it." The repository has several booking types, and the support messages do not make clear whether the problem concerns past bookings, group classes or a race for the same free slot. One sentence is not enough for safe editing.
Agreeing on the task first. The author checks the problem with support and with the owner of the product rule. For the teaching scenario they agreed: a customer may move their own future, confirmed, individual booking to another available time, but not after the appointment has started. Group classes and automatic SMS (Short Message Service) notifications are not part of this change. The documents and names below are hypothetical.
Goal. A customer with a confirmed future individual booking can move it to a free time themselves and understand the result. This should remove a manual support step for this scenario; fewer support requests is an expectation, not a proven result.
Current state. Repository
service-booking, branchmain, verified base revisionabc1234. At present the screen shows available times, but when two customers choose the same time simultaneously, both may receive an optimistic success message. Before editing, check the current branch and any local uncommitted changes.Sources. The product rule in A1M-214; the agreed
Booking APIcontract, version 3; architecture decision ADR-12 on the source of truth for time; the repository's rules. If they contradict one another, or the code shows a different rule, stop and name the conflict.In scope. For one future individual booking: server-side checks of owner and status, a repeat availability check when saving, a truthful interface state and a clear message when the time has already been taken.
Out of scope, and invariants. Group classes, payment, SMS notifications, calendar synchronisation and refactoring of other booking types are out of scope. It must not be possible to change someone else's booking, to lose an existing booking because of a conflict, or to show success before the save is confirmed.
Criteria and evidence. (1) The owner moves their eligible booking and sees the new time after a repeat read from the server. (2) Another user cannot read or move their booking. (3) Two requests for the last free time do not both succeed; the one that loses leaves the old booking unchanged and sees a recoverable error. (4) A booking cannot be changed after the appointment has started. Attach to the report the results of the relevant existing checks and the revision at which they were obtained; if the test environment is unavailable, mark that check separately.
Permissions and preconditions. Reading and local changes in the repository, and checks in the existing test environment, are permitted. Do not send SMS, do not change real bookings or production data, do not make external writes, and do not merge or deploy without a separate instruction. The current API contract and safe test accounts are needed. If they are unavailable, stop the integration check and report what is missing.
Report. Files and behaviour, the base and verified revisions, a table of criteria with PASS/FAIL/BLOCKED/NOT RUN, the actual command results, unresolved decisions and the next step required.
Why these items are there. The goal separates the benefit to the user from a list of activities. The current state provides a point of comparison, but the agent still has to verify it in its copy. The sources say which document defines the product rule and which defines the technical exchange. The scope cuts off tempting adjacent features. The invariants protect integrity even if the implementer chooses a different code structure. The criteria turn the words "fix" and "works" into behaviour that can be observed. The permissions separate writing code from external actions. The report ties claims to a revision and shows what remains unknown.
What the agent does, and the result. The agent discovers that the shared API contract does not define what message the customer who loses the race for a time slot receives. This is not a minor matter of wording: recovery and keeping the previous booking depend on the answer. The agent describes the behaviour it found, proposes two compatible response options and asks the owner which one fits the policy already agreed. The agent updates the contract as the owner directs and implements one success result and one conflict result. It does not add SMS and does not enable rescheduling of group bookings, even though it notices that both would need similar changes.
When this does not fit. This level of clarification is too much for fixing an obvious typo in a single user-facing message where there is no question about product behaviour. It is also not enough if the actual problem lies in payment settlements, the cancellation policy or several booking types: that is a different scope with new criteria. The number of items does not make a task good; clarity about the important decisions does.
When work outside the contract turns up
Situation. While working on a screen for rerunning an import, the agent discovers that the public API has no operation for partial recovery. The internal queue has a state that cannot be safely represented in the current contract. Changing the API would solve the problem, but it changes the scope and may affect customers' integrations.
The wrong decision. The agent adds an endpoint (an API entry point through which a client calls an operation) and a new response to the API, updates the client and ships it all as part of a small user interface (UI) task. Even if the implementation is technically correct, the implementer has decided a compatibility question that belongs to the owner of the public contract. Another wrong option is to hide the problem by faking a successful rerun that does not recover partially completed records.
What to do. The implementer stops changes at the boundary where a decision is missing and sends a short, evidence-based report:
Within the agreed scope I can add a screen that shows the queue state and allows a rerun only for a completely failed import. For a partially processed file, the existing API defines neither safe retry semantics nor idempotency (repeating the same request must not create a new effect) for records that have already been saved. I checked contract version 3 and the API endpoint
POST /imports/{id}/retry; both describe only a full retry. Options: (A) leave the partial state out of reach in this change and submit a separate proposal to extend the API; (B) extend the contract after the owner decides, and add evidence of client compatibility. I have changed nothing in the public API. Which option does the contract owner approve?
Until the owner decides, this part of the work is paused; independent changes within the original scope can continue only if they do not depend on it. In the teaching case, the API owner chooses option A: partial recovery is not part of this change, and support for it is proposed as a separate task. The author records the decision and the boundary in the contract; the agent finishes only the screen and the rerun of a completely failed import. Alternatively, the owner could have approved B, adding the requirement, compatibility criteria, a list of consumers and the necessary permissions. If the contract changes after the decision, the author updates the agreement before implementation, rather than just adding the fact to the final report. The criteria of the original task are not relaxed after the fact to hide incomplete behaviour.
This is especially important for public APIs, migrations and integrations: customers may not be present in this branch but still depend on the established behaviour. "It seems obvious" does not give the agent the right to make decisions on behalf of the compatibility owner.
When verification is blocked
Situation. An import change is ready locally, but confirming the full scenario requires access to a test supplier, and the team has no valid test account. The agent has access to the code and to a local set of fixtures (prepared data for reproducible checks), but not to the integration environment.
A false report says: "The import works, all criteria are met." In fact the integration was never run, so the conclusion is stronger than the evidence. It is equally inaccurate to hide the gap behind a general phrase such as "the checks passed" if only local unit tests were run.
An honest report ties the result to the actions actually taken:
| Criterion | Status | Observation |
|---|---|---|
| Reprocessing a valid file with local fixtures creates no duplicates | PASS | Local check run on commit d47c21a; 0 duplicates in the fixture result. |
| The real test supplier delivers the file in the agreed format | BLOCKED | Integration check not run: no test account and no environment address. |
| Retry-after-timeout scenario | BLOCKED | Not checked because of the same missing test access; the result is needed to confirm recovery after a timeout. |
The next step for the owner: provide test credentials through the approved secrets mechanism, or assign a person with access to run the integration check. The agent does not ask for a password to be sent in chat and does not substitute production credentials for test ones. The change may be useful and justified locally, but its acceptance remains blocked until the person responsible decides what to do about the unavailable evidence.
The example shows that the report separates the fact that a check was run, its result and the state of the criterion. Both integration checks are BLOCKED because they cannot currently be run for lack of access. A separate, optional performance test that nobody asked for and nobody ran would have the status NOT RUN; it is evidence of neither the success nor the failure of the import. A check that was not run did not "probably pass"; at the same time, an access blocker is not evidence of a defect. The decision to accept residual risk belongs to the responsible owner, not to whoever was unable to run the check.
When shorter is better, and when a plan is needed
Detail should reduce risk, not increase the amount of text. For a small task, one sentence describing the result, a link to the problem, a constraint such as "don't change behaviour X" and one check are enough. For a change involving many files, conflicting sources or external consequences, it is worth first asking the agent to investigate the current state and present a plan or open questions before editing. Anthropic also recommends exploration and planning for a broad, uncertain change, but notes that obvious small edits do not need an unnecessary plan (Best practices for Claude Code).
OpenAI's advice for GPT-6 Astra is to give the necessary context and point to the documents that help with a specific decision, rather than making the model re-read the whole repository before every edit. The original article also warns that excessive context can be distracting; this is a recommendation for a specific model, published on 11 September 2026, not a guarantee that a shorter prompt is always better (Rethinking skills and prompts for GPT-6 Astra).
A contract should make decisions easier. If the description is so detailed that it repeats the whole architecture, the repository's instructions and every obvious step, it will be hard to keep up to date, and the boundary that matters will be hard to find. If, on the other hand, two implementers who have read it answer "what will be accepted?" or "may the external system be changed?" differently, the contract has not yet clarified what matters.
A real example: an issue report and the limits of a conclusion
Python's asyncio library performs network operations through an event loop. A selector tells the loop that a socket is ready for reading or writing; a transport manages the socket and notifies the program when the connection has closed. CPython issue #156512 reproduces a failure while resuming writing (resume_writing()): the protocol writes the next chunk and, once the source is exhausted, closes the connection. The code re-enters connection teardown and calls _call_connection_lost(), the close notification, twice; the loop's error handler receives an exception. The author gave reproduction steps, the expected and actual behaviour, the versions and a walkthrough of the execution path. They noted separately that they had spotted a similar risk in _SelectorDatagramTransport._sendto_ready, the path that sends individual network messages, while reading the code, but had not verified it. That is a useful distinction: "reproduced", "saw in the diff" and "suspect by analogy" are different levels of evidence; in their test, the streaming API did not show this failure.
The related Python PR #156657 fixed both write paths, _write_send and _write_sendmsg, and added separate regression checks in which connection_lost() must be called exactly once and the loop's error handler must not fire. It also added an entry to the Python changelog. The PR does not cover the unverified datagram path and does not prove that path is safe. At the time of the merge on 6 September 2026, GitHub showed 99 of 101 checks passed; the aggregate required check was successful. That is not the same as claiming that every check passed.
The example does not prove that every team should write the same kind of report, or that the boundary of this PR was the only one possible. It shows the value of an explicitly labelled level of evidence, a focused change, related regression checks and an accurate report on the checks (Python issue #156512, PR #156657, review; checked 26 September 2026).
In Claude Code issue #76132, a user describes a case where, after some manual steps in the system, an ambiguous "next" was taken as permission to continue before the human had reported the result of the previous step. This is a self-report without an independently confirmed reproduction; the issue was closed with the status not_planned. It should not be presented as proven product behaviour. As a limited example, it is a reminder of why a waiting precondition ("wait for the result from the human") and the signal to continue need to be explicit when an action depends on a manual state (Claude Code issue #76132, checked 26 September 2026).
How a contract changes
A task can change because an unknown API contract, a dependency, a risk or a fact about current behaviour has been discovered. The right response is neither to carry on silently nor to lower the criterion that has just exposed the problem.
- Record the observation. Separate the verified fact from the assumption; add a link to the file, revision, source or command result.
- Explain the impact. What exactly cannot be finished within the current scope? Which criterion, compatibility or risk is affected?
- Propose bounded options. For example: finish the partial behaviour without the unsafe case; widen the scope and add evidence; or stop the work until a decision is made.
- Get a decision from the right owner. The author of the product rule may not be the owner of the public API or of permission for a production action. Identify the role that actually has that right.
- Update the agreement before continuing. A change to the goal, the boundaries, the criteria, the environment or the permissions is recorded in the current description; the report says what exactly changed and why.
This applied rule synthesises the practice of explicit scope and risk review from Shape Up with the documentation of criteria and boundaries in guidance on working with agents. Shape Up itself does not set out a protocol for changing an agent's task. Its principle of not starting unbounded new work inside an old bet helps you see the moment when a new discovery should send the work back to the decision stage (Shape Up: Map the Scopes, Decide When to Stop).
Summary
A workable contract connects value with specific behaviour and its current context. It points to authoritative sources, draws boundaries, and names the requirements that must not change, the permissions, the preconditions, the method of verification and the form of the report. It gives the implementer freedom to choose the implementation, but does not let them independently make decisions that change product policy, compatibility or external authority. If a new fact changes the original agreement, first change and agree the contract; do not bend the report to fit what the agent has already written.
Sources and further reading
Links to changeable instructions and to the state of products and repositories were checked on 26 September 2026.
- Ryan Singer, Basecamp, Shape Up: Write the Pitch, Risks and Rabbit Holes, Map the Scopes, Decide When to Stop. The author's method for shaping the problem, constraints, risks and what is out of scope. This is Basecamp's context, not a universal agent standard.
- OpenAI, Using Goals in Codex. Outcome, completion criterion, checks and stopping condition for long Codex tasks.
- OpenAI, Rethinking skills and prompts for GPT-6 Astra, published 11 September 2026. Selecting relevant context and setting explicit boundaries, in advice for a specific model.
- Anthropic, Best practices for Claude Code. Context, planning and giving Claude Code a way to verify its result.
- Anthropic, Configure permissions. Rules to allow, ask about or deny actions in Claude Code; a product configuration, not a general protocol.
- OpenAI, Agent approvals & security. The separation of security boundaries and approvals in OpenAI products.
- CPython, issue #156512, PR #156657 and the approval. A concrete report showing reproduction, explicit uncertainty, a bounded change and check results.
- Anthropic Claude Code, issue #76132. A user's self-report of ambiguous continuation after manual steps; not a confirmed universal defect.