# Design a schema

A schema tells Makra which values to return and how to assemble them. Good schemas name one concept per leaf, describe ambiguous fields, and express repeated data as arrays.

## Choose a schema form

Shorthand maps a field path to a natural-language description. Use it for small, flat results.

```python
schema = {
    "headline": "The article headline",
    "author": "The byline author name, excluding publication name",
    "published_at": "The publication date shown for the article",
}
```

JSON Schema is better when the output has nested objects or arrays. Makra supports a restricted, single-shape subset. Objects, arrays, properties, descriptions, required fields, and ordinary scalar metadata are useful. Conditional and disjunctive keywords such as `oneOf`, `anyOf`, `allOf`, `if`, `then`, `else`, and `not` are rejected because one extraction program needs one addressable output shape.

```python
schema = {
    "type": "object",
    "properties": {
        "article": {
            "type": "object",
            "properties": {
                "headline": {
                    "type": "string",
                    "description": "The article headline",
                },
                "author": {
                    "type": "string",
                    "description": "The byline author name",
                },
            },
        }
    },
}
```

## Describe meaning, not markup

Do not encode CSS selectors, class names, DOM ancestry, or guessed page wording in a description. Describe the semantic distinction Makra must make.

Weak descriptions such as "price" leave nearby concepts unresolved. Prefer "current selling price, excluding list price and shipping cost". This gives retrieval and structural learning a stable meaning even when the site's labels change.

Keep field names canonical in your application. If one call uses `review_count` and another uses `number_of_reviews`, Makra can match them semantically, but your downstream code now has two names for one concept.

## Required does not mean fabricated

A required field tells the schema what you expect. It does not authorize Makra to invent a missing value or drop an incomplete row. When the page lacks evidence, the result can contain `None`, errors, or warnings.

## Links and visible text

Append `:$link` to a field path when you need the resolved link target. Append `:$anchor` when you need anchor text. Link fields cannot be checked visually because the URL itself has no pixels, so visual validation excludes them.

```python
schema = {
    "article:$link": "The canonical article link",
    "article:$anchor": "The visible article headline",
}
```

## Keep extraction and interpretation separate

Makra returns exact document strings. Model money, dates, quantities, and enums as strings at the extraction boundary unless your application has a deliberate conversion layer.

```python
from decimal import Decimal


def parse_usd(raw: str) -> Decimal:
    return Decimal(raw.replace("$", "").replace(",", "").strip())
```

This separation gives each failure one owner. Makra answers where the value came from. Your parser answers what the string means.

Next, [extract lists and nested data](/markdown/makra-sdk/v0.0.4-beta/extraction/lists-and-nested-data).
