Adds a new TextMate-based language to the Monaco editor and Shiki highlighter in apps/ui, including precompiling grammars from repos/shiki, wiring codeLanguages and the contribution registry, and keeping artefacts traceable. Use when adding Monaco or Shiki support for a new file extension, creating a custom language pack, or copying the SysML v2 integration pattern.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Adds a new TextMate-based language to the Monaco editor and Shiki highlighter in apps/ui, including precompiling grammars from repos/shiki, wiring codeLanguages and the contribution registry, and keeping artefacts traceable. Use when adding Monaco or Shiki support for a new file extension, creating a custom language pack, or copying the SysML v2 integration pattern.
disable-model-invocation
true
Add a Monaco + Shiki language
When to use
A new source extension (e.g. .sysml, .kerml) should open in the editor with correct token colours.
MDX/docs need the same grammar available through the shared Shiki bundle (getHighlighter in apps/ui/app/lib/shiki.lib.ts).
You have or can obtain a TextMate JSON grammar (*.tmLanguage.json).
Prerequisites
Grammar: Prefer MIT/BSD-licenced VS Code extensions on GitHub (search extension:tmLanguage.json <keyword>). Evaluate richness: keyword-only regex blobs vs structured rules (strings, numbers, operators, type capture groups).
Fork tooling: Grammar precompilation lives in the Tau taucad/shiki fork under repos/shiki/precompiled/ (clone via pnpm repos clone shiki after repos.yaml lists it). The script is precompiled/precompile-grammar.ts; see repos/shiki/precompiled/README.md.
Workflow (SysML v2 example)
Author or vendoryour-lang.tmLanguage.json (optionally patch upstream — e.g. merge unrestricted-names from the OMG pilot into daltskin’s SysML grammar).
Precompile from the shiki checkout (requires workspace node_modules installed in repos/shiki):
cd repos/shiki/precompiled
npx tsx precompile-grammar.ts ./your-lang.tmLanguage.json
This writes your-lang-precompiled.mjs next to the script.
Createapps/ui/app/lib/<name>-language/ with three artefacts:
<name>.tmLanguage.json — source grammar (reviewable in PRs).
<name>-shiki-precompiled.ts — header (oxlint/eslint disables + @see + licence attribution) plus the body of the generated .mjs (const lang = Object.freeze(…); const langs = [lang]; export default langs).
<name>-register-language.ts — register*Language(monaco) (id from codeLanguages, extensions, aliases, setLanguageConfiguration), and export <name>Contribution: LanguageContribution with explicit activationLanguageIds.
Mirror simple languages like apps/ui/app/lib/usd-language/ (comment/bracket languages) or richer ones like openscad-language/ (extra providers). Use object shapes for surroundingPairs / autoClosingPairs ({ open, close }) — Monaco types reject raw tuples.
Wire five sites
libs/types/src/constants/code.constants.ts — codeLanguages.<id> and languageFromExtension entries for each file extension.
apps/ui/app/lib/monaco.constants.ts — monacoLanguages and extensionToMonacoLanguage.
apps/ui/app/lib/shiki.lib.ts — import('#lib/.../<name>-shiki-precompiled.js') in langs (keep @ts-expect-error until grammars live upstream).