Package & Publish
Show the whole prompt
Read https://intentius.io/chant/lexicon-authoring/package/.
Make the lexicon I name ready to publish: its `src/package-cli.ts` on `packagePipeline` behind `npm run bundle`, `files`, `exports` and the `prepack` chain shaped like `lexicons/k3s/package.json`, and `chantVersion` in the manifest.
Run `npm run prepack`, then `chant dev check-lexicon lexicons/<name>` until tier 1 is clean. Run `npm pack --dry-run`, show me the file list, and open a pull request.
Do not run `npm publish` or `chant dev publish`.
Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.Optional: hand this page to your coding agent
Read https://intentius.io/chant/lexicon-authoring/package/.Make the lexicon I name ready to publish: its `src/package-cli.ts` on `packagePipeline` behind `npm run bundle`, `files`, `exports` and the `prepack` chain shaped like `lexicons/k3s/package.json`, and `chantVersion` in the manifest.Run `npm run prepack`, then `chant dev check-lexicon lexicons/<name>` until tier 1 is clean. Run `npm pack --dry-run`, show me the file list, and open a pull request.Do not run `npm publish` or `chant dev publish`.Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.The package lifecycle method bundles your lexicon’s generated artifacts for publishing. Core’s packagePipeline assembles the bundle and writeBundleSpec writes it to disk.
Packaging Pipeline
Section titled “Packaging Pipeline”packagePipeline returns a PackageResult in memory. It writes nothing.
writeBundleSpec(spec, distDir) creates dist/. Without it,
chant dev check-lexicon reports dist/manifest.json exists as failing.
import { dirname } from "path";import { fileURLToPath } from "url";import { packagePipeline, collectSkills } from "@intentius/chant/codegen/package";import type { PackageOptions, PackageResult } from "@intentius/chant/codegen/package";import { myPlugin } from "../plugin";import { generate } from "./generate";
// Lexicon packages are ESM, so `__dirname` does not exist.const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
export async function packageLexicon(opts: PackageOptions = {}): Promise<PackageResult> { return packagePipeline( { generate: (genOpts) => generate(genOpts), buildManifest: (genResult) => ({ name: "my-lexicon", version: "1.0.0", chantVersion: ">=0.1.0", }), srcDir: pkgDir, collectSkills: () => collectSkills(myPlugin.skills?.() ?? []), }, opts, );}// src/package-cli.ts, run by `npm run bundle`import { join, dirname } from "path";import { fileURLToPath } from "url";import { writeBundleSpec } from "@intentius/chant/codegen/package";import { packageLexicon } from "./codegen/package";
const pkgDir = dirname(fileURLToPath(import.meta.url));const { spec, stats } = await packageLexicon({ verbose: true });writeBundleSpec(spec, join(dirname(pkgDir), "dist"));console.error(`Packaged ${stats.resources} entities, ${stats.ruleCount} rules`);See
lexicons/aws/src/codegen/package.tsandlexicons/k3s/src/package-cli.tsfor the shipped pair.
PackagePipelineConfig
Section titled “PackagePipelineConfig”| Field | Required | What it does |
|---|---|---|
generate | Yes | Runs your generation pipeline and returns the GenerateResult |
buildManifest | Yes | Builds the LexiconManifest from that result |
srcDir | Yes | Package root, scanned for rule files |
collectSkills | Yes | Returns Map<filename, content>. collectSkills(defs) maps SkillDefinition[] to <name>.md |
ruleDirs | No | Rule directories relative to srcDir. Defaults to ["lint/rules", "lint/post-synth"] |
version | No | Recorded as metadata.generatorVersion. Defaults to "0.0.0" |
Bundle Layout
Section titled “Bundle Layout”writeBundleSpec creates the dist/ directory:
| Artifact | Description |
|---|---|
manifest.json | Lexicon metadata (name, version, intrinsics, pseudo-parameters) |
meta.json | Record<shortName, LexiconEntry> resource registry |
integrity.json | Per-artifact sha256 hashes plus a composite hash over the sorted path:hash pairs |
types/index.d.ts | TypeScript declarations for all resource and property types |
rules/*.ts | Lint rule implementations |
skills/*.md | AI assistant skill definitions |
okf/** | OKF knowledge bundle derived from the same registry and rules (chant #1060), replaced wholesale on each write |
The integrity record covers manifest.json, meta.json, types/index.d.ts
and every file under rules/ and skills/. okf/ is not hashed.
LexiconManifest Fields
Section titled “LexiconManifest Fields”The buildManifest callback must return a LexiconManifest:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Lexicon identifier (e.g. "aws", "k8s") |
version | string | Yes | Lexicon version (e.g. "1.0.0") |
chantVersion | string | No | Minimum chant version required |
namespace | string | No | Type namespace prefix (e.g. "AWS") |
intrinsics | IntrinsicDef[] | No | Intrinsic function definitions |
pseudoParameters | Record<string, string> | No | Pseudo-parameter names and descriptions |
chantVersion is optional to the type and required in practice: chant dev check-lexicon fails tier 1 when the packaged manifest omits it. It is checked
for presence and shape only, never for compatibility with the running core.
Documentation Pipeline
Section titled “Documentation Pipeline”Core’s docsPipeline and writeDocsSite generate a standalone Starlight docs site from your lexicon’s dist/ artifacts:
import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/codegen/docs";
const config: DocsConfig = { name: "my-lexicon", displayName: "My Lexicon", description: "Description for page metadata", distDir: "./dist", outDir: "./docs", serviceFromType: (type) => type.split("::")[1] ?? "Other",};
const result = docsPipeline(config);writeDocsSite(config, result);This creates a self-contained Starlight site with pages for resources, intrinsics, pseudo-parameters, rules, and serialization. Build it with cd docs && npm install && npm run build.
Registering docs() on the plugin is a tier-1 requirement, so wire the method
as well as the "docs" script in package.json. The full field list for
DocsConfig, including the authored pagesDir and the Diátaxis quadrants the
sidebar is grouped from, is in Docs Site.
Publishing to npm
Section titled “Publishing to npm”Once the bundle is built:
- Run
chant dev check-lexicon <dir>and confirm tier 1 is clean - Set
filesto["src/", "dist/"]. tsc compiles modules only, so a compiled module reads the generated files beside its source fromsrc/(moduleSourceDirin@intentius/chant/module-source). Fold reads a composite’s source there too. Shipping onlydist/breaks both - Give every module export two conditions:
developmenton./src/*.tsanddefaulton the compiled./dist/*.js. Thebuildscript runs tsc ontsconfig.build.jsonand keeps the.jsit emits. Both are tier-1 checks, andscripts/lexicon-exports.test.tschecks every export of every lexicon in this repository - Chain the bundle step and the build into
prepack, sodist/is rebuilt from the pinned spec at publish time rather than from whatever is on disk - Publish with
npm pack(for testing) ornpm publish
An installed chant runs plain node and loads a lexicon’s dist/*.js with no TypeScript loader (#3981). In this repository the tools resolve the development export instead. tsc reads it through customConditions and tsx through the root tsconfig paths. vitest adds the condition itself, and bin/chant passes --conditions=development. A lexicon runs from its source there whether or not dist/ has been built. A compiled lexicon that imports another lexicon needs that one compiled too, so every lexicon ships the same way.
lexicons/k3s/package.json is the shape to copy, including its
"prepack": "npm run generate && npm run bundle && npm run validate && npm run build".
Users install your lexicon with:
npm install --save-dev @intentius/chant-lexicon-<name>Next step
Section titled “Next step”Once the bundle is ready, run chant dev onboard to wire the lexicon into CI, Docker smoke tests, and the npm publish workflow. See CI & Distribution for the full checklist.
CLI Commands
Section titled “CLI Commands”chant dev generate— run the generation pipelinechant dev publish— build the distributable bundlechant dev onboard— wire CI, Docker, and publish workflow