> ## Documentation Index
> Fetch the complete documentation index at: https://platform.autumn.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured output

> Get typed objects back from a task with a Pydantic or Zod schema.

Pass a schema and the SDK shapes the task's research output, then validates the returned
rows into typed objects. Use a wrapper model with a single list field: each item is one
output row.

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from pydantic import BaseModel
  from autumn_sdk import AutumnClient

  class Startup(BaseModel):
      company: str
      domain: str
      notes: str

  class Startups(BaseModel):
      startups: list[Startup]

  client = AutumnClient()
  result = client.run(
      "Find 20 AI infrastructure startups hiring founding engineers",
      output_schema=Startups,
  )
  for s in result.output.startups:
      print(s.company, s.domain)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { AutumnClient } from "autumn-sdk";
  import { z } from "zod";

  const Startup = z.object({ company: z.string(), domain: z.string(), notes: z.string() });
  const Startups = z.object({ startups: z.array(Startup) });

  const client = new AutumnClient();
  const result = await client.run<{ startups: z.infer<typeof Startup>[] }>(
    "Find 20 AI infrastructure startups hiring founding engineers",
    { schema: Startups },
  );
  for (const s of result.output.startups) console.log(s.company, s.domain);
  ```
</CodeGroup>

<Note>
  TypeScript requires **Zod v4** (`npm install zod@4`).
</Note>

## How it maps

The SDK converts your schema into the task's `output.schema` (a flat, canonical research
schema) on the way in. On the way out it flattens each "cell" row (fields come back as
`{value, source_id}`) to plain values and validates them against your schema. Rows that
fail validation are dropped, so `result.output` only contains well-formed objects. The raw
rows (with sources and provenance) remain available on `result.rows`.

A schema with no wrapper is treated as the row itself, so `result.output` is then a list of
that model.

## Under the hood

This is the same `output.schema` you can pass directly via a [task spec](/docs/api-routes#start-from-a-task-spec).
The SDK schema is a convenience over it. Supported field types resolve to `str`, `int`,
`float`, `bool`, and `list[...]`.
