Most agent bugs begin as innocent changes. A developer adds one tool, moves a routing condition, or swaps a model. The pull request looks small, but the agent's actual behavior is now spread across prompts, callbacks, graph nodes, tool handlers, and session code.
Declarative agent orchestration puts the behavior you need to review in one structured definition. The runtime still executes code, but your team can see the agent's inputs, tools, triggers, models, and execution steps before it runs. That makes change control a property of the architecture instead of a meeting you hope people remember to schedule.
What declarative agent orchestration means
An agent has two kinds of logic:
- Domain logic talks to your systems. It searches a product catalog, checks an account balance, or opens a support ticket.
- Orchestration logic decides which model can act, which tools it may call, how a session begins, and what happens when an event fires.
Code is a good home for domain logic. It gives you types, libraries, tests, and direct access to your infrastructure.
Orchestration logic changes for different reasons. A product manager may tighten an approval rule. An AI engineer may change a prompt or model. A security reviewer may remove a tool from one agent. Those changes should be visible without reconstructing behavior from a call graph.
A declarative protocol turns that layer into data:
input:
COMPANY_NAME:
type: string
triggers:
user-message:
input:
USER_MESSAGE:
type: string
tools:
search-docs:
description: Search the product documentation
parameters:
query:
type: string
create-ticket:
description: Create a support ticket
parameters:
summary:
type: string
agent:
model: anthropic/claude-sonnet-4-5
backupModel: openai/gpt-4o
system: system
input: [COMPANY_NAME]
tools: [search-docs, create-ticket]
agentic: true
maxSteps: 6
loopGuard: true
handlers:
user-message:
Add user message:
block: add-message
role: user
prompt: user-message
input: [USER_MESSAGE]
display: hidden
Respond:
block: next-messageThe protocol contains no database client or ticketing API call. Your backend implements those tool contracts. The declaration shows which capabilities the model may request, while backend authorization and validation still enforce business rules such as explicit confirmation.
Why move agent workflows out of application code?
Review the behavior as a diff
Suppose a support agent may search documentation and create tickets, but it may not issue refunds. In a code-first system, that capability boundary might live partly in a system prompt, partly in a tool wrapper, and partly in a router function.
With a protocol, reviewers can inspect the tool list and the prompt change together. A pull request that expands the capability surface is obvious:
agent:
- tools: [search-docs, create-ticket]
+ tools: [search-docs, create-ticket, issue-refund]
maxSteps: 6A reviewer can now ask why the agent needs refund access, whether the backend requires approval, and which evaluation covers the change. A model change is one line. Removing a backup model does not hide inside a dependency update.
This borrows a useful idea from infrastructure as code: desired behavior belongs in a versioned, reviewable artifact. The OpenGitOps principles describe declarative, versioned state as a foundation for reliable operations. Agent definitions benefit from the same discipline even when you are not building a full GitOps reconciliation loop.
Validate before runtime
Structured definitions can be checked before deployment. A validator can catch an undeclared prompt, a missing variable, an invalid tool reference, or a malformed handler before a user discovers it.
For Octavus agents, the local loop is deliberately familiar:
npx octavus validate ./agents/support-agent
npx octavus sync ./agents/support-agentThe CLI reads settings.json, protocol.yaml, prompts, and references from the agent directory. Validation exits with 0 on success, 1 for validation errors, and 2 for configuration errors, so it can run as a required CI check. The complete workflow is documented in the Octavus CLI guide.
We validated the support protocol above against the live Octavus platform. It passed with no errors or warnings. That is a small detail, but it changes how examples should be written: documentation and pull requests can carry configurations the runtime has actually accepted.
Separate deployment speed from application changes
Agent behavior usually changes more often than the systems behind its tools. Prompt wording, model selection, allowed tools, and step limits may need several iterations while the account API stays untouched.
When orchestration lives in application code, each behavior change inherits the application's build and release path. A protocol lets teams version and deploy agent definitions independently while keeping tool implementations on their own infrastructure.
That separation also narrows rollback. If a new prompt causes poor routing, revert the definition in source control and sync it again. Unrelated backend work stays deployed.
Make the operating layer visible
Production agents need more than a call graph. They need sessions, streaming, tool boundaries, model fallback, limits, traces, and recovery behavior.
A protocol can expose these controls directly:
backupModelretries an eligible transient provider failure once with a fallback model, before streamed content reaches the client.maxStepsbounds agentic tool-call cycles.loopGuardstops repeated-output degeneration.toolsdefines the capabilities visible to the model.triggersandhandlersshow how execution starts.- Prompts and references live beside the protocol as versioned files.
The runtime can then provide consistent sessions and traces because it sees the execution plan. This is the operating-layer argument behind production AI agents: reliability improves when orchestration is a shared platform concern rather than a collection of callbacks each team rebuilds.
Keep domain logic in code
YAML is a poor place to calculate taxes, query a graph database, or implement a retry algorithm with domain-specific semantics. Keep that code where it belongs.
A practical split looks like this:
| Concern | Best home | Why |
|---|---|---|
| Model, fallback, and limits | Protocol | Easy to inspect and change |
| Prompts and reusable context | Versioned Markdown | Domain experts can review it |
| Tool permissions and schemas | Protocol | Capability changes appear in diffs |
| Business rules and data access | Backend code | Types, tests, libraries, and security controls |
| Session execution and streaming | Platform runtime | Consistent behavior across agents |
| Product-specific UI behavior | Application code | Stays close to the user experience |
This is also why declarative and code-first approaches can coexist. OpenAI describes its Agents SDK as Python-first orchestration using built-in language features. Google ADK offers predefined workflow agents for deterministic sequential, parallel, and loop execution. Microsoft Agent Framework now supports declarative YAML workflows alongside code-first workflows.
The useful choice is made at the boundary. Put reviewable agent behavior in a declaration. Drop into code where custom computation earns the complexity.
A repository layout your team can reason about
A declarative agent can live beside application code without becoming tangled in it:
agents/
└── support-agent/
├── settings.json
├── protocol.yaml
└── prompts/
├── system.md
└── user-message.md
src/
└── tools/
├── search-docs.ts
└── create-ticket.tsThis layout creates a clean review path:
protocol.yamlanswers what can run.prompts/answers what the model is told.src/tools/answers what your systems do when the agent requests an action.
A reviewer can follow an agent change without opening framework internals. Security can focus on the capability surface. Domain experts can review the policy text. Backend engineers keep ownership of data access.
Add CI checks before you add more agents
Declarative orchestration pays off when the declaration participates in normal engineering controls. Start with a short pipeline:
name: Validate agents
on:
pull_request:
paths:
- "agents/support-agent/**"
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
# @octavus/cli is pinned in package.json and the lockfile.
- run: npm ci
- run: npx octavus validate ./agents/support-agent
env:
OCTAVUS_CLI_API_KEY: ${{ secrets.OCTAVUS_CLI_API_KEY }}Then add the checks your risk profile requires:
- Require approval when a tool is added or removed.
- Compare prompt and model changes against evaluation cases.
- Keep staging and production agents in separate projects.
- Use an API key with the Agents permission in CI and a key with the Sessions permission in the application.
- Save trace links for failed evaluation runs.
- When behavior regresses, revert the source-controlled protocol and sync it again.
CI checks the agent definition while the runtime owns execution. The application keeps its domain tools and product logic.
Where declarative orchestration has limits
A protocol can become unreadable if every business decision turns into another branch. Large, deeply dynamic graphs may be clearer in code. The same is true when routing depends on algorithms your team already maintains as tested libraries.
Use three tests before moving a concern into the protocol:
- Will reviewers understand the change better here?
- Can the platform validate and trace it?
- Does the concern describe agent behavior rather than business computation?
If the answers are yes, a declaration is usually the cleaner interface. If the third answer is no, keep the logic in a tool.
The goal is a small, legible control surface for agent behavior. Business computation remains tested code.
Getting started
Start with one existing agent. Move its model, prompts, tool contracts, triggers, and limits into a protocol. Keep the tool implementations in your backend. Add validation to pull requests before expanding the pattern.
The Octavus protocol overview covers interactive agents, workers, prompts, references, and tool contracts. For the broader architecture, read what AI agent orchestration includes and how declarative agent architecture works.
Define, validate, and run an agent without rebuilding the orchestration layer in your application.
