---
title: "The document"
description: "The top-level shape of a design.yaml — the schema line, meta, units, catalogue pins, and the order the ten sections appear in."
url: https://kaicad.barpom.xyz/docs/schema/the-document
schema: "0.1"
source: packages/spec/src/design.ts
---

# The document

A design is one YAML file. It is **pure data** — there is no `kind: custom`, no inline code
and nothing that executes, so a `design.yaml` is always safe to open and safe to share.

```yaml
schema: furniture-cad/v0.1

meta: { ... }          # who and what this is
units: mm              # metric only
catalogs: { ... }      # which catalogue versions to compile against
parameters: [ ... ]    # the numbers a person would change
requirements: { ... }  # design intent the validator can check
materials: [ ... ]     # the stock this piece is made from
parts: [ ... ]         # blanks, and what is cut into them
joints: [ ... ]        # what touches what, and with which hardware
assembly: { ... }      # which part is held still, and how it comes apart
outputs: { ... }       # what to draw and export
```

`materials` and `parts` are the only sections that are required. A document with no `joints`
compiles — you get a pile of parts at the origin — which is occasionally what you want while
you are working out blank sizes.

## The order does not matter, but write it this way anyway

YAML mappings are unordered and the resolver does not care. References are resolved **lazily**:
a parameter may reference a material, a material may reference a parameter, and a part may
reference another part. There is no phase ordering to obey, and a genuine loop is reported as
[`RES-003`](/docs/validation/error-codes#res-003) naming the actual cycle.

Write the sections in the order above regardless. It is the order the pages here follow, the
order the authoring pack emits, and it reads top-down: the numbers, then the stock, then the
parts, then what holds them together.

## `schema:`

```yaml
schema: furniture-cad/v0.1
```

Required, and the first line. It is how a file written against an older version of this
reference is recognised as such rather than mis-parsed.

## `meta:`

```yaml
meta:
  id: walnut-platform-bed-queen
  title: Walnut slatted platform bed — Queen
  description: >
    A knock-down platform bed in solid walnut with a panelled headboard. Rails
    bolt to the posts so the whole thing comes apart to get up a staircase.
  author: claude-cad
  tags: [bed, knock-down, slatted, walnut]
```

| Key | | |
| --- | --- | --- |
| `id` | required | Stable identifier. **Keep it across repairs** — it is how the app recognises a re-emitted file as the same design rather than a new one. |
| `title` | required | What a person calls the piece. |
| `description` | | Prose. Reaches the drawing's title block. |
| `author` | | Free text. |
| `created` | | ISO date. |
| `tags` | | Free-text list, for the design library. |

## `units:`

```yaml
units: mm
```

Optional, and `mm` is the only accepted value. It exists so that a file written in inches is
**rejected with a clear message** rather than compiled into a piece of furniture forty times
too large. Every number in the document is millimetres, except angles, which are degrees.

See [Units and precision](/docs/schema/units-and-precision).

## `catalogs:`

```yaml
catalogs:
  materials: std/lumber@1
  fixtures: std/fixtures@1
  standards: std/standards@1
```

Pins which catalogue the ids in this document resolve against. This is the closest thing the
format has to an import: nothing is copied into your file, and the catalogue is not something
you author — you name a version of it and then reference entries from `materials`, `joints`
and `parameters`.

All three keys are optional and default to the bundled `std/…@1`. Unless you have a reason,
leave them at the defaults or omit the section.

What each family contains, and how a reference resolves, is
[How the catalogue works](/docs/catalogue/how-the-catalogue-works).

## The rest

Each of the remaining sections has its own page:

- [Parameters and expressions](/docs/schema/parameters-and-expressions) — the numbers, and the
  only computation in the format
- [Requirements](/docs/schema/requirements) — intent the validator can check
- [Materials](/docs/schema/materials) — narrowing a catalogue family to a real board
- [Parts](/docs/schema/parts) — blanks, grain and instances
- [Features](/docs/schema/features) — what is cut into a blank
- [Anchors](/docs/schema/anchors) — the placement model, and the concept to read first
- [Joints](/docs/schema/joints) — what touches what
- [Arrays](/docs/schema/arrays) — slats, shelves, pickets
- [Assembly and outputs](/docs/schema/assembly-and-outputs) — the ground part, groups, exports

## A complete, minimal document

Two parts, one screw, nothing derived:

```yaml
schema: furniture-cad/v0.1

meta:
  id: shelf-and-cleat
  title: One shelf on one cleat

units: mm

materials:
  - id: pine
    from: lumber.softwood.s4s
    species: pine
    thickness: 25
    width: 195

parts:
  - id: shelf
    material: pine
    grain: length
    blank: { length: 800, width: 195, thickness: 25 }

  - id: cleat
    material: pine
    grain: length
    blank: { length: 800, width: 40, thickness: 25 }

joints:
  - id: shelf_to_cleat
    kind: screwed
    fixture: fixtures.wood_screw.4x50
    through: shelf
    mate:
      a: shelf:face.bottom
      b: cleat:face.top
      align: { contact: true }
    fasteners:
      pattern: { along: length, count: 4, spacing: auto, margin: 60 }

assembly:
  ground: cleat
```

That compiles, and the validator has something to say about it — which is the point.
