# Schema Reference

The schema is the file `tiroir.yaml` at the root of a store. It declares the store's identity and every drawer type. This page lists every key. To build one step by step, follow [Custom Schema](<https://ancelin-code.github.io/tiroir/install/custom-schema/index.md>).

The file is YAML, UTF-8, one document. Anchors, aliases, tags and several documents are refused. **An unknown key is an error**, so that a typo or a wrong indentation never silently disables a rule. Paths are relative to the store's root and use `/`.

## Top level

| Key | Type | Required | Meaning |
| --- | --- | --- | --- |
| `tiroir` | integer | yes | The version of the file format. `1`. |
| `store.id` | UUID | yes | The store's identity, generated by `stores add`. Never changes. |
| `store.name` | slug | yes | The short name shown in results, such as `acme`. |
| `store.audience` | `personal` or `team` | yes | Who reads the store. |
| `store.language` | language code | yes | The memory language, such as `en` or `fr`. |
| `store.description` | text | no | One line on what the store holds. |
| `shared.path` | path | no | The folder of the shared space. Default `shared`. |
| `shared.topics` | list of text | no | What the shared space is about. |
| `shared.conventions` | path | no | The shared document Claude reads first. Default `shared/conventions.md` when it exists. |
| `context.conventions_max_tokens` | integer | no | A cap on the size of that document. Default 1500. |
| `drawer_types` | mapping | yes | The drawer types, at least one, each under `drawer_types.<name>`. |

In a preset, the `store` block is a placeholder: `stores add` generates the `id` and replaces `name`, `audience` and `language` with its own arguments. Only `description` is kept, and the other values have to be valid.

## Drawer type

A type name is a slug, such as `client` or `repo`.

| Key | Type | Required | Meaning |
| --- | --- | --- | --- |
| `label` | text | yes | The human name of the type, in the memory language. |
| `label_plural` | text | no | Its plural. |
| `description` | text | no | What a drawer of this type holds. |
| `path` | pattern | yes | The folder of each drawer, such as `clients/{code}`. See below. |
| `fields` | mapping | yes | The drawer's metadata, one entry per [field](<#field>). |
| `summary.template` | path | yes | The Markdown template of a new summary. See [Templates](<#templates>). |
| `summary.sections` | list of text | yes | The level-2 headings of the summary, in order, at least one. |
| `log.template` | path | no | The template of a new log entry. Default: empty. |
| `detect.names` | list of field names | no | The fields whose values designate a drawer in a conversation. They must be `text` or `list` fields. |
| `detect.cwd` | field name | no | The field compared with the folders of the working directory, for tools that send one. |
| `inject.sections` | list of text | no | The sections put before Claude when the drawer comes up. Default: all. Each must be in `summary.sections`. |
| `inject.max_tokens` | integer | no | A cap on one drawer's injected block. Default 800. |

Most of what `detect` and `inject` drive arrives with the next release (see the [Roadmap](<https://ancelin-code.github.io/tiroir/roadmap/#2-retrieval>)). They are checked today, and you can declare them now.

### The `path` pattern

`{field}` is replaced by the **slug** of that field's value: lowercase, accents removed, every run of other characters replaced by `-`. A client named `Boulangerie Dupont & Fils` with the pattern `clients/{name}` lives in `clients/boulangerie-dupont-fils`. A pattern must contain at least one placeholder of a **required** field, and the patterns of two types must not overlap.

## Field

A field's name is a slug. `type`, `author` and `date` are reserved.

| Key | Type | Required | Meaning |
| --- | --- | --- | --- |
| `type` | see below | yes | `text`, `number`, `date`, `boolean`, `enum` or `list`. |
| `required` | boolean | no | Default `false`. |
| `values` | list of text | for `enum` | The allowed values. |
| `pattern` | regular expression | no | For `text` only. The whole value must match. |
| `default` | a value of the field's type | no | Used when a drawer is created without the field. |
| `description` | text | no | Shown in validation messages. |

A `date` is written `YYYY-MM-DD`. A `list` is a list of text. Computed fields do not exist.

## Templates

A summary template is a Markdown file that holds **exactly** the headings of `summary.sections`, in the same order, with an optional line of guidance under each. It can use `{field}` placeholders, replaced when a drawer is created. The drawer's metadata, between two `---` lines at the top of `summary.md`, is generated from the fields and is not part of the template.

## Errors

When Tiroir creates a store, it checks `tiroir.yaml` and reports **every** violation, each with its key path and its line.

| Code | When |
| --- | --- |
| `schema.invalid` | A key is unknown, a type is wrong, a required key is missing, or the YAML is malformed. |
| `schema.unsupported-version` | `tiroir` is greater than the version this server reads. |
| `schema.invalid-path` | A `path` has no placeholder of a required field, or overlaps another type's. |
| `schema.unknown-section` | `inject.sections` or a template heading is not in `summary.sections`. |
| `schema.invalid-detect` | A field listed in `detect` is neither `text` nor `list`. |

Nothing is created when there is a violation. In 0.1.0, the drawers of a preset's `data/` folder are not checked against the schema: copy the template headings exactly.
