---
title: Schemas and result schemas
editUrl: true
head: []
template: doc
sidebar:
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

Prefactor agent schemas describe the expected shape of span payloads and span results for each span type. In SDK terms, you provide these through `httpConfig.agentSchema` and they are registered with the agent manager during initialisation. Every span type must have payload and result definitions in the activity schema; integration packages supply permissive defaults for their prefixed span types so you can start recording traces before you write tight, custom schemas.

> Schemas are used for observability and governance — they describe expected structure, and any conformance gaps are visible in the web app. The SDK records spans regardless of whether they match the schema.

Each default schema defines both `span_schemas` and `span_result_schemas`. This separation lets you validate request-side fields and result-side fields independently, which is useful when your workflows evolve at different speeds for inputs and outputs. Out of the box, the SDK defaults are permissive: they describe a generic object and allow properties you have not listed yet, so they do not block incremental instrumentation.

When you need stronger constraints, provide your own schema object in `httpConfig.agentSchema`. A common pattern is permissive definitions for chat turns (`user_message`, `assistant_message`) alongside tighter definitions for each tool span type so payloads and results match that tool's real contract.

## TypeScript example

An `agentSchema` for a conversational agent: open shapes for messages, and per-tool definitions for `web_search` and `read_file`:

```typescript
import { init } from '@prefactor/core';
import { PrefactorLangChain } from '@prefactor/langchain';

const openObject = {
  type: 'object',
  additionalProperties: true,
} as const;

const agentSchema = {
  span_schemas: {
    user_message: openObject,
    assistant_message: openObject,
    web_search: {
      type: 'object',
      properties: {
        query: { type: 'string' },
        max_results: { type: 'number' },
      },
      required: ['query'],
      additionalProperties: false,
    },
    read_file: {
      type: 'object',
      properties: {
        path: { type: 'string' },
      },
      required: ['path'],
      additionalProperties: false,
    },
  },
  span_result_schemas: {
    user_message: openObject,
    assistant_message: {
      type: 'object',
      properties: {
        content: { type: 'string' },
      },
      required: ['content'],
      additionalProperties: true,
    },
    web_search: {
      type: 'object',
      properties: {
        results: { type: 'array' },
      },
      required: ['results'],
      additionalProperties: true,
    },
    read_file: {
      type: 'object',
      properties: {
        contents: { type: 'string' },
      },
      required: ['contents'],
      additionalProperties: false,
    },
  },
};

const prefactor = init({
  provider: new PrefactorLangChain(),
  httpConfig: {
    apiUrl: process.env.PREFACTOR_API_URL!,
    apiToken: process.env.PREFACTOR_API_TOKEN!,
    agentIdentifier: '1.0.0',
    agentSchema,
  },
});
```

## Python example

The Python SDK follows the same schema model. Pass your schema as `agent_schema` in the client config:

```python
import os
from prefactor_core import PrefactorCoreClient, PrefactorCoreConfig
from prefactor_http import HttpClientConfig

OPEN_OBJECT = {"type": "object", "additionalProperties": True}

agent_schema = {
    "span_schemas": {
        "user_message": OPEN_OBJECT,
        "assistant_message": OPEN_OBJECT,
        "web_search": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "max_results": {"type": "number"},
            },
            "required": ["query"],
            "additionalProperties": False,
        },
        "read_file": {
            "type": "object",
            "properties": {
                "path": {"type": "string"},
            },
            "required": ["path"],
            "additionalProperties": False,
        },
    },
    "span_result_schemas": {
        "user_message": OPEN_OBJECT,
        "assistant_message": {
            "type": "object",
            "properties": {
                "content": {"type": "string"},
            },
            "required": ["content"],
            "additionalProperties": True,
        },
        "web_search": {
            "type": "object",
            "properties": {
                "results": {"type": "array"},
            },
            "required": ["results"],
            "additionalProperties": True,
        },
        "read_file": {
            "type": "object",
            "properties": {
                "contents": {"type": "string"},
            },
            "required": ["contents"],
            "additionalProperties": False,
        },
    },
}

config = PrefactorCoreConfig(
    http_config=HttpClientConfig(
        api_url="https://app.prefactorai.com",
        api_token=os.environ["PREFACTOR_API_TOKEN"],
        agent_schema=agent_schema,
    )
)

client = PrefactorCoreClient(config)
await client.initialize()
```

See the [Python SDK reference](/sdks/python-sdk/api/core) for the exact parameter names.

## Activity schema in the web app

The schema you register from the SDK appears in the **Activity schema** tab of the agent in the Prefactor web app. The span type identifiers you define (for example `user_message`, `assistant_message`, `web_search`) correspond to the span types shown there. See the [Agent › Activity schema tab](/admin-ui/agent/activity-schemas) to view deployed schemas and their validation status.