Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,67 @@ without a major version bump until v1.0.

---

## [Unreleased] — 2026-06-16
## [Unreleased]

### Definitions overhaul (BREAKING)
### Frontmatter: locale/currency cleanup and template placeholders — 2026-06-17

Tightens the document-metadata model so the schema and the rendering rules agree, and adds a
reuse-first way to author templates and drafts. No new structural complexity — these changes
*remove* dangling references and *reuse* the existing `{{placeholder:}}` mechanism.

#### Changed

- **No document-level locale or default currency.** The rendering rules previously told renderers to
read "the document's locale" and "a default currency from the document metadata" (§10.2–§10.5),
but the frontmatter schema defined neither field. Formatting (date order, separators, currency
symbol) is **presentation**, so it is now explicitly a render-time setting — the **active locale**
from the render template or renderer configuration (§10.1). Currency stays per `{{money:}}`
directive; an omitted `currency` emits a validation warning and MAY fall back to a render-template
default, but there is **no document-level default currency**.

- **`identification_number` is a cross-type reserved field.** Clarified (§3.4) that
`identification_number` is the reserved field name for a registration/national identifier on **any**
party — RECOMMENDED for `legal_entity`, OPTIONAL for `natural_person` (not every individual has
one). Prefer it over a custom field so tooling can locate the identifier consistently. Documentation
clarification, not a schema change.

#### Added

- **Placeholders in frontmatter (spec §3.10).** Template and draft documents MAY use the existing
`{{placeholder:}}` directive (§10.7) as a **quoted** string value in frontmatter, reusing its ids,
types, and rendering unchanged:

```yaml
legal_name: "{{placeholder: client-legal-name}}"
effective_date: "{{placeholder: effective-date, type=date}}"
```

- Allowed in **value** fields (`title`, `legal_name`, `address`, `identification_number`,
`effective_date`, `governing_law`, …); **not** in identifier or structural fields (any `name`,
`type`, `document_type`, `sides`/`parties` structure).
- Must be a quoted YAML string (an unquoted `{{` is invalid YAML).
- A required field holding a placeholder counts as present — the document is treated as a
template/draft with unfilled blanks; a placeholder id shared with the body is the same blank.

#### Validation changes

| Rule | Before | After |
|---|---|---|
| `{{placeholder:}}` in a frontmatter identifier/structural field | — | **Added (Error)** |
| `{{money:}}` omitted `currency` looks up a *document* default | (implied) | **Removed** — no document default; warning only |

#### Files touched

- [`spec/legaldown-spec.md`](spec/legaldown-spec.md) — §3.4 (identifier note), new §3.10
(frontmatter placeholders), §10.1 (active-locale note), §10.2–§10.5 (locale wording), §10.3
(currency clause), §10.7 (cross-reference), §13.7 (locale listed among style-template settings),
§15.5 (validation row).
- [`llm/legaldown-spec-llm.md`](llm/legaldown-spec-llm.md) — Sides and Parties notes, Placeholder
section, validation summary.

---

### Definitions overhaul (BREAKING) — 2026-06-16

This revision reworks how defined terms are declared (spec §7). The goal was to support the way
lawyers actually define terms — including **inline, at first use** — while making the schema
Expand Down
5 changes: 4 additions & 1 deletion llm/legaldown-spec-llm.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ tags: [tag1, tag2] # OPTIONAL
- Party `type` is explicit: `legal_entity` or `natural_person`
- Unknown party fields are allowed and must be ignored by implementations
- Display fallback: side `label` → title-cased/pluralized `name`; party `label` → `legal_name`
- `identification_number` is the reserved field for a registration/national ID — RECOMMENDED for `legal_entity`, OPTIONAL for `natural_person` (not every individual has one); prefer it over a custom field when present
- Template/draft frontmatter MAY use `{{placeholder:}}` as a **quoted** string in value fields (e.g. `legal_name: "{{placeholder: client-name}}"`), but NOT in identifier/structural fields (any `name`, `type`, `document_type`, `sides`/`parties` structure); same id in frontmatter and body means the same blank

### Amendments

Expand Down Expand Up @@ -256,7 +258,7 @@ Value must be valid ISO 8601 (`YYYY-MM-DD`). Optional `note` provides an automat
{{placeholder: fee, type=money, currency=EUR, note=Base monthly fee}}
```

- Pure inline directive; no frontmatter declaration needed
- No separate declaration needed; appears in document text, and MAY also appear as a quoted string value in frontmatter value fields (not identifier/structural fields) for templates and drafts
- `type`: optional, defaults to `text`
- Supported types: `text` | `date` | `money`
- Same placeholder id used multiple times means the same logical blank
Expand Down Expand Up @@ -315,6 +317,7 @@ Separate files per language with identical heading structure and section identif
- `field_types` keys that are malformed or collide with built-in directive names
- Missing or malformed `type` on `{{field:}}`
- Invalid `{{placeholder:}}` identifiers or inconsistent placeholder types across repeated uses
- `{{placeholder:}}` in a frontmatter identifier or structural field (any `name`, `type`, `document_type`, `sides`/`parties` structure)
- Mismatched bilingual structure
- `amends.title` is empty or missing when `amends` is present
- `amends.file` path does not exist when specified
Expand Down
44 changes: 38 additions & 6 deletions spec/legaldown-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ Each party object describes an individual or organization that appears in the do
|---|---|---|
| `date_of_birth` | RECOMMENDED | Date of birth in ISO 8601 format |

A `natural_person` MAY also include `identification_number` (OPTIONAL) when the individual has a registration or national identification number (national ID, birth number, passport, etc.). `identification_number` is the reserved field name for this value across **all** party types — prefer it over a custom field so tooling can locate the identifier consistently. It is never required for a natural person, since not every individual has such a number.

Additional custom fields MAY be included on any party object. Implementations MUST ignore unknown party fields rather than failing. This allows organizations to include jurisdiction-specific information, tax identifiers, or any other relevant party metadata.

### 3.5 Representatives
Expand Down Expand Up @@ -375,6 +377,32 @@ attachments:
---
```

### 3.10 Placeholders in Frontmatter

Frontmatter value fields MAY use the `{{placeholder:}}` directive (§10.7) to mark unfilled values in template and draft documents. This reuses the placeholder mechanism unchanged — same identifiers, types, and rendering — rather than introducing a separate "draft" concept.

```yaml
sides:
- name: clients # identifier — stays concrete
parties:
- name: client # identifier — stays concrete
type: legal_entity # structural — stays concrete
legal_name: "{{placeholder: client-legal-name}}"
identification_number: "{{placeholder: client-id}}"
address: "{{placeholder: client-address}}"
effective_date: "{{placeholder: effective-date, type=date}}"
```

**Rules:**

- A placeholder in frontmatter MUST be written as a quoted YAML string, because an unquoted `{{` begins a YAML flow mapping and is not valid YAML
- Placeholders MAY appear in **value** fields (for example `title`, `legal_name`, `address`, `identification_number`, `effective_date`, `governing_law`)
- Placeholders MUST NOT appear in **identifier** or **structural** fields — any side or party `name` (these must satisfy the identifier format; a party `name` is additionally referenced by `{{party:}}`), party `type`, `document_type`, or the `sides`/`parties` array structure
- Type-specific placeholders follow §10.7 (for example `"{{placeholder: effective-date, type=date}}"`)
- A required field whose value is a placeholder satisfies that field's presence requirement; the document is treated as a template or draft with unfilled values
- A placeholder id used in both frontmatter and body refers to the same logical blank (§10.7)
- Renderers render frontmatter placeholders as a visible blank, consistent with §13.5 (for example `[_____]`, or `[TBD: id]` when no visual blank is available)

---

## 4. Document Structure
Expand Down Expand Up @@ -791,6 +819,8 @@ Standard Markdown tables do not support merged cells or complex formatting. For

Field specs are typed inline directives that represent structured values — including dates, monetary amounts, pass-through custom values, and fillable placeholders — within the document text. They enable renderers to format values consistently according to locale and template settings, and validators to verify that values are well-formed.

The **active locale** used for formatting (date order, decimal and grouping separators, etc.) is a render-time setting — part of the style template or renderer configuration (style templates list the locale among their settings, §13.7) — not a frontmatter field. LegalDown documents do not declare a formatting locale. Renderers MAY use the document `language` as a hint. The underlying value (ISO date, numeric amount) is stored canonically, so only its display varies by locale.

All field specs MAY include an optional `note` parameter to provide a plain-text explanation of the value for automation or machine-processing purposes. The `note` value MUST NOT affect rendered output, MUST NOT contain commas or closing braces (`}}`), and MUST be preserved in structured output formats when present.

### 10.2 Date Directive
Expand All @@ -816,7 +846,7 @@ Provider shall deliver the final report no later than {{date: 2027-03-31, note=F

- The date value MUST be in ISO 8601 format (`YYYY-MM-DD`)
- The date MUST be a valid calendar date (e.g., `2026-02-30` is invalid)
- Renderers MUST format the date according to the document's locale or render template settings (e.g., "June 1, 2026", "1 June 2026", "2026-06-01")
- Renderers MUST format the date according to the active locale or render template settings (e.g., "June 1, 2026", "1 June 2026", "2026-06-01")
- The raw ISO 8601 value and `note` (if present) MUST be preserved in structured output formats for machine processing

### 10.3 Money Directive
Expand Down Expand Up @@ -847,8 +877,8 @@ The monthly fee is {{money: 500, currency=EUR, note=Base monthly service fee}}.
- The amount MUST be a numeric value (integer or decimal, using period `.` as the decimal separator)
- The amount MUST NOT include grouping separators, currency symbols, or whitespace
- The optional `currency` parameter specifies the currency using an ISO 4217 three-letter code (e.g., `USD`, `EUR`, `CZK`, `GBP`)
- If `currency` is omitted, the renderer SHOULD use a default currency from the document metadata or render template, or emit a validation warning
- Renderers MUST format the amount according to the document's locale or render template settings (e.g., "$10,000.00", "USD 10,000.00", "€500.00")
- If `currency` is omitted, the renderer MAY apply a default currency configured in the render template or renderer configuration; if none is configured, it MUST emit a validation warning. LegalDown defines no document-level default currency — currency is specified per `{{money:}}` directive
- Renderers MUST format the amount according to the active locale or render template settings (e.g., "$10,000.00", "USD 10,000.00", "€500.00")
- The raw numeric value, currency code, and `note` (if present) MUST be preserved in structured output formats for machine processing

### 10.4 Party Directive
Expand Down Expand Up @@ -880,7 +910,7 @@ Notices under this Agreement shall be delivered to {{party: beta-industries}}.
- The directive MUST resolve against a party `name` in the frontmatter `sides[].parties[]` arrays
- The optional `label` parameter specifies display text for rendering; if omitted, the renderer MUST use the party's `label` and fall back to `legal_name`
- The `label` value is plain text — it MUST NOT contain commas or closing braces (`}}`)
- Renderers MUST format the resolved party reference according to the document's locale or render template settings
- Renderers MUST format the resolved party reference according to the active locale or render template settings
- The raw `party-name` value, `label` (if present), and `note` (if present) MUST be preserved in structured output formats for machine processing

### 10.5 Duration Directive
Expand Down Expand Up @@ -910,7 +940,7 @@ The service level response time shall not exceed {{duration: 4, unit=H, note=Cri

- The `value` MUST be a positive numeric value (integer or decimal, using period `.` as the decimal separator); zero and negative values are not allowed
- The `unit` parameter is REQUIRED and MUST be one of: `S`, `M`, `H`, `D`, `MO`, `Y`
- Renderers MUST format the duration according to the document's locale or render template settings (e.g., "12 months", "30 days", "4 hours", "1 year")
- Renderers MUST format the duration according to the active locale or render template settings (e.g., "12 months", "30 days", "4 hours", "1 year")
- The raw numeric value, unit code, and `note` (if present) MUST be preserved in structured output formats for machine processing

### 10.6 Custom Field Directive
Expand Down Expand Up @@ -958,7 +988,7 @@ Invoice {{field: INV-2026-0042, type=invoice-id}} remains unpaid.

### 10.7 Placeholder Directive

The `{{placeholder:}}` directive represents a fillable inline blank. Placeholders are declared directly where they are used in document text and MUST NOT require any frontmatter declaration.
The `{{placeholder:}}` directive represents a fillable inline blank. Placeholders are declared directly where they are used and MUST NOT require any separate frontmatter declaration. They appear in document text and MAY also appear as quoted string values in frontmatter (see §3.10).

**Syntax:**

Expand Down Expand Up @@ -1270,6 +1300,7 @@ Renderers SHOULD support external style templates specifying:
- Table formatting
- Paragraph spacing and indentation
- Cover page format
- Locale for value formatting (date order, number and decimal separators, currency display)

Templates SHOULD be defined in a separate configuration file (e.g., YAML or JSON) completely independent of document content. The same LegalDown source SHOULD render correctly with any compatible template.

Expand Down Expand Up @@ -1408,6 +1439,7 @@ Validators MUST categorize issues at three levels:
| `{{placeholder:}}` `type` parameter, when present, is one of `text`, `date`, or `money` | Error |
| Repeated `{{placeholder:}}` occurrences with the same `placeholder-id` use the same effective `type` | Error |
| `{{placeholder:}}` `currency` parameter for `type=money` is a recognized ISO 4217 code | Warning |
| `{{placeholder:}}` in frontmatter appears in an identifier or structural field (any `name`, `type`, `document_type`, `sides`/`parties` structure) | Error |
| Field spec `note` parameter is plain text and does not contain commas or closing braces | Error |

### 15.6 Document Metadata Validation
Expand Down