Concepts · Templates
Authoring a new template
Eight-step workflow for adding a Matter platform template — scaffold an MCTF directory, author the seven sidecar files, validate, register in the catalog, regenerate codegen artifacts, run tests, ship.
Last updated
This walkthrough is for engineers + lawyers contributing a new
Matter-authored platform template (those in the
matter-authored/ source bucket). Ingesting templates from
upstream open-source repositories follows the separate flow in
Sources (see the bun run --filter @repo/templates ingest
CLI).
The seven-file directory shape every template carries is documented in MCTF format. This page is the operational workflow.
TL;DR
# 1. Scaffold the directory (manual today; CLI in M2)
mkdir -p packages/templates/templates/matter-authored/<kind>_<YYYY-MM-DD>
# 2. Author the body.mdx + the seven sidecar JSON files.
# 3. Compute body_sha256 and paste into manifest.json
shasum -a 256 packages/templates/templates/matter-authored/<dir>/body.mdx
# 4. Validate
bun run --filter @repo/templates test
# 5. Run MCP regen + route-guards regen (only if x-matter-template-catalog changes)
bun run --filter matter-mcp-server generate-tools
# 6. Commit
git add packages/templates/templates/matter-authored/<dir> && git commitEight-step workflow
1. Choose the template_id and version
template_id is matter:<kind>:<YYYY-MM-DD> where <kind> matches
the document's logical type (e.g. initial_board_resolution,
indemnification_agreement). The <YYYY-MM-DD> is the revision's
release date — never the date a draft started. Same date + same kind
= same revision; bumping content requires a new date.
2. Author the body.mdx
The body uses MDX inside the strict sandbox allowlist:
- Standard markdown nodes (headings, paragraphs, lists, tables, code, links).
- Four JSX nodes:
<SignatureBlock>,<Exhibit>,<DefinedTerm>,<Attribution>. - Handlebars
{{var}}placeholders for variable substitution. - Conditional blocks via
{{#if clauses.<id>.enabled}}or{{#if clauses.<id>.selected === "<value>"}}.
Reject patterns the sandbox enforces (see MCTF format):
- Any non-allowlisted JSX element.
- MDX expressions (
{someJsExpression}). - Top-level
import/export. - Forbidden tokens (
constructor,__proto__,prototype,caller,callee).
3. Author the seven sidecars
manifest.json— root descriptor. Setbody_sha256to the SHA-256 ofbody.mdxbytes (step 4 below). Setavailability: "preview"for first draft; promote to"ga"after legal review.fields.schema.json— parameters surface. Annotate every PII-carrying field withx-matter-classification+x-matter-pii-kind. Defaults: unannotated →confidential; free-text →restricted.clauses.json— three-position grammar per negotiable clause. Marknegotiation_eligible: trueif the clause should surface in the future NegotiationSession flow.signers.json— signer roles + regulatory regime tuples + counterpart / witness requirements. Addagent_authorizedtomethod_forbidden_in_livefor any document a tier_3 agent must not be able to sign without human attestation (formation documents are the prototypical case).jurisdiction_scope.json— ISO-3166-2 codes. Day-1 catalog is US-DE only; future jurisdictions are a data add, not a schema migration.attribution.json— for Matter-authored templates,spdx_license: "proprietary"andrequired_in_body: false.render_capabilities.json— capability requirements (complex layout, pixel-perfect typography, form fields). The capability router maps these to engines.source.json— for Matter-authored templates,commit_sha: "matter-authored". For ingested templates, the upstreamcommit_shafromsources.lock.json.attachments.json— declarativeattaches_toreferences; can be[]for standalone templates.
4. Compute body_sha256
shasum -a 256 packages/templates/templates/matter-authored/<dir>/body.mdxCopy the hex digest into manifest.body_sha256. The MCTF validator
asserts the two match; mismatch = the body or the manifest is out
of sync.
5. Validate
bun run --filter @repo/templates testThe auto-discovery test in mctf-validator.test.ts
walks every directory under templates/ and runs validateMctfDirectory
on each. New templates added under that tree get validated
automatically — no per-template test boilerplate.
Common failure modes the validator catches:
body_sha256_mismatch— the manifest'sbody_sha256doesn't match the bytes ofbody.mdx. Recompute viashasum -a 256.missing_required_attribution— a CC-BY-* source's body doesn't include<Attribution />. The MDX AST allowlist treats the node as required whensource.licensestarts withCC-BY-.duplicate_clause_id/duplicate_signer_role— within-file uniqueness violations.zod_parse_error— one of the sidecars failed Zod validation. The error message names the field.
6. (When the OpenAPI catalog changes) Regenerate codegen
If the new template adds a row to x-matter-template-catalog in
apps/docs/api-reference/openapi.yaml
(matter-authored templates are listed there manually today; the
catalog-codegen step lands in M2), regenerate the MCP tool catalog
- route guards:
bun run --filter matter-mcp-server generate-tools
bun run --filter matter-api generate-route-guards7. Manual visual check (optional but recommended)
In dev mode, navigate to /settings/templates in the dashboard.
The new template appears in the catalog grouped by category.
Confirm:
- The name + version + lifecycle phases render correctly.
- The category pill is the right color (formation → indigo, governance → green, etc.).
8. Commit
git add packages/templates/templates/matter-authored/<dir>
git commit -m "feat(templates): add <kind> v<version>"The commit includes the seven sidecars + the body. The drift-guard test in CI ensures the manifest stays consistent with the body.
Promoting preview → ga
Templates ship as availability: "preview" until legal review
clears them. Promotion to "ga" is:
- Legal sign-off recorded in
internal_notes(or via a separate approval system). - Bump
availability: "ga"inmanifest.json. - Run the test suite again.
- Commit.
The catalog browser at /settings/templates shows the availability
pill alongside each template; preview renders amber, ga renders
green.
Deprecating a template
availability: "deprecated" warns SDK consumers but still renders.
The successor template's template_id lands in
successor_template_id on the deprecated revision's manifest.
Customer-facing surfaces surface the deprecation warning at render
time.
availability: "retired" stops new renders entirely — the API
returns 409 template_retired with the successor's URL in the
Problem body. Existing Documents that reference the retired
revision are unaffected; they keep their template_revision_id
forever.
See also
- MCTF format — the seven-file directory contract.
- Customization — how orgs / entities overlay on top.
- Render and sign — the end-to-end agent flow.