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/mcpng add @cngx/core --ai-tools claude (or cursor, vscode) registers the
server in the editor's project config, adds a marked block to the agent
instructions, and writes .cngx/README.md with the server's tools, how to check
that it runs, and how to turn it off. The full preset does the same for every
editor folder it finds. See Install.
It 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 } |
{ ok: true, groundedVersion, result } like the other name tools, groundedVersion always the bundled release: the runnable example URLs (public documentation links) and a StackBlitz URL when one exists. result is null for an unknown name. |
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. |
get_error_code |
{ code, version? } |
{ ok: true, groundedVersion, result }: a CNGX error code's title, owning lib, severity, production behaviour, call-site messages, and documentation page. Accepts a bare code, a four-digit number, or a pasted console line. result is null for an input that is not a code, and a not-found view (the matching lib and its nearest codes) for an unknown code. |
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), or over HTTPS from the public
release asset URL when gh is missing, unauthenticated or fails, 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.
get_error_code takes the same version for a code from another release than the
bundled one. It fetches that release's error-codes.json asset instead of its snapshot.
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, or over HTTPS when gh fails - 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. Both paths time out after 15 seconds. No network or an absent asset returns a typed error result instead:
| Reason | Meaning |
|---|---|
gh-missing |
No longer produced: a missing gh falls back to HTTPS. Kept in the type for compatibility. |
network |
The download failed for a network reason. |
asset-missing |
The release or its documentation.json asset does not exist, or its error-codes.json asset for get_error_code, which releases before the first such asset lack. Also covers a snapshot with an unreadable or unknown schema, a local temp-directory or write failure (the message names it), and a query that threw (its message starts with internal:). |
invalid-version |
A version that is not a release version (1.2, 01.2.3, 1.2.3-rc.), answered before any fetch. |
The CLI
@cngx/cli exposes the same queries as cngx subcommands (cngx api CngxSelect,
cngx migrate 0.1.0 --to 0.2.0, cngx explain CNGX0001) for agents and CI jobs that do not speak MCP. It
does not depend on the MCP SDK: both packages run one query core, kept in
packages/mcp/src/core and copied byte for byte into packages/cli/src/core by
npm run cli:sync. CI runs npm run cli:copy-check, so the copy cannot drift
from the tools the server registers.
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(). Every rule, its rationale and its options are on Lint Rules.@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.