Skip to content

Completeness Checklist

The chant dev check-lexicon command evaluates a lexicon directory against three tiers of completeness. Run it from anywhere:

Terminal window
chant dev check-lexicon lexicons/my-lexicon

Pass --format json for machine-readable output.

These must all pass for the command to exit 0. Run for real via just check-lexicons and gated in CI (chant #1067) — see chant dev check-lexicon for the exceptions currently tracked, not silently skipped.

CheckWhat it verifies
The package exports a LexiconPluginThe module named by exports["."].default exports an object satisfying the plugin contract
The plugin exposes a Serializer with a name and rule prefixserializer.name, serializer.rulePrefix, and serializer.serialize
lintRules() returns at least 1 ruleAsked of the plugin, not counted from src/lint/rules/
postSynthChecks() returns at least 1 checkAsked of the plugin, not counted from src/lint/post-synth/
Every rule id starts with a declared rule prefixIds must fall under serializer.rulePrefix or a declared extraRulePrefixes entry, so ids do not collide when lexicons load together (chant #1349)
The plugin registers completionProviderchant serve lsp dispatches through this member — a file in src/lsp/ that nothing registers is unreachable (chant #1342)
The plugin registers hoverProviderAs above
The plugin registers docs()chant dev generate reaches the docs generator through the plugin, not through a package script
dist/manifest.json existsThe lexicon bundle was built
dist/manifest.json declares a chantVersionPresent and shaped like a version — see below
package.json routes exports["."].default at ./src/index.ts and deletes emitted JS in buildThe packaging shape every consumer depends on
At least 1 example in examples/A non-empty subdirectory
Every shipped example builds and passes its own post-synth checksDiscovers and serializes each examples/*/src/ rather than counting directories (chant #1067), then runs the lexicon’s own post-synth checks against the output and fails on any error-severity finding (chant #1400)
Registered intrinsics are exported by the packageEvery intrinsics() entry’s name resolves to a real export of src/index.ts (chant #1067)
Registered intrinsics' isTag matches how they're authoredisTag: true requires a first parameter typed TemplateStringsArray; isTag: false requires anything else (chant #1067)
Registered intrinsics' foldsAsCall opt-in is only on plain callsThe call-form opt-in cannot be declared on a tagged template, which has no call form to fold (chant #1044)
MCP tools and resources register under one well-formed namespaceThe name an agent sees is <lexicon>:<verb> / chant://<lexicon>/<path>, not a doubled or scheme-carrying variant (chant #1341)
plugin.test.ts existsPlugin unit test
serializer.test.ts existsSerializer unit test
At least 1 .mdx doc pageDocumentation exists
Every doc page is reachable from the sidebarStarlight has no auto-discovery, so a page missing from the sidebar is reachable only by direct URL (chant #1312)
Every authored doc page has a diataxis quadrantPages under docs/pages/ name their Diátaxis quadrant; the sidebar is grouped from it (chant #1731)
coverageReport() leaves no spec kind unaccountedA plugin declaring coverageReport() must account for every upstream spec kind — modeled or on its exclusion list, computed offline from committed snapshots (chant #1330); lexicons without the member pass vacuously

chantVersion on the manifest is checked for presence and shape only — it is not validated for compatibility against the core version actually running. That would need a live check at plugin-load time (a different tool, e.g. loadPlugin/loadPlugins), and is a deliberate non-goal of chant #1067.

Warnings — these make the lexicon useful in practice.

CheckWhat it verifies
The plugin registers mcpToolsMCP tool contributions active
The plugin registers mcpResourcesMCP resource contributions active
The plugin registers skillsAI skills active
The plugin registers detectTemplateTemplate detection active
The plugin registers initTemplatesInit templates active
auditCatalog() covers every post-synth checkMetadata for chant audit — title, tier, fix kind, category. A lexicon that omits it contributes nothing, silently (chant #1346)
Any declared ownership channel names paths the plugin implementsA declared marker channel must name read paths the plugin actually implements, with complete keys (chant #1348)
Declares a configSchema if it reads its own config namespaceA lexicon reading config.<name> should declare its shape, or an unknown key there is silently ignored (chant #1344)
At least 1 composite in src/composites/.ts files other than index.ts
At least 3 examplesBroader usage coverage
src/lsp/completions.test.ts existsLSP completions tested
src/lsp/hover.test.ts existsLSP hover tested
coverage.ts is implementedNo “not yet implemented” placeholder
At least 8 doc pagesComprehensive documentation — recommended topics: overview, getting-started, resources, intrinsics, pseudo-parameters, composites, lint-rules, importing
At least 15 post-synth checksCovering security, correctness, and best practices (see Post-Synth Check Guide)
At least 3 skillsCore patterns, cloud/platform-specific, advanced patterns (see Skills Authoring Guide)
At least 3 initTemplatesDefault, domain-specific variant 1, domain-specific variant 2

Informational — tracks depth of testing and feature coverage.

CheckWhat it verifies
Each lint rule has a .test.tsPer-rule or consolidated coverage (e.g. rules.test.ts)
Each post-synth check has a .test.tsPer-check or consolidated coverage (e.g. post-synth.test.ts)
typecheck.test.ts existsType-level verification
roundtrip.test.ts existsSerialize/deserialize round-trip
At least 5 compositesRich composition library
src/actions/ with at least 1 actionAutomation actions
validate.ts checks at least 30 required namesDeep artifact validation across resources, property types, and bundle files
Composite test file existscomposites.test.ts covering props, types, defaults, dependencies
At least 5 examples with testsPer-example or consolidated root test

The three tables above are the whole of chant dev check-lexicon, and a test asserts that — a row here with no matching check, or a check with no row, fails the build (chant #1343). Several things worth doing are consequently absent from them, and were previously listed as though they were verified:

Not checkedWhere it lives instead
exportResources() implementedImplementing Live Export
import/parser.test.ts, import/generator.test.ts, import/roundtrip.test.tsImporting Templates
default-labels.test.ts, coverage.test.tsTesting Your Lexicon

A capability counts as present when the plugin exposes it, not when a file with the right name exists (chant #1342). The checks above load the lexicon and ask it. That is what caught helm shipping src/lsp/completions.ts and src/lsp/hover.ts — with tests — while registering neither provider, so its LSP support was unreachable in an editor for as long as it has existed.

When designing post-synth checks, aim for coverage across these categories:

CategoryExamples
SecurityEncryption enabled, TLS version, HTTPS-only, access control, identity configuration
CorrectnessRequired fields present, valid values, correct dependencies
Best PracticesNaming conventions, tagging/labeling, resource configuration defaults
DeprecationOutdated API versions, legacy features, deprecated properties

See Testing Your Lexicon for patterns, mock helpers, and checklists for each test file.

Use the AWS lexicon as reference for full coverage:

lexicons/my-lexicon/
├── src/
│ ├── plugin.ts # LexiconPlugin entry point
│ ├── plugin.test.ts
│ ├── serializer.ts # Build output serializer
│ ├── serializer.test.ts
│ ├── index.ts # Re-exports
│ ├── coverage.ts # Coverage analysis
│ ├── validate.ts # Artifact validation
│ ├── validate-cli.ts
│ ├── codegen/
│ │ ├── generate.ts # Code generation pipeline
│ │ ├── generate-cli.ts
│ │ ├── naming.ts # Naming strategy
│ │ ├── package.ts # Bundle packaging
│ │ └── docs.ts # Docs generation
│ ├── spec/
│ │ ├── fetch.ts # Upstream schema fetching
│ │ └── parse.ts # Schema parsing
│ ├── lint/
│ │ ├── rules/ # Lint rules + tests
│ │ └── post-synth/ # Post-synthesis checks + tests
│ ├── lsp/
│ │ ├── completions.ts # LSP completions
│ │ ├── completions.test.ts
│ │ ├── hover.ts # LSP hover
│ │ └── hover.test.ts
│ ├── composites/ # Composite resources
│ ├── actions/ # Automation actions
│ ├── import/ # Template parser + generator
│ └── generated/ # Generated artifacts (do not edit)
├── dist/ # Built bundle
├── examples/ # Usage examples with tests
├── docs/ # Starlight docs site
├── package.json
├── tsconfig.json
└── justfile

After scaffolding with chant init lexicon:

  1. Implement src/spec/fetch.ts and src/spec/parse.ts
  2. Implement src/codegen/generate.ts and src/codegen/naming.ts
  3. Run just generate to produce types
  4. Implement src/serializer.ts
  5. Write lint rules in src/lint/rules/
  6. Add post-synth checks in src/lint/post-synth/
  7. Implement LSP completions and hover
  8. Build examples
  9. Generate docs

Counts below are what chant dev check-lexicon reports at chant 0.57.0, and they move with every lexicon change, so run the tool rather than trusting the table for anything that matters.

LexiconPost-synth checksSkillsCompositesDoc pagesTier-3 required names
k8s4010503730, passes
aws62340246, fails
azure244192525, fails

k8s is the most complete of the three and the one to read first. aws has the broadest resource surface and the only per-rule test layout. Its validate.ts names six required artifacts (lexicons/aws/src/validate.ts), which is below the tier-3 threshold of 30, and azure’s 25 is below it too. Both are informational failures, not tier-1 ones.