Extension and Knowledge Systems

Building Your Own Orchestrator: Architecture for Reliable Agent Execution

How to judge whether you need your own agent orchestrator, which responsibilities it consists of, what it must record to recover from failure, and how to…

Chapter 73Extension and Knowledge Systems

Imagine an agent that has to pick up a task from Jira, investigate the repository, change the code, run the checks, hand the result to an independent reviewer and prepare a pull request. If everything happens in one process over a network that never fails, this can be a handful of functions and model calls. But what should happen if the process restarts just after creating the pull request, the requirement changes halfway through the work, or two copies of a worker pick up the same job?

An orchestrator is a system that stores the intent of the work, decides the next permitted action, assigns it to an executor and verifies the result. In a system with agents, some decisions can be delegated to a model, but state, permissions, limits and acceptance conditions must remain understandable and verifiable. A collection of prompts does not create reliability by itself.

This unit shows how to judge whether you need your own orchestrator, which responsibilities to build it from, what to record so you can recover after a failure, and how to stop a retry, a stale worker or a failed reconciliation from causing a side effect. It builds on the agent loop from agent SDKs and APIs, task contracts from agent task contracts, parallel work from parallelism and agent observability. It describes a control system; it does not propose building or deploying any particular framework.

First decide whether it is worth building

Your own orchestrator makes sense when there is a specific, recurring need that no existing product or library covers: unusual integrations, processes lasting hours or days, requirements to store state yourself, control over permission boundaries, custom recovery rules, or the need to combine deterministic business steps with model decisions. It can be justified when the cost of manual repetition and errors is higher than the cost of building and operating it.

The starting alternative is often simpler:

Option What it already gives you What remains the team's responsibility
A ready-made agent development product A working interface, a tool loop and known launch rules Integration with your own process, the source of truth and permission boundaries
An agent software development kit (SDK) A library or runtime for the loop of model, tools, transitions and sometimes state The domain process, external side effects, full recovery and product policies
A managed agent application programming interface (API) A hosted agent loop, sessions and events under a specific service contract Your own tools, data, connection to the product, result verification and the service's limits
A deterministic workflow Predefined steps, conditions, retries and error handling Only those uncertain decisions that genuinely need a model
Your own orchestrator Precise control over a specific process and its state Design, security, storage, queues, monitoring, on-call and compatibility maintenance

Products change; the examples, checked on 10 October 2026, show how responsibility is divided between product and application, and are not a recommendation of any particular vendor. The OpenAI Agents API documentation describes a managed Codex harness with session state, orchestration and recovery; the application still has to supply the tools and choose the runtime environment. The Responses API leaves the loop to the application's owner, and the Codex SDK runs the harness on the owner's infrastructure. The Anthropic Managed Agents documentation separately describes a beta service with events and sessions. None of these names means the provider automatically understands your acceptance criteria, your rights to take a business action or the canonical state of an external task. Look past the word "agent" to the table: what the service stores, what it can recover, which actions it triggers and what is left to your program.

Fully worked example 1: a daily report and ten agents. Every morning a team counts open support requests by queue, groups them by priority and sends one report to an internal channel. Someone proposes ten agents for this: a dedicated planner, five analysts, three checkers and a coordinator.

First we pin down the result: one report by nine in the morning, counts that are comparable because they use the same filters, a link to the source, and a notice if the support system is unavailable. A request to the support system's API returns exact records; a few ordinary functions compute the figures; a template produces the text; one step publishes it. An extra model call can briefly explain an unusual change, but its text does not change the record counts.

The result is observable: one report, a recorded data window, the counters and the delivery status. Before publishing, the system stores a report key built from the date and channel. If the process crashes after sending, the retry looks for the message by that key or uses the target API's documented idempotency key. If it finds exactly one match, the orchestrator records a link to it and does not send a duplicate. If the target system offers no reliable way to check or deduplicate the result, the uncertain state blocks the retry until it is reconciled. Ten agents would add the complexity of scheduling, of reconciling diverging counts, of model costs and of investigating failures, but they would not make the data source any more accurate. For a daily report, a deterministic process is easier to verify and cheaper to maintain. If, on the other hand, the team receives different complex questions every day that need interpretation of text, a model can be added to the explanatory step alone, and its benefit measured. This choice does not rule out future expansion: it defers it until there is a measured need.

Do not start your own system with a universal framework "for every future case". Start with one process, agree on the evidence of completion and describe the cost of an error. If a ready-made agent product cannot provide the integration you need or does not store the business state you need, that identified gap becomes the argument for your own control layer.

Components are responsibilities, not microservices

An orchestrator can be a single program with modular functions or several services. It is worth splitting it into services only when there is a separate requirement for scaling, isolation, ownership or life cycle. What matters are the boundaries of responsibility:

Responsibility The question it must answer Typical output
Task intake Who created the work, and where is its canonical record? A task identifier and the initial contract
Contract validation Are the requirements, baseline, scope and criteria complete? A validated request, or a blocked one with a reason
Scheduler Which permitted step is ready, and what are its dependencies? The next job to execute
Queue How does work wait for an executor and come back after a failure? A message carrying the work key, not the entire state record
Worker How is the delegated step carried out within its boundaries? An artefact, a tool result or an explicit error
Tool registry Which arguments, resources and actions are available? A checked call with a defined access level
Reviewer Against which independent criteria is the artefact accepted? A conclusion with links to evidence and open questions
State store What is the current fact about the work? A state version, an event log, reconciliation keys and links
Cost and access control When should it stop, and is this effect allowed? A decision about a boundary, a limit or a pause for a human
Monitoring How will an operator learn about a failure, a delay or a result? Events, metrics and alerts without unnecessary private content

The orchestrator owns the order and conditions of transitions; the worker carries out the assigned action. The scheduler can be deterministic code: it checks whether dependencies, limits and permission are in place, and then hands out work. A model can propose a plan or explain a trade-off; its plan must be normalised into checked steps, not turned directly into a right to write anywhere.

For your own agents you need to keep the distinction between "the model proposed a tool", "the tool started executing", "the external system confirmed the write" and "the orchestrator verified the desired state". The text of a final answer does not replace confirmation from the target system. For example, the line "pull request (PR) opened" does not prove that the PR exists in the right repository, has the correct base or contains the expected revision.

The task contract sets a fixed frame

A task contract is a versioned record of the agreement about a specific piece of work. It contains the goal, the boundaries, the sources of truth, the acceptance criteria, the baseline revision (for example a commit, a document version or a data snapshot), the permitted actions, the owner, the deadline or budget, and the expected evidence of the result.

A contract differs from a prompt in that the system enforces it. Before launch, a validator checks the required fields and boundaries. Every step stores the contract version it worked with. If a requirement changes, a new version is created; the orchestrator marks which executions are now stale, stops new writes under the old version and assesses the artefacts already produced. It does not rewrite the task's history after the fact.

Here is an example of the structure, not the schema of any specific API:

PSEUDOCODE
contract = {
  task_id: "review-481",
  version: 3,
  goal: "Review the change to invoice processing",
  sources: ["repository@commit-abc", "ticket-481"],
  acceptance: ["required checks green", "review evidence attached"],
  allowed_actions: ["read repository", "edit isolated branch", "run approved checks"],
  forbidden_actions: ["merge", "publish", "change permissions"],
  budget: { max_model_calls: 12, deadline: "<task-specific timestamp>" }
}

The schema checks types and required values; authorisation separately checks whether this user and this run may read this particular repository. A contract is not a permanent guarantee: permissions can be revoked, a source can become unavailable, and a branch can change. Before every external action, its resource and the validity of the permission are checked again.

State must change according to rules and evidence

A state machine is a list of permitted states and the rules by which work moves between them. The table below is a teaching model. A real process may be shorter or have additional states, as long as the team has defined what they mean.

State Transition event Condition Responsible Evidence of the transition
created contract submitted identifier is unique, minimum fields present task intake the request record and its source
planned plan proposed steps checked against scope and limits scheduler; a model if needed contract version and list of steps
ready dependencies satisfied the scheduled step is permitted and has an executor scheduler step key, arguments and assignment
running worker takes the lease current task and lease versions dispatcher and worker lease holder, generation number, start time
blocked a dependency or decision is missing reason recorded; a retry does not hide an unknown state orchestrator; a human resolves the domain question reason, owner and the next condition for resuming
review artefact ready source version and checks recorded worker hands over; reviewer checks links to the diff, commit and check report
accepted criteria confirmed independent review matches the contract the designated acceptance owner evidence identifiers and contract version
failed attempt limit or terminal error no automatic recovery takes place orchestrator; an operator investigates error type, attempts and reason for stopping
cancelled request cancelled new actions blocked; active work checked task owner and orchestrator cancellation event and outcome of stopping

A transition must check its condition atomically with the update of the state version. For example, two workers must not both record "I am the owner" just because each of them has just seen ready. The accepted state does not mean "the model said it is done": it requires defined evidence. For code, that might be passing checks on a specific commit plus a reviewer's conclusion; for a report, a sample from a defined period plus successful delivery.

Not every system has to store all the listed states as separate rows in a database. What matters is that it is clear whether the work is waiting, running, stopped, under review or finished, and who can confirm it.

Durable state enables recovery; conversation history alone does not

Durable state is a record that survives the end of a process and is available for continuing. An event log is an ordered list of facts about the work: contract created, step assigned, action sent, artefact received, check completed. A checkpoint is a saved snapshot of useful progress that lets you continue without recomputing earlier steps.

Before an external effect, save the intent: which task, which target system, which idempotency key and which contract version. After the response, save the observed result: the identifier of the created object, its Uniform Resource Locator (URL), its version or a receipt from the system. If the response is lost, the recorded intent gives you a point for reconciliation, but it does not tell you whether the action happened. In that case the state has to be checked with the owner of the resource.

A queue is not necessarily the source of truth. For example, Amazon Simple Queue Service (SQS) documents at-least-once delivery for standard queues: on rare occasions a copy of a message may be delivered again, so the handler has to be safe to repeat. The visibility timeout is the period during which a received message is normally hidden from other consumers; it does not guarantee the absence of duplicates, as the SQS developer guide explains separately. So a message in the queue says "try to process this", not "this action happened exactly once". Another provider or queue type will have a different contract, and it has to be read on its own terms.

Idempotency means that repeating the same logical operation with the same key does not create an unwanted additional effect. A stable key can be built from the task identifier, the step number and the contract version. It will not help if the target system ignores it, if the key has expired, or if the request parameters under that key have changed. If the destination API supports idempotency keys, use their exact semantics; if not, check the actual state before retrying, or hand the unknown outcome over for manual reconciliation.

No single log makes a distributed process atomic from end to end. A local write and an external network request do not become one transaction just because both appear in the same code. A system can deliver messages at least once while the application builds idempotent consumption on top. The label "exactly-once" in a service description calls for reading the limits of the guarantee: where exactly it applies, to which resource and within what time window.

A fully worked process and its partial failures

Fully worked example 2: a job from task definition to pull request. A team asks for a bug in one module to be fixed, compatibility with the existing API to be preserved, and evidence that the regression has been tested. The automated process has to go through these stages: task → read-only research → implementation → checks → review → pull request (PR). Every transition has an owner, a condition, a permission and evidence.

Transition What happens Permission Evidence for the next step
task → research The validator records the contract, the baseline commit and the criteria Read access only to the named repository and the linked task Contract version, commit and list of criteria
research → implementation The worker summarises the relevant files and proposes a bounded plan The same read scope; writing allowed only to an isolated branch The plan, links to sources and the list of files
implementation → tests The changed code is saved as a commit or diff Write access to the dedicated working branch; allow-listed commands Commit, names of changed files and working tree state
tests → review The required checks are run on the recorded revision Permitted tests only; changing a test to hide a failure is forbidden Log with the commit identifier and exit code
review → PR An independent review compares the diff with the contract Creating a PR in the permitted repository; no merge Reviewer result, PR URL, head and base revisions
PR → accepted The PR's existence, its current checks and the independent review against the contract are verified Read access; merging is a separate action unless it is part of the acceptance criterion Link, head and base commits, check results and the reviewer's conclusion

Each row is a separate action whose result has to be saved. If the commit changed during testing, the earlier report no longer supports the new diff. If the checks have passed but the PR check is still running, the state stays review or blocked; do not call it acceptance. A model can propose the text of the PR description, but the rule about permitted branches and the right to create a PR must live in code and server-side authorisation. In this example the process ends with one confirmed PR with evidence on the same head revision; if a check or a permission is missing, it stays blocked. The stages are separated because transitions and access must be reproducible conditions, not a model's conclusion. The table covers creating and checking the PR; merging needs its own acceptance condition and its own evidence.

Fully worked example 3: the process crashed after creating the pull request (PR). The orchestrator recorded the intent create_pr(task=481, contract_version=3, repo=org/course, owner=org, head_ref=task-481-fix, head_commit_id=abc123…, base_ref=main, base_commit_id=def456…, key=481:3:create-pr) and called the GitHub API. head_ref is the branch name and head_commit_id is the expected commit identifier on that branch; they are different values. GitHub created PR #72, but the process crashed before recording the URL and the success in the store. The restarted run sees an unfinished intent with the same key. It does not treat a timeout error as proof that nothing happened: it first reads the PRs in the target repository, searching by the permitted attributes: the repository, the branch head_ref=task-481-fix, the base base_ref=main and the state (open or closed). For a closed PR, the merged_at field shows when it was merged; an empty value means the PR was closed without merging. It then checks that the PR has the expected commit identifiers head_commit_id=abc123… and base_commit_id=def456…. The search covers every page of results. For this example the branch is unique to this task, and the scheduler serialises PR creation by its key, so two recovered workers cannot perform the write in parallel.

If exactly one PR is found and its branch, base and commit identifiers match the intent, the orchestrator records #72, the link, the revisions and a recovery event. An open PR is recovered as an existing result; for a closed one, merged_at is checked separately, and no duplicate is created automatically. If there are no matches, that is still not proof that the first request definitely failed: a retry is allowed only after the orchestrator has waited for the earlier request to finish, checked the current source, and satisfied the consistency conditions defined for the specific GitHub API, holding exclusive rights to create a PR for this branch. If the API offers no reliable way to establish that the result is absent, the system stops in blocked rather than risk a duplicate. If two candidate PRs are found, or the head is already different, the operator receives both links to resolve the ambiguity. The observable result is one confirmed link between the task and the correct PR, or an explicit blocker, not a confident message from the agent. For an external system with no key and no reliable search, an automatic retry can be dangerous; the uncertainty then has to be resolved some other way.

Below is short pseudocode. It shows the order of the checks; it is not a real GitHub method or a specific queue library. The official GitHub API for listing pull requests filters by head branch in the format owner:branch, by base branch and by state; for recovery, PRs in any state are checked, and the result has to be read through to the end of every page. After the search, the commit identifiers from the PR object are compared separately. In GitHub's response, the sha field in head and in base holds the identifier of the corresponding commit:

PSEUDOCODE
intent = store.get_pending("481:3:create-pr")
if intent:
    matches = github.find_prs(  # the method reads every page of results
        repo=intent.repo,
        head=f"{intent.owner}:{intent.head_ref}",  # GitHub format: owner:branch
        state="all",
        base=intent.base_ref,
    )
    if exactly_one(matches):
        pr = matches[0]  # stable identity: repository and head/base ref pair
        if pr.head.sha != intent.head_commit_id or pr.base.sha != intent.base_commit_id:
            mark_blocked("PR found, but its revisions have changed; review the existing PR", pr)
        elif pr.state == "open" and pr.base.ref == intent.base_ref:
            store.record_success(intent.key, pr.html_url, pr.head.sha)
        elif pr.state == "closed" and pr.merged_at != null:
            mark_blocked("PR already merged; reconcile completion, do not create a duplicate", pr)
        elif pr.state == "closed":
            mark_blocked("PR closed without merging; reconciliation needed", pr)
        else:
            mark_blocked("PR state needs review", pr)
    elif none(matches):  # only after a successful search across all pages
        retry_or_escalate_using_target_api_contract(intent)
    else:
        mark_blocked("ambiguous external result", matches)

Parallel workers need an owner and a freshness check

Concurrency is the simultaneous work of several processes on jobs that may touch shared data. A separate conversation context does not isolate the file system, the database or an API. Two workers can have different prompts and still overwrite the same row, create two PRs or use one resource at the same time.

For each unit of work, record the owner, the input version, the write scope and the dependencies. A lease is a time-limited right to process a job; once it expires, it can be granted again. A lease does not magically switch off a stuck process. An old worker can wake up after a pause and carry on with its action after a new worker has already received its lease. A generation number or a fencing token (protection against a stale owner) helps the target store reject a write from the old owner, provided that the store checks the number before every change.

Not all external APIs support fencing tokens. In that case the orchestrator has to restrict dangerous concurrent writes, use conditional updates based on revision, re-check the current state, and not let the worker decide for itself whether its permission is still valid. Parallelise independent reads or work on different files, but serialise steps that depend on a shared resource. Worktrees and isolated environments covers working trees for isolating code changes; the orchestrator must also protect other shared resources.

Fully worked example 4: a worker holds a stale contract version. The original task, version 3, requires changing only the report page; a worker has read it and produced a finished diff. Before review starts, the owner adds a requirement to validate a new field and raises the contract to version 4. The old worker keeps going, because its model still sees the earlier history.

When it submits the request for the transition implementation → tests, the orchestrator compares contract_version=3 in the message with the current version 4. The transition condition is not met. The worker does not get a new lease for writing, and its finished diff remains an artefact stamped with version 3. The scheduler determines that this diff changes only the report page and can serve as the basis for the follow-up work; a new worker receives the clean version of the requirement, the commit diff and the list of unverified criteria. It checks that the old changes are compatible with the new requirement and adds the validation, after which the tests run on the new revision.

The observable result is that the old work is not lost, but it cannot be accepted under the new contract. If the change to the requirement only renamed a button and the finished diff already matches it, re-running may be unnecessary after a controlled comparison of the criteria. If, however, the requirement concerns data access or a dangerous action, the boundaries and permissions need to be checked again. It is precisely the new contract version that lets you explain why the earlier test report is no longer sufficient.

Retry, timeout and cancellation are different decisions

A retry runs the same logical work again. Backoff (a growing delay between attempts) reduces pressure on a temporarily failing dependency; adding random variation to the delay helps prevent many clients from retrying at the same moment. A timeout limits how long you wait, but it does not prove that the other side did not perform the action. Cancellation means forbidding further work and deciding how to handle requests already sent and artefacts already partly created.

Retry only after classifying the error. Retrying a read that did not change state is usually safer than retrying a charge, a publication, a user invitation or a deployment. A retry must have a limit on count, time and cost, respect the dependency's limits, and define the next step once attempts are exhausted. When the external outcome is unknown, reconciliation comes before any retry. When the state cannot be verified, the safe decision may be to pause rather than make another call.

For a long-running operation, the team can store the wait as a state and wake up on a timer or an event. If a cloud queue is used, you need to know its acknowledgement and message visibility semantics. If a durable execution orchestrator is used, you need to know exactly what it replays after a restart and which callbacks may run again. For example, SQS explicitly warns that a received message can become available again once the visibility timeout expires; that is a property of SQS, not of every lease mechanism.

A model limit on turns or tokens is not, by itself, a budget for the whole business process. The orchestrator has to count actual requests, worker time, service usage, tool costs and waiting time. It must have a completion rule: accepted, safely blocked, rejected or cancelled. "The run did not crash" is not a sufficient condition for success.

Permissions, instructions and data are subordinate to system boundaries

A tool registry is a list of available operations with defined schemas, resources, permissions and owners. Argument validation answers whether a request has the right shape. Authorisation answers whether this particular action on this particular resource is allowed. These are different checks.

The orchestrator must apply least privilege: research gets read access only; implementation gets write access to a separate working environment; sending an external request has its own tool and its own scope; merging, publishing, deleting or changing permissions do not follow automatically from delegation. A permission is bound to the task, the target, the contract version, the scope, the time and the budget. If the revision or the resource has changed, the action must be checked again.

Text from an issue, documentation, a browser or a repository can contain hostile instructions. Such text is data to analyse, not a rule that overrides system policy. Do not pass trusted keys in an ordinary prompt and do not write them to logs. In monitoring records, keep the technical evidence you need, but not full private text unless it is needed for an investigation.

Human approval comes in where the risk or the owner of the action requires it. For that, the system must show exactly which action it is waiting to perform, on which resource, at which revision and with what consequence. The full approval policy, human roles and the management of approval fatigue are covered in human in the loop. Here the system requirement is enough: the orchestrator records who approved what and when, and re-checks that the action stays within the approved boundaries.

Independent acceptance and integration require evidence

The scheduler, the worker and the reviewer may all use language models, but saying "done" in the same words does not make them independent. Review must compare the result with the criteria and the artefacts. For a code change, check the commit, the diff, the test log, the PR's base branch and the results of continuous integration (CI). The checks must refer to the same revision that is being proposed for acceptance.

The orchestrator must be built so that a worker cannot quietly change its own acceptance criteria, switch off a safeguard or mark its own unverified result as accepted. Code checks invariants and permitted transitions; a reviewer assesses the substance of the changes against independent requirements; a human decides the defined risky or ambiguous questions. An additional reviewer is useful only when it has a different source of verification or a different criterion, not when it simply repeats the same context.

After an external integration, save its exact version: the PR link, head commit, base commit, the results of required checks and the merge status, if merging is permitted. If the main branch has moved on since the review or the checks, find out whether the evidence still applies to the proposed diff. After merging, re-read the target branch and record the actual merge commit; check that it was exactly the verified change that went in. If the merged commit has a different revision because of a squash or a rebase, keep the link between the verified diff and the new commit, and run the required checks on the actual result. "PR created" is not "code verified", and "check green" is not "code merged".

Monitoring and evaluation cover the orchestrator itself

Every job must have a correlation key, the contract version, the configuration version, a run identifier, the last confirmed state and links to artefacts. An operator must be able to see not just "the model responded with an error" but where the process stopped: in the queue, a tool, a check or an external API. Access keys, private data and the model's unnecessary hidden reasoning are not useful log fields.

Measure the share of accepted tasks, errors by type, waiting and execution time, retries, costs, manual stops, version conflicts and the share of results sent back for rework; general metric definitions are collected in agent observability. Tie the measurement to a useful outcome, such as a shorter time to a verified PR or a lower error rate, not the number of agents launched. Keep model quality separate from infrastructure reliability; otherwise a temporary queue failure will look like poor answer quality. For a temporarily unavailable dependency, define a safe fallback: postpone the step, return the result without optional enrichment, or hand the case to a human. Do not let the fallback quietly weaken the acceptance criterion. Set stop conditions for an unknown external outcome, an exceeded budget, an invalid contract and repeated errors.

Evaluating the orchestrator itself covers transition invariants, a redelivered message, a lost response after an external write, a stale contract, an expired lease, an unavailable store, cancellation and an exceeded budget. Useful controlled scenarios are those that reproduce real failure boundaries. Check that after a failure the system does not treat an unknown outcome as "not done" and does not repeat an external write without a reconciliation policy. These are tests of your job processor, not homework for the reader.

When changing the orchestrator, keep contract and event versions compatible, and record the model, SDK and tool schema versions alongside each run. Test updates first on a control set of tasks and a limited rollout; if the output format or behaviour changes, stop the rollout and go back to the known version. Do not switch a job that is already in progress to a new contract mid-way without a recorded check. If the recovery code for old jobs has changed, old records may now mean a different state. An operator runbook (a step-by-step guide to actions during a routine operation or an incident) must describe how to find a stuck task, check the external resource, pause dangerous retries, restore the queue and record a manual decision. Incident runbooks covers how a runbook is structured; the point here is that a workflow system needs its own runbook, not just the product it builds.

Orchestration, choreography and step size

In an orchestrated process, a designated coordinator knows the current step and sends the next commands. In a choreographed process, independent participants react to events without receiving each command from one central coordinator. In the first case it is easier to see the full order, but the coordinator is more tightly coupled to the components and the transition schemas. In the second, participants can evolve separately, but it is harder to reconstruct the full history and see who is responsible for completion.

This is not a choice between "correct centralisation" and "bad decentralisation". Software Architecture: The Hard Parts examines the advantages, coupling, state ownership and trade-offs between orchestration and choreography for distributed workflows. For a bounded sequence of research → code → check → review, a central coordinator can give readable states. For many independent event consumers, a more loosely coupled design may be appropriate, as long as each has a defined owner and there is a way to see the overall result. The choice depends on the consistency you need and on operational understanding.

Step size is also a trade-off. If a step is too large, it is hard to repeat without duplicating work, it holds resources for a long time, and it leaves many unknowns after a failure. If every small action is a separate model task, you get unnecessary transitions, context packages, queues and costs. Granularity is determined by whether the result can be verified, whether it needs to be recovered separately, and the cost of handing over across boundaries, not by the number of agents in the diagram.

Complexity does not disappear with parallel work

Parallel workers speed up independent steps, but coordination has its own price: synchronisation, ordering, conflict resolution, shared contracts, failure notifications and checking that results are compatible. In "No Silver Bullet", Brooks distinguishes the essential complexity of a problem, the complexity that comes from the problem itself, from the accidental complexity of a particular tool or representation. A new runtime can remove some of the accidental work of storing state, but it will not decide what "invoice verified" means or whether a requirement is complete.

Brooks's idea of conceptual integrity is useful for an orchestrator: the transition rules, the meanings of states and the permission boundaries must add up to one understandable model, even if several modules implement them. Ten models with conflicting contracts do not create clarity. Team Topologies likewise starts from the premise that human organisation should manage the flow of value, cognitive load and responsibility for a system; its team names should not be turned into mandatory classes of agents.

The orchestrator's owner must be defined independently of whoever produced the result. The owner approves the meanings of states, tracks recovery errors, makes decisions about versions and knows who can stop a dangerous action. Without such an owner, an "autonomous" system merely hides manual on-call work behind unclear messages.

Conclusion

A reliable orchestrator does not start with a number of agents. It starts with a clear task, a versioned contract, an explicit source of state and verifiable transition conditions. The system must save intent before an external action, reconcile the external fact after it, limit retries and block stale work. A model can propose a plan and explain a result; code defines invariants and permissions; a human is responsible for the anticipated high-consequence decisions. Start with a transparent process and add machinery only where an observed case justifies its cost.

Sources and further reading

External sources and changing documentation were checked on 10 October 2026. The PR and support-request examples above are teaching scenarios invented for this unit, not reports about a real product.

  • OpenAI, Agents API, Agents API overview, quickstart and changelog: the division of roles between the Agents API, Agents SDK and Responses API, including control of the loop, application tools, the environment and state; the changelog dates the Agents API's release into public beta to 10 September 2026.
  • Anthropic, Managed Agents: start a session, event stream and webhooks: current states, stored events and the limits of webhook messages; Managed Agents is marked as beta. Checked 10 October 2026.
  • GitHub, API for pull requests: the head-branch filter format, base-branch and state filters, and pagination of the list. Checked 10 October 2026.
  • Amazon Web Services (AWS), SQS at-least-once delivery and visibility timeout: the standard queue's guarantee, redelivery and the limits of the visibility period. Checked 10 October 2026.
  • Martin Kleppmann and Chris Riccomini, Designing Data-Intensive Applications, 2nd edition, O'Reilly Media, February 2026, official description and table of contents: the book's fifth, eighth and ninth chapters on durable execution and workflows, a revisited treatment of "exactly-once" message processing, partial failures, timeouts, leases and distributed systems. This unit applies those limits; the SQS example was checked separately against the AWS documentation.
  • Neal Ford, Mark Richards, Pramod Sadalage and Zhamak Dehghani, Software Architecture: The Hard Parts, O'Reilly Media, 2021, the book's eleventh chapter, on distributed workflows: orchestration/choreography trade-offs, state management, state ownership and coupling; its seventh chapter, on granularity: the forces that help define component boundaries.
  • Frederick P. Brooks Jr., "No Silver Bullet: Essence and Accidents of Software Engineering", University of North Carolina at Chapel Hill, technical report TR86-020, September 1986: the difference between essential and accidental complexity. Conceptual integrity is taken from The Mythical Man-Month: Essays on Software Engineering, 20th Anniversary Edition, 2nd edition, Addison-Wesley, 1995, Pearson publisher's page.
  • Matthew Skelton and Manuel Pais, Team Topologies: Organizing Business and Technology for Fast Flow of Value, 2nd edition, IT Revolution, 2025, official edition page: cognitive load, clear team responsibility and adaptive organisation of interactions; applied as a principle for organising human work, not as a classification of agents.
  • Anthropic Engineering, "Effective harnesses for long-running agents", 26 November 2025: the authors' own experiment with multi-session work, covering initialisation, incremental progress, a log and completion checks. The authors state explicitly that whether a single agent outperforms a multi-agent approach remains an open question; the example does not prove a universal advantage for any harness.
  • Dmitry Mezhensky, Dmitry Larko and Eugene Steinberg, Grid Dynamics, "From prototype to production-ready agentic AI solution", published on Temporal, 29 September 2025: a description of moving from hand-built Redis/Kafka state and retries to workflows with recoverable history and retry policies. The source is published by the platform vendor and contains a customer's experience; it is one described case, not an independent comparative study. The technical guarantees of SQS in this unit are confirmed separately by the AWS documentation.