The decision
- Context
- Our enterprise AI application is TypeScript from the browser to the server, and many teams publish agents onto one platform. Every run needs the same controls, and the interface has to follow each run step by step. We wanted the orchestration in that stack, on an execution layer we own.
- Options weighed
- An agent framework, with our controls built around it
- Our own TypeScript execution layer chosen
- Consequences
- One language and one set of types from the execution layer to the interface.
- Controls such as budgets, retries and approvals become platform rules every team's agent inherits, not code each team writes.
- The roadmap is ours: protocol changes, model features and security fixes arrive when we build them, not when a framework ships them.
- At near-parity with the established frameworks, a migration would buy little and cost every team a rewrite, so we stayed.
Context
We started building our orchestration layer almost two years ago, for an enterprise AI application that is TypeScript end to end. Teams publish their own agents onto the platform, ground answers in the organisation's documents and records with citations, and hand work one agent cannot finish to a multi-agent mesh.
Why our own
Two reasons decided it.
It stays with the frontend. The application is TypeScript from the browser to the server, and so is the orchestration. The interface follows a run as it happens using the same types the execution layer emits, so a new kind of step ships as one change instead of a change in two languages plus a contract between them.
We own the execution layer. How a step runs, how often it retries, when it stops and when it waits for a person are platform decisions, not per-agent choices. Owning the layer means every team's agent gets the same rules.
What an owned execution layer has to provide
Frameworks offer most of the pieces. A platform that owns its execution layer has to wire them together itself, and these are the parts that matter most:
- Controls applied by the platform: budgets, timeouts, retries and approval before writes, enforced for every agent rather than written into each one.
- Run events typed once: steps, tool calls, approvals and citations, shared with the interface so it can render a run as it happens.
- Hand-offs under the same controls when one agent passes work to another.
- A trace for every step, emitted through OpenTelemetry into the platform's observability stack.
What it costs
Owning the layer means owning its roadmap. New protocols, model features such as structured outputs, and security fixes arrive when the platform team builds them rather than when a framework releases them. New engineers learn this layer instead of a framework they may already know, and evaluation and tracing tools built for the popular frameworks need an adapter before they work here. That maintenance is the price of the two reasons above, and it has to stay smaller than the platform work it protects.
Why we stayed
We kept maturing the layer for almost two years, and today it is almost in line with the established frameworks. That is why we stayed on it: moving now would buy parity rather than progress, and every team's agents would have to move with it. We keep comparing.
When we would revisit
- A framework runs in our TypeScript stack and carries our controls and run events without a fork.
- A capability we need ships in a framework and cannot be built cheaply here.
- Keeping the layer current starts to crowd out the platform work it exists to serve.
Key takeaways
- Put orchestration in the application's language when the interface has to follow a run step by step.
- The execution layer is where platform rules live. Owning it is how every team's agent gets the same controls.
- Re-check against the frameworks on a schedule. At parity, a migration has to buy more than it costs.
About this decision note
- Format
- Decision note
- Level
- Architect
- Read
- 2 min read
- Published
- Oct 17, 2026
- Disciplines
ADR-style: context, options, the call, consequences.
More on these topics
Comparison · · 1 min read
LangGraph vs writing the agent loop yourself
Two ways to write the same supervisor, an explicit state graph or a loop your own code owns on the model API. Compared on control flow, tracing, testing, checkpointing and what each makes hard.
Deep dive · · 7 min read
Every question your AI readiness review asks was answered months ago
The last six days of a sixty-day series, and the pattern is that operability gets bought early or it does not get bought at all.
Checklist · · 24 checks
Working with Claude, practices that hold up
Prompting, agents and tools, Claude Code, evaluation and safety. The habits that make Claude-based systems reliable, as a checklist you can run against your own setup.
Discussion