# ClaudeAgent and CodexAgent return typed objects with output_schema

> Pass a Pydantic model or a JSON Schema dict as `output_schema` to an Agno `ClaudeAgent` or `CodexAgent`, on the agent or per run, and `run.content` comes back parsed.

- Published: 2026-10-12
- Author: Yash Pratap Solanky
- Categories: Changelog
- Canonical: https://www.agno.com/blog/claudeagent-and-codexagent-return-typed-objects-with-output-schema
- Markdown: https://www.agno.com/blog/claudeagent-and-codexagent-return-typed-objects-with-output-schema.md

Agno's `ClaudeAgent` sends the schema to Claude Code as a `json_schema` output format and parses the object Claude delivers through its structured output tool, a call that stays out of the run's tool history. `CodexAgent` turns a Pydantic model into a strict schema, with `additionalProperties: false` and every field required, and parses only Codex's final answer, skipping its commentary. Both set `content_type` as `Agent` does, to the model's class name or to `dict` for a JSON Schema.

A per-run `output_schema` overrides the agent's, and the `output_schema` form field on the AgentOS runs endpoint now reaches external agents too. When the answer doesn't fit the schema, the run keeps the text and Agno logs a warning.

```python
from pydantic import BaseModel
from agno.agents.claude import ClaudeAgent

class Capital(BaseModel):
    city: str
    country: str

agent = ClaudeAgent(id="claude", output_schema=Capital)
run = agent.run("Capital of France?")
print(repr(run.content), repr(run.content_type))
```

Against the fake Claude SDK from the release's tests, standing in for Claude Code:

```text
Capital(city='Paris', country='France') 'Capital'
```

Code that read Codex's dict schema output as a string needs one change. Earlier releases returned the raw JSON text, and `CodexAgent` now returns the parsed dict. Here is the same run on both, with the release's fake Codex SDK answering:

```python
schema = {
    "type": "object",
    "properties": {"title": {"type": "string"}, "year": {"type": "integer"}},
    "required": ["title", "year"],
}
run = CodexAgent(id="codex", output_schema=schema).run("Invent a movie set on Mars.")

# Before
# content: '{"title": "Red Dust", "year": 2031}'
# content_type: 'str'

# Now
# content: {'title': 'Red Dust', 'year': 2031}
# content_type: 'dict'
```

The schema has to describe a JSON object. Agno checks the root when you build the agent and again on each run, and refuses an array or scalar before any SDK call. With both SDKs installed:

```python
from typing import List
from pydantic import RootModel

class Names(RootModel[List[str]]):
    pass

ClaudeAgent(id="claude", output_schema=Names)
# ValueError: ClaudeAgent output_schema must describe a JSON object (got type 'array'); wrap a list or scalar in a model field

CodexAgent(id="codex", output_schema={"type": "array", "items": {"type": "string"}})
# ValueError: CodexAgent output_schema must describe a JSON object (got type 'array'); wrap a list or scalar in a model field
```

Earlier releases built that `CodexAgent` without complaint and left the array schema for the API to reject.

See the [cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/frameworks/claude-agent-sdk/structured_output.py), and learn more about [structured output for Claude and Codex](https://docs.agno.com/agent-os/multi-framework/structured-output) in the documentation.
