Skip to main content

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:ExecutesToolsCaps honouredNotes
claude_agent_sdkThe Claude Agent SDK, inside an isolated container per runClaude 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 policiesEvery 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.
langgraphA governed tool loop driven from the manifest's prompt and tools, for the graph's entry nodeYour domains, one tool per action, named <domain>__<action>Budget policy, timeout_secondsEntry 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.
crewaiA governed tool loop driven from the manifest's prompt and tools, for the crew's first agentYour domains, one tool per action, named <domain>__<action>Budget policy, timeout_secondsThe 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_aiA governed tool loop driven from the manifest's prompt and toolsYour domains, one tool per action, named <domain>__<action>Budget policy, timeout_secondsReads top-level system_prompt and model.
autogenA governed tool loop driven from the manifest's prompt and toolsYour domains, one tool per action, named <domain>__<action>Budget policy, timeout_secondsReads 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 an mcp__… prefix. Calls to your domains carry signed end-user tokens when the run has an end user.
  • Caps: max_turns and max_budget_usd are passed to the SDK, and the run stops when either is reached. timeout_seconds is 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's request_schema. Calls go through the same domain path as every other framework: credentials, policy checks, timeouts, and end-user tokens.
  • With no domains: and no tools:, the run is a single governed model call, and the answer streams into the run's events as it's generated.
  • Model: model: in provider:model form, routed through your workspace's LLM provider configuration. When omitted, the model is openai:gpt-4o-mini.
  • Caps: spend is governed by budget policies evaluated during the run, and timeout_seconds stops 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 push from dependencies and source. 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_URL points at the run's proxy, so the anthropic SDK, langchain-anthropic and pydantic-ai all 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_workflow policies run before your process starts; after_workflow policies run on what it returned; timeout_seconds kills 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 + entrypoint when 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_sdk when 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.