Framework Support for Manifest Agents
Every agent in waxell.yaml declares a framework:, either on the agent or
once under defaults:. On the hosted runtime that value decides how a run
executes. This page lists what each value gives you.
All frameworks share the same platform: signals start runs, every model call
and tool call is governed by your policies, and every step lands in the run's
trace and event stream. Runs
can carry an end user (_sub_user_identity), and the run's wall-clock cap
(timeout_seconds, default 300, max 3600) applies.
There are two ways an agent executes. Declaratively, the runtime drives the
agent from the manifest alone — the rows below. From your code, when the
manifest sets source and entrypoint:
the runtime builds the agent its own container and runs your LangGraph graph,
pydantic_ai Agent, CrewAI Crew or callable there. See
Run your own code.
At a glance (declarative)
framework: | Executes | Tools | Caps honoured | Notes |
|---|---|---|---|---|
claude_agent_sdk | The Claude Agent SDK, inside an isolated container per run | Claude Code built-ins you list (Read, Write, Edit, Bash, Glob, Grep, WebSearch, WebFetch, …), your custom tools, and your domains as <domain>__<action> | max_turns (default 25), max_budget_usd (default 10.0), timeout_seconds, plus budget policies | Every tool call is policy-checked before it executes. model: pins the SDK's model. With no built-ins listed, the agent gets Read, Glob, Grep. |
langgraph | A governed tool loop driven from the manifest's prompt and tools, for the graph's entry node | Your domains, one tool per action, named <domain>__<action> | Budget policy, timeout_seconds | Entry node = entrypoint: / entry_node:, else the node marked entrypoint: true, else the first node. Its system_prompt (or instructions) and model (or llm.model) are used, falling back to the top-level fields. |
crewai | A governed tool loop driven from the manifest's prompt and tools, for the crew's first agent | Your domains, one tool per action, named <domain>__<action> | Budget policy, timeout_seconds | The system prompt is built from the first agent's role, goal and backstory, followed by the first task's description. Model from that agent's model (or llm.model), else the top level. |
pydantic_ai | A governed tool loop driven from the manifest's prompt and tools | Your domains, one tool per action, named <domain>__<action> | Budget policy, timeout_seconds | Reads top-level system_prompt and model. |
autogen | A governed tool loop driven from the manifest's prompt and tools | Your domains, one tool per action, named <domain>__<action> | Budget policy, timeout_seconds | Reads top-level system_prompt (or system_message) and model. openai_agents manifests run the same way. |
Accepted spellings: claude-agent-sdk; langgraph-supervisor;
crew-ai / crew_ai; pydantic-ai / pydanticai;
autogen-agentchat / autogen_agentchat; openai-agents / openai_agents.
claude_agent_sdk: the SDK in a container
The run starts a container with the Claude Agent SDK and hands it the
manifest's system_prompt, model, allowed tools and caps. The SDK drives its
own agent loop. Waxell governs it from the outside:
- Before each tool call, the SDK asks Waxell's policy engine. A denied call never executes.
- Built-in tools run inside the container. List only the ones the agent needs; see Ship a Claude Agent.
- Custom tools declared in your manifest (see Build & Push a Custom Tool), and domain actions
from
domains: [...], are bridged into the SDK over MCP. Domain actions are named<domain>__<action>; the SDK may show them with anmcp__…prefix. Calls to your domains carry signed end-user tokens when the run has an end user. - Caps:
max_turnsandmax_budget_usdare passed to the SDK, and the run stops when either is reached.timeout_secondsis enforced on the container.
agents:
- name: release_notes
framework: claude_agent_sdk
model: anthropic:claude-sonnet-4-6
tools: [Read, Grep, WebFetch]
domains: [changelog]
max_turns: 12
max_budget_usd: 4.0
timeout_seconds: 600
langgraph, crewai, pydantic_ai, autogen: the governed tool loop
For these frameworks the runtime reads the manifest and runs the agent itself. It sends the system prompt and the signal payload to the model through Waxell's LLM router, executes the tool calls the model asks for, and feeds the results back:
- One node or agent per run. For a LangGraph manifest that's the entry node; for a CrewAI manifest it's the first agent, with the first task as context. When a manifest declares more nodes or agents, the run's event stream includes a note naming the one that ran.
- Up to 8 model ↔ tool rounds per run. The model's final answer is the run's result.
- Tools: every action of every domain in
domains: [...]becomes a tool named<domain>__<action>, with its parameters taken from the action'srequest_schema. Calls go through the same domain path as every other framework: credentials, policy checks, timeouts, and end-user tokens. - With no
domains:and notools:, the run is a single governed model call, and the answer streams into the run's events as it's generated. - Model:
model:inprovider:modelform, routed through your workspace's LLM provider configuration. When omitted, the model isopenai:gpt-4o-mini. - Caps: spend is governed by budget policies
evaluated during the run, and
timeout_secondsstops the run at the deadline.
agents:
- name: ticket_router
framework: langgraph
entrypoint: classify
domains: [tickets]
nodes:
- name: classify
model: anthropic:claude-sonnet-4-6
system_prompt: |
Classify the ticket, then assign it with the tickets tools.
- name: escalate
system_prompt: Escalate to on-call.
timeout_seconds: 120
agents:
- name: research_crew
framework: crewai
domains: [crm]
agents:
- role: Account researcher
goal: Summarise an account's open opportunities
backstory: You work for the sales team and are precise about numbers.
model: openai:gpt-4o
tasks:
- description: Pull the account and list open opportunities by stage.
Run your own code
Add source (your code) and entrypoint (module:attr inside it) to the
agent, and the framework value becomes provenance: the runtime no longer drives
a loop from the manifest, it runs your program.
agents:
- name: reviewer
framework: langgraph
source: ./agents/reviewer
entrypoint: graph:app # a compiled StateGraph
dependencies:
pip: [langgraph>=0.2, langchain-anthropic>=0.3]
signals:
- name: review.requested
# agents/reviewer/graph.py
from langchain_anthropic import ChatAnthropic # reads ANTHROPIC_BASE_URL / _API_KEY
from langgraph.graph import StateGraph, MessagesState, START, END
llm = ChatAnthropic(model="claude-sonnet-4-6")
def review(state: MessagesState):
return {"messages": [llm.invoke(state["messages"])]}
g = StateGraph(MessagesState)
g.add_node("review", review)
g.add_edge(START, "review")
g.add_edge("review", END)
app = g.compile()
What you get:
- Your code, in its own container, built on
wax pushfromdependenciesandsource. A fired run waits for the build the first time and starts when the image is ready. - Governed model calls with no instrumentation. The container's
ANTHROPIC_BASE_URLpoints at the run's proxy, so theanthropicSDK,langchain-anthropicandpydantic-aiall go through Waxell: policy checks on the actual prompts, tokens and cost on the run page, and your real key never in the container. Code agents use Anthropic models. - Run-level governance.
before_workflowpolicies run before your process starts;after_workflowpolicies run on what it returned;timeout_secondskills it at the deadline. - The run's result is your program's return value (see the dispatch table in the reference).
Every framework's code is supported the same way; the dispatch follows what the
entrypoint resolves to, not the framework: value. A pydantic_ai agent:
agents:
- name: triage
framework: pydantic_ai
source: ./agents/triage
entrypoint: agent:triage
dependencies:
pip: ["pydantic-ai-slim[anthropic]>=0.4"]
# agents/triage/agent.py
from pydantic_ai import Agent
triage = Agent("anthropic:claude-sonnet-4-6", system_prompt="Triage the ticket.")
The payload's prompt (or input, message, query) is passed to
run_sync; the result is .output.
Choosing a framework
-
Choose
source+entrypointwhen you have working agent code and want it to run as written, governed and observed, without re-expressing it as a manifest. -
Choose
claude_agent_sdkwhen the agent needs file and web built-ins, a long agentic loop, or an SDK-native turn and dollar cap. -
Choose any other value when you're bringing an existing agent's prompt, model and tool contract across and want it to run governed against your domains. The framework value keeps the agent's provenance visible in the catalog and in every trace.
Related
- waxell.yaml reference: every manifest field, including limits
- Register a Domain: the tools every framework can call
- Build & Push a Custom Tool
- Your first agent with
wax init