Agent Tooling
CNGX publishes more than libraries. It ships a tooling surface for LLM coding agents working in consumer apps, so an agent reaches for the real API instead of guessing one. The surface has three layers, and the division of labor is the whole design:
- The MCP server answers what exists - the live API shape and the delta between two releases.
- The skills teach how to use it - the composition patterns, wired to the MCP so they never carry an API shape that can drift.
- The agents do the work under a locked persona and a restricted tool set - read-only review by default, one audited executor for edits.
A mechanical layer sits under all three: the @cngx/eslint-plugin per-file rules
and the @cngx/doctor project-wiring scan give a deterministic verdict the agents
cite rather than re-derive.
The MCP server
@cngx/mcp is a stdio Model Context Protocol
server over a documentation.json snapshot of the CNGX public API, bundled into
the package at build time. It answers get_api CngxSelect with a few hundred bytes
of typed API instead of a multi-megabyte docs dump, and it runs standalone with no
CNGX repository present:
npx @cngx/mcpIt is read-only over source, and every tool answers offline against the bundled
snapshot by default. The server reaches the network only when a caller asks for
another release: migrate_usage always spans two versions, and the shape and
config queries fetch a different release's snapshot when handed an optional
version. Every such fetch is fail-safe.
| Tool | Input | Returns |
|---|---|---|
find_component |
{ query, version? } |
Components, directives, and injectable services whose name, selector, or category matches the fragment: name, kind, selector, category, file. |
list_components |
{ lib?, kind? } |
The deterministic catalog: every component, directive, and injectable service as name, kind, selector, category, lib, sorted by name. Optionally filtered by lib and/or kind. |
get_api |
{ name, version? } |
One component's, directive's, or injectable service's API: inputs, outputs, signal flag, host bindings, public methods, description. Resolves by class name or selector. |
get_slots |
{ name, version? } |
The projected template slots, each a slot directive selector name plus its one-line doc. |
get_theme_tokens |
{ name, version? } |
The theming tokens (the CSS custom properties a component exposes) and its theme overview. |
get_di_tokens |
{ query?, version? } |
The top-level DI injection tokens, optionally filtered by a name fragment. |
get_config |
{ name, version? } |
A configuration cascade by config token name, stem, or component name: the config token, its provider functions, the with* feature functions, and the resolution-priority ordering. |
get_story_example |
{ name } |
The runnable example URLs (public documentation links) and a StackBlitz URL when one exists. |
migrate_usage |
{ from, to? } |
A structured API delta between two CNGX releases: removed, renamed, and signature-changed components (injectable services included), inputs, outputs, slots, and DI tokens. to defaults to the bundled snapshot version. |
Each answer grounds against one CNGX release; the server reports the bundled
version and the snapshot timestamp in its connect-time instructions. An answer
carries the release it grounded against, so a caller always knows which version
it reflects. Confirm the consuming app runs a matching release, or pass a
version, before relying on an answer.
Version-scoped queries
The shape and config queries - find_component, get_api, get_slots,
get_theme_tokens, get_di_tokens, and get_config - take an optional version.
Omitted, or equal to the bundled snapshot, they answer offline against the bundled
release with no fetch. Given a different version they resolve that release's
snapshot from the CNGX release assets via gh release download (pinned to the
CNGX repo, so it works from any working directory), cache it in memory for the
session, and query that instead. Either way the answer names the release it
grounded against, so a caller reading one component's API at an older version knows
the reply reflects that version and not the bundled one. A fetch that fails returns
the same typed error result migrate_usage uses, so the query answers as data
rather than throwing.
Cross-version deltas
migrate_usage is the version-upgrade answer. It resolves each version to a
snapshot - the bundled one when the version matches it, otherwise fetched from the
release assets via gh release download - and diffs the two into a categorized
delta. Rename inference is conservative: it only pairs a removed symbol with an
added one where a structural fingerprint supports it (a top-level entry's category
plus its input and output names, or a slot's description). A leaf member keyed only
by a bare type reports the removal rather than guessing a rename.
The fetch never throws across the tool boundary. A missing gh, no network, or an
absent asset returns a typed error result instead:
| Reason | Meaning |
|---|---|
gh-missing |
The gh CLI is not installed or not on PATH. |
network |
The download failed for a network reason. |
asset-missing |
The release or its documentation.json asset does not exist. |
Resources and prompts
The same offline snapshot is served as two further MCP surfaces beyond the tools.
Resources let a client browse and attach CNGX documents without an imperative
call: cngx://catalog (every component, directive, and injectable service),
cngx://tokens (the DI tokens), cngx://provenance (the snapshot's version and
timestamp), and a
cngx://api/{name} template whose {name} autocompletes against the catalog.
A fifth resource, cngx://llms, serves the llms.txt-equivalent API index -
counts, reference links and packages - as text/markdown composed offline from
the snapshot, so an agent gets the index through the MCP rather than a live
GitHub Pages fetch. A sixth, cngx://llms-full, serves the verbatim compodocx
llm-md dump - the full API text with every artifact's selector, inputs, outputs
and live-example URLs - as text/markdown over the same snapshot, so the whole
API surface, index and full text, is reachable offline through the MCP.
Prompts are single framing messages a client exposes as slash-commands -
wire_component, theme_component, and migrate_cngx - each names the tools to
ground against, carries no data, and never writes code.
The skills
Skills are auto-discovered how-to guides. Each one teaches a composition pattern and routes every concrete symbol to the MCP tools or the published docs, so a skill body never carries an API shape that could drift. They group by what the consumer is doing.
| Skill | Use it to |
|---|---|
cngx |
The index: the three design principles and the grounding the plugin bundles. |
cngx-wire |
Build a screen or feature: discover the component, confirm its API, compose it over configuring it. |
cngx-forms |
Wire a form: the Signal-Forms-first field pattern, the select-family decision tree, the Reactive-Forms adapter, and error surfaces. |
cngx-data |
Wire a sortable, filterable, paginated collection: compose the orthogonal data directives through one computed() chain. |
cngx-async |
Wire loading, error, and success state: the async state machine, projecting a branch, and bridging transitions to toasts, alerts, and banners. |
cngx-a11y |
Keep a screen accessible: preserve the ARIA CNGX derives in the reactive graph, and wire the @cngx/common/a11y atoms. |
cngx-theme |
Theme an app: import the theme bundle so directive styling renders, then set brand tokens via the --cngx-* custom properties. |
cngx-from-material |
Migrate an Angular Material screen: the mat-* to CNGX symbol mapping and the idiom shifts the move requires. |
cngx-migrate |
Upgrade an app across CNGX versions: pull the machine API delta from migrate_usage, confirm each changed symbol, and produce an ordered edit plan. |
cngx-doctor |
Act on a doctor finding: read the machine finding contract and apply the fix it names. |
cngx-from-material and cngx-migrate are two different migrations and must not be
confused. cngx-from-material moves an app off Angular Material onto CNGX.
cngx-migrate moves an app already on CNGX from one version to the next.
The agents
Agents are auto-discovered workers a skill cannot be. A skill body can only ask an
agent not to edit; an agent's tools allow-list decides it mechanically. That
mechanical guarantee is the reason the review agents exist as agents rather than as
skills: a read-only review cannot mutate the code it reviews.
| Agent | Class | Does |
|---|---|---|
cngx:reviewer |
read-only | A Pillar-grounded review of a CNGX change. Reviews holistically, cites the mechanical rule ids where they apply, routes that verdict to the linter and the doctor. Edits nothing. |
cngx:a11y-auditor |
read-only | An accessibility sweep of a screen. Finds where the consumer has silenced a guarantee the contract already ships (a described-by target removed, a disabled control that no longer says why, focus not restored after an overlay closes). Edits nothing. |
cngx:upgrader |
executor | Executes a version upgrade. Applies the ordered plan cngx-migrate produces one file at a time, runs the consumer's own build, test, and lint between steps, and halts on the first failure. The one edit-capable agent. |
Read-only by default
The tool guard models two classes. Read-only is the default: an unclassified agent
is held to a whitelist of read tools (Read, Grep, Glob, and the read-only MCP
queries), so an agent that declares a write tool without being classified fails the
guard. Only a named executor - a decision reviewed when the name is added to the
guard - may additionally declare the edit and shell tools. A per-class whitelist is
stricter than dropping the guard, and it keeps read-only the property every unknown
future agent inherits.
cngx:upgrader is that one classified executor. It earns edit rights because it
runs in an isolated context with a validation gate between every step: it confirms
each new API via the MCP before writing, applies only the planned edit, validates,
and stops on the first red step rather than pushing past a failure. Producing the
plan and applying it stay separate on purpose - one reasons over the whole delta,
the other executes under the gate.
The mechanical layer
The agents do not invent a mechanical verdict; they route to one. Two deterministic tools own it:
@cngx/eslint-plugincarries the per-file rules - the ones a single file's scope can decide, such as aneffect()created inngOnInit, a service call in aneffect()left outsideuntracked(), or a two-way binding wired as aninput()plusoutput()pair instead of amodel().@cngx/doctorcarries the project-wiring checks - the ones that need a whole-project view:toaster-without-withtoasts(a feedback surface used without its root opt-in),track-b-css-not-imported(a directive whose theming stylesheet no app entry imports), andfloating-fallback-missing(@floating-ui/dominstalled but never provided). The doctor runs automatically through a guard hook, so a mistake is caught as the code is written.
An agent that meets a finding either tool already owns cites its id and defers the verdict to that tool, so the three never contradict.
How the layers compose
The three surfaces are one story. Take a version upgrade end to end:
migrate_usagereturns the machine delta between the two releases - the what.cngx-migratereads that delta, cross-references the release notes, confirms every renamed or signature-changed symbol againstget_api,get_slots, andget_di_tokens, and produces an ordered edit plan - the how.cngx:upgraderapplies that plan file by file, validating between steps and halting on the first failure - the do.
A rename is never a blind find and replace, an API shape is never carried from memory, and an edit never lands past a red check. The same discipline runs through every layer: ground the symbol against the live source of record, or it is a guess, and a guessed API is a defect rather than a shortcut.
See The CNGX Way for the library architecture these tools document, and The Three Pillars for the bar the review agents hold a change to.