Skip to content

Latest commit

 

History

History
1219 lines (833 loc) · 181 KB

tools.md

File metadata and controls

1219 lines (833 loc) · 181 KB
title Tools
description Every agent tool the devtools expose, grouped by inspector, with what it answers and its arguments.
One hundred and eighteen tools, grouped by inspector. Each one answers a question you would otherwise answer by clicking through the panel.

Tools

This page lists every tool the MCP server exposes. Each group matches an inspector in the panel.

The server's prompts chain these tools into ready workflows, such as debug-error and fix-form.

Before you call a tool

Names

Tool ids use a colon, as pangular:scan-routes. MCP clients see them with an underscore, as pangular_scan-routes. The tables below drop the pangular: prefix. The read tools are also registered on the page under the same names, for browser agents.

The Tool index lists every tool with its inspector, tier and transports, generated from the server's own list. Each tool has a short title that clients show in their tool lists. Every tool answers with one plain text block: markdown, or compact JSON for a source scan. See Titles and answers.

Source and live tools

Each tool reads from one of three places. The stdio server registers only the tools that read your source, because no page reaches it.

Reads your files. Works over stdio and HTTP, with or without a browser. Reads what a connected page reported. Needs the HTTP endpoint and the app open in a browser. Reads what the Vite dev server recorded. Needs the Vite plugin.

Analog, Capacitor and TanStack Query tools

The analog- tools, capacitor-list-calls, capacitor-list-plugins, tanstack-list-queries, tanstack-inspect-query and tanstack-run-query are listed only when the app uses the library: the project's package.json lists @capacitor/core or an @tanstack/angular-query package, the project is an Analog app, or a page reports the library's data. In the last case the server adds the tools and sends notifications/tools/list_changed. A client that doesn't follow it sees them when it reconnects. Setting inspectors.<name> or agent.tools.<name> in the configuration turns them on or off for good. If the server can't read a package.json, it lists them all.

A wrong project folder

If the server scans a folder with no Angular project in it (no angular.json, and no package.json that depends on @angular/core), every source tool refuses with isError: true and names the folder, instead of answering an empty list. Restart the server with --root or PANGULAR_ROOT set to the project folder. See Connect over stdio.

The page argument

Most page tools take an optional page argument to pick a browser tab. Without it, every tool reads the same default page: among the tabs that report the tool's data, a tab in the foreground before one in the background, then the tab that connected last. list-pages lists pages in that order, so its first row is the default page. The answer names the page it read on its first line (Page <id>.), unless its text or JSON already names it.

Some calls name their page another way:

Call Page
run-form-action, fill-form, a form tool given form The tab in the form id (the part after @, as in Checkout.form@ab12)
set-signal, set-component-property The one tab that has the instance component names
ngrx-inspect-store, ngrx-history given store The tab of that store
highlight, inspect-component given component Every tab is searched for the instance, default page first
defer-blocks, for-blocks, hydration Every tab is listed

Tools that change app state never pick one of several tabs on their own: navigate, probe-route, record-guards, ngrx-dispatch, ngrx-restore, ngrx-store-devtools, tanstack-run-query, set-signal and set-component-property refuse and list the tabs when more than one could take the call. The tables below leave page out.

If page names a tab that doesn't report that data, the tool answers No page <id> is reporting ... and lists the tabs that do. It never falls back to another tab. A page that is not a string, such as a number, is refused the same way, and an empty string counts as left out. page is the only page argument: a call that sends pageId is refused.

Arguments and refusals

The server checks each call's arguments against the tool's input schema before the tool runs: types, required arguments, allowed values and ranges. A wrong argument is answered with Invalid arguments: and a line for each argument that names what it takes, as in `limit` must be at most 50, not 1000000.. A null for an optional argument counts as left out.

The argument names are the same in every tool:

Argument What it names
page A page id from list-pages
component A component instance: an instance id, a class name or a host tag
selector A CSS selector, and nothing else
injector An injector: an environment injector name such as Root, a tag, a class or an id
node A signal graph node, by id or label
property A field on a component: an input, a property or a signal
store A store, by id or name
after A point in a log: a forms marker or an NgRx seq. Only entries after it are listed
since A point in time: a duration back from now such as 30s, a date, or epoch ms

A call that sends an argument name a tool no longer takes, such as selector for inspect-component or storeId for ngrx-history, is refused with the name to use instead.

An argument that moved to another tool is refused with the tool to use: record, flash, track and angularProfiling on change-detection (use record-change-detection), overlay on hydration (use highlight with hydration), and routeId and on on navigate (use list-routes with resolveLazy, and record-guards with on).

A tool that refuses a call answers with isError: true. That covers a wrong or missing argument, a page that reports no such data, an action turned off in the config or under agent.readOnly, a form or action the page refuses, and a write that would have to guess the tab. The text starts with Refused: or Invalid arguments: and says what to change.

An action or destructive tool that does nothing also answers isError: true: no page to send it to, a target that matches nothing, a navigation the app cancelled or that failed, or a recording no page confirmed. An empty result of a read, such as no HTTP calls yet, is an ordinary answer.

Tools that start or stop a recording (record-change-detection, record-pipes, track-subscriptions) wait up to 3 seconds for each page to confirm, and name the pages that did.

Older Angular versions

When the page's Angular lacks the debug API a tool needs, the tool answers Unsupported on this Angular version with the version the feature needs and the version the page runs, instead of an empty list. inspect-signals, watch-signal, defer-blocks, for-blocks, change-detection and diagnose-change-detection answer this way. inspect-providers puts the same note before a reduced tree. See Supported Angular versions.

list-pages

Lists the tabs, Angular Native apps, NativeScript apps and Capacitor apps that report to the server, default page first (see The page argument): page id, URL, title, platform (browser, Angular Native, NativeScript, or Capacitor (android) and Capacitor (ios) for an app in a native WebView, followed by the page's Angular version when it reported one, as in browser, Angular 15.2), seconds since the last report or heartbeat, and which inspectors report. Takes no arguments. Reads: page. Use it to find the id to pass as page.

The URL comes from the HTTP or router report. A page that sends neither (no router, and no HTTP setup) still shows the URL its component tree reports, which also stands in when the other reports are more than 30 seconds older. A tab in the background stops reporting until it is shown again, so its last report is marked (background): an old time there means the data is the last known state, not that the page is gone. A tab that closes leaves the list at once. A tab that crashes or is killed without closing leaves it, with all its data, 30 seconds after its last report or heartbeat.

snapshot

Gives one page's full picture in one bounded markdown answer, for an agent that wants everything at once or a bug report. Reads: page. Each section comes from the tool named under its heading, with the same masking, so call that tool for the rest.

Section What it holds Full answer
page Page id, URL, title, platform, Angular version, inspectors list-pages
components The component outline list-components
route The URL and the active route tree inspect-route
navigations Recent navigations, one line each, newest first explain-navigation
http HttpClient and fetch() calls, newest first, and a line that counts the lint-http findings list-http-calls
errors Error groups, most recent first list-errors
console Console calls, newest first list-console
forms Each form with its status and error count inspect-forms
signals The signal graph, without Angular's own nodes and history inspect-signals
stores NgRx stores and Redux DevTools stores ngrx-inspect-store
queries TanStack Query queries and mutations tanstack-list-queries
Argument Required What it is
sections No The sections to include, in the order above. Every section without it.
limit No Most items per section, 1 to 50 (default 10).
maxChars No Longest answer, 2,000 to 50,000 characters (default 20,000).

Each section is also cut at 4,000 characters. When the answer reaches maxChars, it ends with a Truncated note that names the sections left out. A section whose inspector is off in inspectors, or whose tools are off in agent.tools, is listed under Skipped, and a section the page reported nothing for is listed as empty. The answer starts with the untrusted-data notice once, for every section.

open-in-panel

Gives the user a link that opens the panel on one tab with one item selected, and switches the panels that are open to it. Reads: page. Use it to point the user at what you found.

Argument Required What it is
tab Yes The tab: dashboard, timeline, audit, components, routes, signals, injectors, store, queries, forms, pipes, network (SSR & HTTP), errors, performance, build, analog, capacitor or plugins. Only tabs that are on count.
id No The item to select: a component id on components, the id of the component whose element injector to show on injectors, the id of the component whose signal graph to show on signals, a form id on forms. Other tabs ignore it.
page No The page the item belongs to, from list-pages.

The answer is a full URL, such as http://localhost:4200/__devframes/pangular/#tab=components&id=12&page=k3x9, when the hub serves the panel and a page has reported its address. Otherwise it is the hash to add to the panel's address. Each panel that is open and not in a background tab opens the link at once. The tool is read: it changes what the panel shows, not the app. See Deep links.

wait-for

Waits until a condition holds on a page, then answers. Use it after a click, a navigation or an action instead of calling another tool in a loop. Reads: page. It reads what the collectors already reported and never changes the page. It answers as soon as the condition holds, or after timeoutMs with Timed out after <n>ms and the last state it saw.

Condition Holds when Argument Inspector
component A component matching component is rendered. component (required) Components
component-gone No component matches component any more. component (required) Components
navigation The router has no navigation in progress, and its URL matches url when given. url Router
http-call An HttpClient call finished after the wait started, and its URL matches url when given. url SSR & HTTP
error A new error was captured after the wait started, with the Angular code code when given. code, such as NG0100 Errors
form A form is settled (default), valid, not-pending, or submitted after a marker. form, until, after Forms
Argument Required What it is
condition Yes One of the conditions above.
component No An instance id, class name or host tag, as in highlight.
url No Text the URL contains. * matches anything and a leading ^ anchors it at the start of the path, as in fault rules.
code No An Angular error code.
form No A form id or label from inspect-forms. Every form without it.
until No For form: settled (no pending async validation, debounce or submit in flight), valid, not-pending or submitted.
after No For form with until: "submitted": a marker from a forms answer.
timeoutMs No How long to wait. Default 5000, at most 30000.
page No The page id. Without it, every page counts, and navigation uses the most recent page.

Without url, navigation holds as soon as no navigation is in progress, which can be before a navigation you just started reaches the page. Pass url to wait for the destination. A condition is offered only while its inspector is on for agents, and the tool is dropped when all five are off.

Action tools

Every tool has one of three safety tiers. The server sends the tier to your client as the tool's read-only and destructive hints.

Tier What the tool can do Tools
read Reads your source, the page or the server. highlight only shows and selects a component. Every other tool, and every resource
action Changes the running page, the server's fault rules and SSR overrides, or what the page records, or runs a Nitro task. A reload or the next call undoes most of it, but a Nitro task can change data for good. navigate, probe-route, record-guards, ngrx-dispatch, ngrx-restore, tanstack-run-query, run-form-action, fill-form, set-http-rule, remove-http-rule, set-ssr-override, remove-ssr-override, refetch-transfer-state, set-component-property, set-signal, load-defer-block, watch-signal, record-pipes, track-subscriptions, record-change-detection, analog-run-nitro-task and audit
destructive Can lose data: it erases recordings or Store DevTools history, deletes the Nitro cache, or sends writes to your own API routes. clear-recordings, analog-run-api, analog-purge-nitro-cache and ngrx-store-devtools
The twenty-six action and destructive tools act on the app. Your client can ask you before it runs them.

When the hub is mounted, each finished call of an action or destructive tool posts an Agent ran <tool> message to the hub, so you can see what the agent changed. record-change-detection posts only when it starts, stops or clears a recording, or turns a live view on or off, and audit only when it runs axe. See Messages and badges.

Turn tools off

The server decides which tools exist. Set agent.readOnly to keep only the read tools. change-detection reads a recording the panel started, and its hints, like those of diagnose-change-detection and audit, name only Record in the panel. audit stays without its axe argument, so it reads the last axe pass the panel ran. Set agent.tools.<inspector> to false to hide one inspector's tools and resources, and keep its tab. Turning an inspector off with inspectors, or blocking an action with actions, drops the matching tools too. wait-for stays while any of the Components, Router, SSR & HTTP, Errors and Forms inspectors is on, with only the conditions of the inspectors that are. A plugin's own tools follow the same switches, with the tier the plugin declares. actions.router drops navigate and probe-route and keeps record-guards and list-routes with resolveLazy. See Inspectors and agent tools.

Source scan

These seven tools read your source and answer compact JSON. Every tool that reads only your files starts with scan- (after its library prefix, as in ngrx-scan and analog-scan-routes).

Tool What it answers Arguments
scan-routes Angular routes from your route files, with full URL path (parents and loadChildren prefixes included), kind (page, group, redirect or wildcard), guards, resolvers, and file and line. None
scan-components Components and directives from @Component and @Directive classes, with class name, selector, kind, inputs, outputs, change detection (components only), and file and line. filter, offset, limit
scan-signals signal(), computed(), linkedSignal(), effect(), toSignal() and resource declarations (resource, httpResource, rxResource), plus signal inputs, models and queries. filter, offset, limit
scan-providers DI providers: @Injectable services, inject() calls, constructor parameters and providers arrays, with token, file and where each one is provided. Other provide*() calls have type: "helper". None
ngrx-scan NgRx declarations: @ngrx/store actions (with their type strings in types), reducers, effects, selectors, features and store setup, and @ngrx/signals signalStore (with its members), signalState and signalMethod. None
scan-pipes Custom @Pipe classes, and built-in pipes from @angular/common in use in templates, with purity, standalone status, and where each is declared or used. None
scan-build The project name, the Angular and TypeScript versions, SSR status, the Analog version in Analog apps, and a builtAt timestamp. None

scan-components and scan-signals answer at most limit items (default 200, at most 1,000) and at most 20,000 characters. A list that fits is the JSON array alone. A cut list is followed by a note with the items shown, the total and the offset of the next part, such as Showing signals 1-200 of 450; 250 more not shown. Pass offset: 200 for the next part. An item longer than 20,000 characters on its own is cut, so that answer is not valid JSON. Its note gives the offset of the next item. filter keeps the items whose fields contain the text, in any case: class name, selector, kind and file for components, and name, kind, file and component for signals.

Components, signals and DI

highlight

Highlights a component in the page, scrolls it into view, selects it and makes it the target of inspect-signals. The component-tree resource then carries its live detail, and the Components tab selects it too. Reads: page.

Argument Required Value
component one of An instance id from the component-tree resource (like c12), a class name or a host tag.
selector one of A CSS selector.
hydration one of true outlines the hydrated, skipped, mismatched and dehydrated regions of a page rendered on the server, with a label on each and a legend. false removes the outline.

Pass exactly one of the three. An instance id targets that exact instance, for example the second card of a list. A class name or tag that matches several instances picks the first and lists the ids of all of them. A component that matches no instance is refused, not sent on as a CSS selector. A CSS selector highlights but doesn't change the selection. With page, a CSS selector or the hydration outline goes to that tab only. The hydration outline draws in its own layer over the page, ignores the pointer and changes nothing in the app. It is the Outline on page button of the Hydration section.

inspect-component

The live detail of one component instance: inputs, outputs and whether a parent listens, other own properties (signals and resources unwrapped), DOM listeners, host directives, change detection, encapsulation, host path and injected services. It selects the instance on its page and waits up to 3 seconds for the page to report it. Reads: page.

Argument Required Value
component yes An instance id from the component-tree resource, a class name or host tag.
path no One value to read instead of the whole detail, such as user.address.
depth no With path: levels to read below it, 1 to 5. Defaults to 1.
limit no With path: most entries per object or list, 1 to 1000. Defaults to 30.

A class name or tag that matches several instances answers for the first and lists the ids of all of them. A class name or tag only finds components. The id of a directive host from list-components answers with the directives on that element, since it has no component detail. When nothing matches and the page's tree stopped at a limit, inspect-component and highlight say which one, since the instance can be past it. Secret-looking values are redacted.

Each value in the detail shows its first level. A nested object, array, Map or Set reads {"$collapsed": type, "size": n}, and a list cut at 30 entries ends with a $more count. Pass path to read that value: an input or property name, then keys and indexes, as in user.address or items[0]. An index into a Map or Set counts its entries. With path, the tool reads the value without changing the selection. It reads own data properties only, so getters never run, and it refuses a path through a redacted name. Each input and property carries editInside when a path inside it can be written with set-component-property or set-signal.

The answer stops at 20,000 characters. Past that, each value longer than 1,000 characters shows only the start of its JSON, then each list (inputs, outputs, properties, listeners, directives, injected services, and the inputs and outputs of each directive) keeps fewer entries. A note names the cut values and says how many entries are not shown. The detail of the component-tree resource has every value in full.

list-components

The live component tree of one page as an indented outline, one line per instance: class name, host tag and instance id, as in ProductCard <app-card> c12. An element that hosts directives but no component gets a line too, as in <a> [routerLink] c14 [directive host: RouterLink]. Reads: page.

Argument Required Value
filter no A search, as in the Components filter: plain text, <tag> and [directive], such as <button> [matTooltip]. The outline keeps the matches and their ancestors.
depth no The most levels to list, 1 for the roots only. Unlimited by default.
directiveHosts no false leaves out the elements that host directives but no component. They are listed by default.

Markers follow the id:

Marker Meaning
[routed route /products] A router outlet shows this instance. A named outlet adds outlet <name>. It needs the Router inspector on.
[directives: RouterLinkActive, ...] The other directives on the host.
[directive host: RouterLink] The element hosts these directives and no component.
[hydration: skipped] In a page rendered on the server, the host was skipped, mismatched or created on the client.
(+3 below) depth hides 3 instances under this one.

Without page, it lists the default page among the tabs that have a component tree and names the other tabs that have one. The outline carries no input or property values. Pass an id to inspect-component for those, or to highlight to show the instance. The answer stops at 20,000 characters and says how to narrow it, and it says when the page's tree stopped at a limit.

defer-blocks

The @defer blocks of each page: the component that holds each one, its state, its incremental hydration state, its triggers and whether it has @loading, @placeholder and @error blocks. A Needs attention list names blocks that failed to load and blocks still on their placeholder after 10 seconds. A block whose triggers only wait for the user (on viewport, on interaction or on hover) is not listed there: its row notes that it is waiting for its trigger. Times are counted on the page's clock, which the page sends with each report, so a page whose clock differs from the server's still gets the right age. Reads: page.

It takes only page.

Without a development build, the page has no util to read defer blocks, and the answer says so.

A block that hydrated before the devtools attached to the page shows hydrated before inspection in the Hydration column, because the page never saw it hydrate.

Each page lists at most 50 blocks in the table and 50 under Needs attention, with a note on how many more are not shown. The whole answer stops at 20,000 characters. If several tabs report, pass page to read one. The Defer blocks list on the Components page has every block the page reported. A page reports its first 500 blocks. When it has more, the answer says so.

load-defer-block Action

Makes one @defer block fetch its dependencies and show its main content now, as if its trigger fired, in development only. Use it to check deferred content without scrolling, hovering or waiting. Reads: page.

Argument Required Value
block Yes A block id from defer-blocks, such as d3.
page No The page id. Required when more than one tab reports a block with that id.

The page loads the block the way DeferBlockFixture.render does in Angular's testing package, then runs change detection with ng.applyChanges. If change detection throws while the block renders, the answer quotes the error. When the dependencies fail to load, the block shows its @error block and the answer says so. A block without an @error block is left on its placeholder. The block's own triggers do not fire, so a load does not prove they work.

It refuses, and loads nothing, when:

  • the block already shows its main content
  • the block is server HTML waiting for incremental hydration (dehydrated or hydrate never), since a load would skip its hydrate trigger
  • the page's Angular does not export the internals a load needs (ɵgetDeferBlocks, ɵtriggerResourceLoading and ɵrenderDeferBlockState)
  • no page reports a block with that id, or several tabs do and page is missing

A reload of the page undoes it. Set actions.components to false to drop the tool.

for-blocks

The @for blocks of each page: the component that holds each one, its item count, what its track expression tracks by and whether it has an @empty block and shows it. A block with no items and no @empty block gets a note that it renders nothing. Reads: page.

It takes only page.

Angular reports the track expression as one of three kinds, not as its source text:

Tracks by Template
$index track $index
the item itself track item, where item is the loop item
an expression Any other expression, such as track trip.id

The page reads the blocks with ng.ɵgetControlFlowBlocks, which Angular 22.0 added for development builds. On an older Angular or a production build, the answer says the page cannot list them. The page sends the item count only, never the items.

Each page lists at most 50 blocks, with a note on how many more are not shown, and says when the page has more than the 500 blocks it reports. The whole answer stops at 20,000 characters. If several tabs report, pass page to read one. The @for blocks list on the Components page has every block.

scan-templates

Checks the component templates in your source, inline template and templateUrl files, with the compiler bundled with Pangular Inspector. The scan does not load compiler code from the project. Reads: source.

Argument Required Value
rule no Only findings of this rule, one of the ids below.
file no Only findings in files whose path contains this text, such as cart/.
severity no Only findings of this severity: error, warning or info.
limit no How many findings to list, 1 to 200. Defaults to 50.
Rule Severity Finds
template-parse-error error An error the template parser reports, such as an unclosed element, a broken expression or @for without track.
track-by-index warning @for that tracks by $index (or an alias of it) while its body reads fields of the item, so the items are objects. Rows that bind a form directive, such as [formControlName]="$index" or [formField], are skipped.
img-missing-alt warning <img> without alt, [alt] or [attr.alt], unless it has role="presentation", role="none" or aria-hidden="true".
click-without-key warning (click) on a plain element such as <div> or <span> with no keydown, keyup or keypress handler. Buttons, links, form controls and components are skipped.
legacy-control-flow info *ngIf, *ngFor, *ngSwitchCase or *ngSwitchDefault where @if, @for or @switch would do. Skipped before Angular 17.
ngclass-ngstyle info ngClass or ngStyle where [class] or [style] bindings would do.

Each finding gives its severity, rule, file:line and a fix. Errors come first. A template whose text has not changed since the last call is not parsed again. A backtick template built with ${} is skipped.

hydration

Hydration of each page that was rendered on the server: how many component hosts were hydrated, skipped with ngSkipHydration, mismatched or created on the client, and how many @defer blocks are still dehydrated. It names the skipped and client-created hosts and the dehydrated blocks, at most 30 of each, and each mismatch with a line diff of the server HTML Angular expected (-) and the client DOM it found (+). Reads: page.

It takes only page. Without it, it lists every page.

A page that was not rendered on the server gets an answer that says so. A page with server HTML but no hydrated host gets a note that client hydration is off or the build is a production build. To outline the regions on the page, call highlight with hydration: true. The whole answer stops at 20,000 characters.

change-detection

Change detection cycles recorded with Angular's profiler: the slowest components by self time, the most often checked components, lifecycle hook time per class and hook, output listener time, afterRender callback time, and the latest cycles with their duration, component checks, sync passes, hook and afterRender time and the output that ran before each one. Reads: page. Needs Angular 20 or later. It only reads; record-change-detection starts a recording.

Argument Required Value
limit no Rows per list. Default 10, at most 50.
export no json returns the recording as the file the panel's Import reads. trace returns it in the Trace Event Format for Perfetto.

Without page, it reads the default page among the pages that are recording. A page that names no connected tab gets the list of connected tabs. A connected tab that has not recorded yet gets a hint to start a recording there. The answer starts with the change detection mode of the page it reports on: zoneless, zone.js, or zoneless with zone.js still loaded. Recording is off until the panel or record-change-detection starts it. When older cycles were dropped at limits.cdCycles, the answer says how many. The answer counts the slow cycles, those longer than limits.cdSlowMs (16 ms by default), and marks each one (slow) in the cycle list. A recording lists at most 100 component classes and counts checks for up to 2000 instances. When it checked more, the answer says how many were left out. Once a page reports its live views, the answer ends with a line that says which views are on.

The export file is masked like other answers (JWTs, bearer tokens and secret names), has no instance check counts, and comes in a json code block to save as a .json file. An export over 100,000 characters is not returned, because cut JSON doesn't parse. The answer gives its size and the counts of cycles, timed spans, component classes, hook rows and output rows instead. Export it from the panel then, or clear the recording and record a shorter session. See Export and import a recording.

Each cycle line also names what started the cycle and how many of its refreshed checks changed nothing, when the page reports them. See diagnose-change-detection.

record-change-detection Action

Starts, stops or clears a change detection recording, and turns the live views on or off. Read the result with change-detection. Reads: page. Needs Angular 20 or later.

Argument Required Value
record no start starts a fresh recording on a page that is not recording and leaves a running one as it is, stop stops it and keeps the cycles, clear empties it.
flash no true turns the flash overlay on: a fading box with the class name and check count over each component Angular checks. false turns it off.
track no true writes each component check, lifecycle hook and output listener to a Pangular track in the Chrome Performance panel. false turns it off.
angularProfiling no true calls ng.enableProfiling() for Angular's own Performance panel track. It stays on until the page reloads, so false is refused.

Pass record, a view or both. A recording keeps running when the tab reloads, until stop; the cycles from before the reload are gone. Without page, record goes to every connected page (stop only to the pages that record). record waits up to 3 seconds for each page to confirm and names the pages that did; when none does, or no page is connected, it refuses with isError. A page that answers a start with no recording says why: its Angular version lacks the profiler, with the version it runs, or it has the profiler but the recording could not attach yet. Call it with record: "start", use the app, then call change-detection.

flash, track and angularProfiling go to the page in page, or to every connected page. An Angular Native or NativeScript app has no live views. The tool says there is no DOM when page names such an app, or when page is left out and every page that reports is one. record works on these apps as on a browser page. They are the Live views toggles of the panel; see Watch checks live. With agent.readOnly the tool is not registered, so start the recording from the panel.

diagnose-change-detection

Why change detection ran and what it wasted, from the recording that record-change-detection or the panel started. Reads: page. Needs Angular 20 or later.

Argument Required Value
limit no Rows per list. Default 10, at most 50.

Without page, it reads the same page as change-detection. The answer starts with the page's change detection mode, then has these parts:

Part What it lists
What started the cycles Cycles per cause, then the latest causes: a DOM event with its type, target and listener component, a signal write with the signal's debugName, an HTTP response, a timer, markForCheck, setInput, an effect, a view change, ApplicationRef.tick() from app code, or a zone.js tick that nothing in Angular asked for. Causes from app code carry its first app frames.
Components that depend on zone.js Components that changed in ticks only zone.js started, with the zone.js tasks behind them, such as setTimeout. Without zone.js these components would not update.
Wasted checks Per component class, the refreshed checks where nothing it renders changed, and its change detection strategy.
Inputs that break OnPush Inputs mutated in place (same reference, other contents) and inputs given a new reference with the same contents, with the component that set them.
Hints OnPush for a class refreshed at least 10 times that changed something in under 20% of them, or a note that it is already OnPush, plus a line per input and per zone.js dependent above.

It only reads, so it stays with agent.readOnly. With no recording yet, it says to start one with record-change-detection. See Why it ran and what it wasted for how the page finds causes and wasted checks.

Edit a component Action

set-component-property and set-signal write a JSON value to one live component instance, in development only, and answer with the value it now holds, redacted like the component detail. Reads: page.

Tool Writes How
set-component-property An input or another property. Signals are refused; use set-signal. Assigns the value, then runs change detection with ng.applyChanges.
set-signal A writable signal the component holds as a property: signal(), linkedSignal() or model(). Calls .set().
Argument Tool Value
component both An instance id from the component-tree resource, or a class name or host tag that matches one instance.
property set-component-property The class property or public input name, or a path inside its value, like user.name or items[0].title.
property set-signal The signal property, or a path inside its value, like filters.query. The signal is set to a copy with that one value changed.
value both The new value as JSON.

Both tools refuse, and write nothing, when:

  • the target is a signal input (input() or input.required()), a computed() or an asReadonly() signal, a getter without a setter, a method or an output
  • the value is not JSON, or the target holds a class instance, Map, Date or function
  • a name on the path is redacted, or the target holds a redacted value (see What is redacted)
  • a class name or tag matches several instances, or more than one tab reports components and page is missing

A parent binding sets a bound input again the next time its own value changes. Only signals held as component properties can be set; the signals that inspect-signals lists elsewhere cannot. Set actions.components to false to drop both tools.

find-leaks

Leak hints for one page, in three parts. Reads: page.

Part What it lists
Still retained Component instances destroyed but still in memory after at least 2 navigations and 10 seconds: class, instance id, the route they lived on, age, navigations since and open subscriptions. When the page has ng.ɵgetInjectorProviders (a development build of Angular 16.2 or later), Angular's DI debug data keeps every destroyed component in memory, so this part lists no instances and says so, pointing to the Chrome Memory panel. Detached views are named apart.
Open subscriptions after destroy Subscriptions still open after the component that made them went away, grouped by class, instance and call site, with why each is flagged. Only while subscription tracking is on.
Live effects and subscriptions Components with live effects (from ng.ɵgetSignalGraph, Angular 20.1 and later) or tracked open subscriptions, with instance ids for inspect-component.
Argument Required Value
component no Only classes whose name contains this text, in any case.
limit no Rows per table, 1 to 200. Defaults to 20.

Garbage collection runs when the browser decides, so the answer says "still retained" and points to the retainers in the Chrome Memory panel rather than calling it a leak. It also says what the page can't report: no WeakRef or debug API, no signal graph, or tracking off. Routes and call sites are masked like other live values. See Leaks.

Track subscriptions Action

track-subscriptions starts or stops subscription tracking on a page, the same switch as Track subscriptions in the Components panel. Reads: page.

Argument Required Value
action yes start or stop.
page no The tab to track. Defaults to the default page for start, and every page that tracks for stop.

While on, the overlay wraps Observable.prototype.subscribe and records which component made each subscription. stop puts subscribe back. Subscriptions made before tracking started are not seen, so reload the tab or go to the screen again after start, then call find-leaks. Tracking patches the page, so track-subscriptions is an action tool and agent.readOnly drops it. No action covers it, so actions leaves it in place. agent.tools.components: false hides both tools.

screenshot-component

An image of one component's host element as the page renders it now. The answer is an MCP image content block (PNG, or JPEG when the PNG is large) with a short note: the size in CSS pixels, what was masked and what could not be drawn. Reads: page.

Argument Required Value
component one of An instance id from the component-tree resource (like c12), a class name or a host tag.
selector one of A CSS selector.
page no The page id, from list-pages. Without it, a component is searched on every page, default page first, and a CSS selector uses the default page.

The page draws a copy of the element, not the screen: it copies the element's DOM with every computed style written inline into an SVG, and draws that on a canvas that is never added to the page. Nothing in the app changes, no app code runs, and a component scrolled out of view or behind a dialog is drawn all the same. Pass one of component and selector. A class name or tag that matches several instances captures the first and lists the ids of all of them, and one that matches none is refused. A CSS selector captures the first element it matches on the default page, or on page.

The copy masks what the redaction masks in form values: password fields, fields where any of formControlName, ng-reflect-name, name or id looks secret (plus redaction.secretNames), and fields with a secret autocomplete. Any other element named that way, such as a custom form control <app-pin formControlName="pin">, becomes a grey block with everything inside it, its inputs included. Elements marked data-private, .sentry-mask, .rr-mask or data-pangular="mask" become grey blocks, and data-pangular="unmask" keeps a field. JWTs, bearer tokens and secret key=value pairs in text are masked too.

What the copy can't show:

  • Images, canvases and videos the page can't read, such as an image from another origin without CORS, are grey boxes. Background images from another origin are left out.
  • Iframes are grey boxes with their tag.
  • Web fonts don't load inside the copy, so text uses a fallback font and can wrap differently.
  • Scroll positions inside the component, ::before and ::after content other than plain text, and elements past the first 3000 are left out.
  • A component larger than 2000 pixels on its longest side is scaled down to fit.

The image needs an MCP client that shows image content, and devframe 1.2.6 or later to pass it on. With an older devframe, the tool answers with the note and no image. agent.tools.components: false hides the tool.

An Angular Native or NativeScript app has no DOM to copy. With its page, the tool says so without asking the app. Without page, the search skips those apps, and when only a device app reports, the answer says so.

inspect-signals

The signal graph the page reported: nodes (signal, computed, linkedSignal, effect), dependency edges ({ consumer, producer }, where consumer reads producer, both node ids), the component or injector they belong to, and recent value history per node. Reads: page.

Argument Required Value
component one of Host tag, class name or instance id of the component, like app-root. Also accepts root, a route path like /admin or Route: admin, an element injector id like inj-12 from inspect-providers, or the instance id of a directive host from list-components.
selector one of A CSS selector for a component host, like app-card.featured. The first match is read. At most 500 characters.
node no A node id or label. The answer holds only that node, or every node with that label, with its direct producers and consumers and their resources and history.
history no false leaves out the value history. Defaults to true.
framework no false leaves out the nodes Angular itself created (framework: true). Defaults to true.

Pass component or selector, not both. A directive class name matches only the directive host the page already reports a graph for. For another directive host, pass its id or its element injector id. A host that has directives but no component reads as a directive host. When the graph the page last reported belongs to another component or injector, the tool asks the page for the one you named, once, and the Signals page keeps showing what it showed. A component the component tree knows is read by its first instance. A component it doesn't know answers with the graph the page reported and says what that graph covers. A selector that matches no component host is refused.

The answer also holds:

Field Value
resources One entry per resource(), httpResource() or rxResource(): status, isLoading, params, value, error, nodeIds.
environments The root and route injectors the page can report, with id and name.
changes On a node or resource, every change since the page first saw it. The history keeps the last 50.
nodeCount Set when Angular reported more than the 400 nodes the page keeps.
unnamedSignals Set when signals, computeds or linkedSignals in the graph have no debugName. Their history holds sampled values only.
framework true on a node that Angular's router, forms or HTTP code created. See Framework signals.
watch The node ids the page watches (ids) and whether write stacks are on (stacks). Set only while one of them is on.
stack On a write history entry while write stacks are on: the first 3 app frames of the code that set the signal.
element The element injector the graph was read from: id, tag, directives, and injectorId when you passed an element injector id. Without component, the host has directives only.
locator On a writable node the page can restore: id and key of the component field, or owner: "service" with the injector id and the service class in service.
runs, runMs, lastRunMs On an effect, where Angular's profiler reports effect runs: how many times it ran, and its total and last run time in ms. See Effect runs.

The answer is cut at 20,000 characters. A graph that is too long first keeps fewer history entries per node, then keeps the first nodes that fit. A note under the JSON says how many history entries and nodes it left out. Pass node or history: false to see the rest.

With root or a route path, the tool asks the page for the effects of that injector and waits up to 1.5 seconds for the answer. It reads that graph once and leaves the Signals page on the target it shows. If no injector matches, the answer lists the ones the page knows. On Angular 20.0, the answer says the live graph needs Angular 20.1 or later.

The page reports one graph: the component picked on the Signals page or with highlight, otherwise the deepest component in the primary router outlet. Call highlight first to switch the graph to another component. Only signals a template or an effect has read appear.

watch-signal Action

Watches a signal on the page, and turns write stacks on or off, the same switches as Watch and Record write stacks on the Signals page. Acts on: page.

Argument Required Value
node no A node id or label from inspect-signals. A label watches every node with it, up to 20.
watch no false stops watching node. Defaults to true.
stacks no true records write stacks on the page, false stops.

Pass node, stacks or both. A watched signal logs each change to the page console and shows under Watched on the Signals page. With write stacks on, each write entry in the inspect-signals history carries stack: the first 3 app frames of the code that set the signal, without Angular, packages, zone.js and the overlay. Taking a stack slows every signal write, so turn it off when you are done. Both reset when the page reloads.

Watching changes what the page records, so watch-signal is an action tool and agent.readOnly drops it. No action covers signals, so actions leaves it in place. agent.tools.signals: false hides it.

inspect-providers

The injectors a page reported. Element injectors list what each component injected and which injector supplied it. Environment injectors run from the platform down to the root and route injectors, and list what the services they already created inject. Reads: page.

Argument Required Value
injector no A tag name, a component or directive class name, an environment injector name like Root, Platform or Route: admin, an injector id, or a component instance id like c12. Returns only the matching injectors.
token no A token name, like HttpClient. Returns the injectors that provide it and the components or services that inject it.
tokenId no The id of one token, like tok-3, from tokenId in the tree. Keeps only that token when several share a name.

An injector that names an element injector returns it with its lookup path resolved to names and provided tokens. One that names an environment injector, in any case, returns that injector's providers, what the services it already created inject, and its parent injectors. When nothing matches, the answer lists the tags and environment injector names on the page to retry with.

An element injector that belongs to a component carries componentId, the instance id that inspect-component, list-components and the component-tree resource use. framework: true marks the injectors and providers that come from the installed @angular/* packages; see Framework injectors. inactive: true marks the injector of a lazy route the router loaded that no rendered element uses, such as a route the app left; see View switch.

Without injector or token, the answer is the whole tree and says which change detection mode the page runs. The answer stays within 20,000 characters and its JSON always parses. A larger tree shows element injectors as an outline (id, name, type, component, and provider and dependency counts), and when that is still too long it leaves out the deepest injectors and says how many. The environment injectors are always there, as an outline when they are large, and without their deepest injectors when even that outline is too long. An injector or token answer that is too long cuts each injector's providers and dependencies lists, with providersTotal and dependenciesTotal giving the full counts, so a large injector such as Root still shows. An @ngrx/signals store that an environment injector created carries the name the NgRx tools use, such as TravelStore, in token, and its class name SignalStore in tokenClass; token finds it by either name, and so do read-provider-value and explain-injection. injector and token take at most 500 characters each.

Each provider and dependency carries tokenId, the page's id for the token object, so two tokens with the same name, such as two new InjectionToken('config'), stay apart. A token that several tokens share lists every match with its tokenId, and tokenId keeps one of them. read-provider-value and explain-injection answer such a name with the candidates instead, and take tokenId to pick one. read-provider-value needs no tokenId when its injector leaves only one token with the name. Ids last until the page reloads. A tree from an older overlay has no ids, and the tools match by name.

When the page reported only part of its injector tree (it keeps at most 2000 element injectors and 2500 in all, and leaves out injectors nested more than 1000 levels deep), the answer says so.

read-provider-value

The current value of a service or other provider that an injector on the page already created: its own fields, with signals and resources unwrapped and marked signal or resource, and methods left out. Each value shows its first level, and a nested object, array, Map or Set reads {"$collapsed": type, "size": n}. Nothing is created: an environment injector answers only for a value it already holds, and an element injector only for a token a component or directive on the page injected. Otherwise the answer says it was not created yet. Getters never run, and secret-looking names are redacted. Reads: page.

Argument Required Value
token yes A class name like CartStore or an InjectionToken description like API_URL.
tokenId no The id of one token, like tok-3. Needed when several tokens share the name and injector doesn't narrow them to one; the answer then lists them.
injector no An injector id, Root, Platform, Route: admin, a tag or a component class name. Defaults to the first injector that provides the token, environment injectors first.
path no A member, then keys or indexes, like items or cart.items[0]. Without it, the answer lists the members.
depth no With path, the levels to read below it, 1 to 5.
limit no The most entries per object or list, 1 to 1000. Defaults to 30.

A value without members, such as a string or an array from useValue, is shown whole. See Peek at a provider value.

explain-injection

How Angular resolves one token for one component, element or environment injector: each injector on the lookup path in order, whether it provides the token and why the lookup stops. It reads the injector tree the page reported, so nothing is created or injected. See Explain a lookup with flags. Reads: page.

Argument Required Value
injector yes Where the injection happens: a component or directive class name, a tag, a component instance id like c12 (an error's owner id works), an injector id, or an environment injector name like Root.
token yes The token as the Injectors tab names it: a class name like HttpClient or an InjectionToken description like API_URL.
tokenId no The id of one token, like tok-3. Needed when several tokens share the name; the answer then lists them.
self no true asks only the first injector.
skipSelf no true starts at the parent injector.
host no true stops at the host element of the component that declares the start, where only its viewProviders and the component count.
optional no true ends in null instead of NG0201.

The answer is a table of steps: provides it, not provided, hidden (a viewProviders entry the lookup can't see), skipped, not asked or unknown. A providedIn: 'root' service counts as provided once something on the page got it. When injector matches several injectors, the answer uses the first and lists the others. Before Angular 16.2 the path is rebuilt from the rendered tree and providers are unknown, and the answer says so. injector and token take at most 500 characters each.

startup-timing

How the running app started, from navigation start: DOM content loaded, first contentful paint, when Angular started, when the root component was created, when the app was first stable, and the slowest providers to construct. Reads: page. See Startup timing.

Argument Required Value
limit no Providers to list, 1 to 50. Default 10.

When the overlay or the startup hook saw the app become stable, the time is exact. Otherwise the answer says the app was stable at or before the time the overlay looked. Provider times need the startup-hook entry on Angular 20 or later in a development build; without it the answer says how to add it.

NgRx

These tools read the live @ngrx/signals and @ngrx/store state a page reported, and the sessions you export and import. redux-inspect-stores reads the other stores. Reads: page, or an imported session.

ngrx-inspect-store

With store, the full state of one store: state, computed values, withEntities() collections (a summary of state and computed already there), methods with call counts, scope, where it is provided, and which components or injectors reference it. Without it, every store discovered so far, and the classic @ngrx/store state if present.

Argument Required Value
page no The tab to read. Defaults to every connected page.
store no A store id from a previous call or the NgRx Store page, or the store's name, such as TravelStore.

ngrx-history

The change log for a page's stores, oldest first: @ngrx/signals state diffs (method calls and patchState writes, each with a per-key diff), classic @ngrx/store actions, and @ngrx/signals/events dispatched events. A method-call entry carries a duration in milliseconds. With watchState registered, it is the time from the start of the method to that patch; without it, the time the whole call took. A signal-store entry carries the event that caused it when the change happened while that event was being dispatched. Each entry lists up to 50 changes; when there were more, it ends with how many were left out, such as 12 more changes not shown. With ngrx.trace on, an entry names the closest app frame it came from.

Argument Required Value
page no The tab to read. Defaults to every connected page.
store no Only that store's entries, by id or name. Without it, every store, action and event.
after no A seq from a previous call. Returns only entries after it. Requires page when more than one page is connected, since each page has its own sequence numbers.

ngrx-inspect-entry

The State, Diff and Action of one past entry: the full redacted state of its store right after it, every change from the state before it (up to 500), and the action, method arguments, origin and causing event. The page keeps the raw states of the entries in its log, so any entry still in the log can be read. Events have no state of their own.

Argument Required Value
seq yes The entry number, from ngrx-history or the NgRx Store page.
page no The tab to read. Defaults to the default page among those that report NgRx.
session no The id ngrx-import-session returned, to read an imported session instead.

ngrx-export-session

A session of one store as JSON: the redacted state before the first entry, then each action or method call with the state changes it made. Save it as a .json file to import it later, here or on the NgRx Store page. The answer carries the JSON when it fits in 60,000 characters; otherwise it says to export a shorter range.

Argument Required Value
store no store for @ngrx/store, or a signal store id like ngrx-1 or its name. Defaults to @ngrx/store, or the one store with entries.
from no The first entry number to include.
to no The last entry number to include.
page no The tab to read.

ngrx-import-session

Reads back a session that ngrx-export-session or the NgRx Store page exported, and answers with its id and entries. The server checks it first: the format and version, at most 1000 entries and 4,000,000 characters, and change paths that cannot reach a prototype. Nothing in the app changes. The server keeps at most 5 sessions, each for an hour after its last use.

Argument Required Value
session yes The exported session, as JSON text.

ngrx-generate-test

A Vitest spec that replays a range of entries: the state before the range, the recorded actions or method calls in order, and the state after the range as the expectation. An @ngrx/store range becomes a reducer spec, for one feature reducer when only one top-level key changed, or through combineReducers otherwise. A signal store range becomes a spec that injects the store with TestBed, sets the start state with unprotected() and checks getState(). The answer says which imports to point and which recorded values were cut or redacted. Jest runs the spec too once you drop the vitest import.

Argument Required Value
store no The store, as for ngrx-export-session.
from no The first entry number to replay.
to no The last entry number to replay.
page no The tab to read.
session no An imported session id, to generate from it instead.

ngrx-explain-change

Why a state value changed. With path, the newest entries in the kept log (up to 5) whose diff wrote that path, a path inside it or one around it, newest first. Each lists what ran (the action, the method, a patchState outside a method, or an event), its arguments or action, its origin, the event that caused it, its duration, the changes to that path, and, with ngrx.trace on, the app frames it was called from. With seq, that one entry with its whole diff. Without call sites, the answer says how to turn ngrx.trace on. It reads the newest page that matches; a change older than the kept log (limits.changeLog) is not found.

Argument Required Value
path without seq A state path as the diff writes it, from the state root (cart.items, items[0].done) or a signal store field (filter). Copy path in the state tree copies one.
seq without path An entry number, to explain that entry instead.
store no Only entries of that store, by id or name. store is the @ngrx/store Store. With seq, an entry of another store is not explained, and the answer names its store.
page no The tab to read. Defaults to the newest page that reports NgRx.

redux-inspect-stores

Stores that report through the Redux DevTools extension API, such as NGXS, Elf and MiniRx (see Other stores). Without store, a table of the page's stores with their id, library and action count. With store, or when the page has one store, its last state and its latest actions, newest first, each with the action and a state diff of up to 50 changes. It never restores a state.

Argument Required Value
store no A store id, such as r1, or its name.
limit no How many actions to list, 1 to 200. Default 20.

Router

All router tools read the page, except scan-render-mode, which also reads your *.routes.server.ts files.

On a page that runs more than one Angular app with a Router, inspect-route, explain-navigation, diff-navigations, follow-navigations, preview-navigation, list-routes, lint-routes and router-config take an optional app: the app's id (the tag of its root, such as app-root) or its root component name. Without app they answer for the first app, and the answer ends with a line that names the other apps. An unknown app is refused with the list of apps. See Several apps on one page.

Read the current route

Tool What it answers Arguments
inspect-route The current route: URL, query params, fragment, title, the navigation in flight, the active route tree (component, params, data, guards, resolvers), the outlet tree with each outlet's routerOutletData, and history changes made outside the router (browser Navigation API events no router navigation came with). With component, the route a component was rendered for, or whether a link is active. component: component class, element tag or link text, app
diff-navigations What changed between two recorded navigations: URL and outcome, query params, route params and data per route, the route and component in each outlet, guard and resolver verdicts, phase timing, lazy loads and the request count. a, b: navigation ids, app
explain-navigation Recent navigations, newest first: who started each one, redirects and loops with the cause of each hop, per-phase timing, guard and resolver verdicts, lazy loads, a possible open redirect when the target came from a query param, the browser Navigation API event each one came with, what the withNavigationErrorHandler() handler did, and the cancel or error reason in plain language. url, id, limit (1 to limits.navigations, default 5), perf, format, app

Use explain-navigation for "why was I redirected". When the SSR & HTTP inspector recorded HttpClient calls on the same page, each navigation lists them with method, URL, status and time: the ones that started while it ran, and the ones that started after it ended, before the next navigation and within 5 seconds. Without them, it counts the requests resource timing saw. Pass perf: true for "why is navigation slow": it lists the slowest navigations and preloads. Pass format: "repro" for a markdown repro of one navigation (id, or by default the latest one that did not succeed), with router options, any loop it is part of and the relevant slice of the route config. format is explain by default, and repro can't be combined with perf.

Use diff-navigations for "why did this work last time". Without b, it takes the newest finished navigation that is not a probe. Without a, it takes the latest earlier navigation to the same path, else the one before. Params and data come from the routes each navigation activated, so a cancelled or failed navigation has none, and the answer says so.

Follow navigations

follow-navigations returns the navigations that are new or changed since a cursor, oldest first, across every page. Use it to follow a login and redirect flow step by step without calling explain-navigation in a loop. Reads: page.

Argument Value
since The cursor a previous call returned. Without it, the tool lists the last 5 navigations and the current cursor.
waitMs With since: how long to wait, at most 30000 ms, when no navigation came after the cursor yet. The tool answers as soon as one comes. Default 0.
page Only the navigations of this page.
app On a page that runs several Angular apps with a Router, the app to follow: its id or root component name. Without it, the tool follows the first app of each page.

Each line has the sequence number, the page, the app (for an app other than the first), the navigation id, the URL, the outcome, the time, a redirect target and the reason it failed. The answer ends with Next cursor: pass it as since on the next call. A navigation that was still pending comes again with (updated) once it ends, is redirected or changes target. Probes are left out. The server keeps the last 500 changes, and says how many a cursor missed. A cursor from before the server started lists everything it kept.

Read the route config

Tool What it answers Arguments
list-routes The live route config: every route with its full path, component or redirect, lazy state, guards, resolvers, title, source file and an example URL. match, audit, filter, resolveLazy, app
lint-routes Route config mistakes, such as routes after **, redirect cycles, redirect loops seen at runtime, deprecated class guards, runGuardsAndResolvers: 'always' on busy parents, lazy components already in the main bundle, resolvers whose data the page fetches again, missing titles and param typos. Each finding says how Angular reacts and how to fix it. Says how many links past the first 100 were not checked, as "at least" when the page stopped checking elements early. app
preview-navigation What going to a URL would do, predicted from the live route config without navigating or running app code: the redirects it follows, the route chain and params, then in order the canMatch guards, lazy children, canDeactivate guards of the routes being left, canActivateChild and canActivate guards, resolvers, lazy components, the components that render and the title, with each route's source file and the render mode. url (required), app
router-config How the router is set up (provideRouter, forRoot or other or unknown), effective options, enabled features, strategies, base href and hydration. app
scan-render-mode The ServerRoute and render mode (Server, Client, Prerender) a URL gets, plus server entries that match no client route. url, defaults to the page URL

preview-navigation stops at a function redirectTo, a redirect loop or a lazy route whose children have not loaded, and says why. Load those children first with list-routes and resolveLazy. canMatch guards and custom matchers only run in the app, so confirm a prediction with probe-route.

list-routes takes five optional arguments:

Argument Value
match A URL such as /users/42. The tool predicts which route it hits, or the nearest routes when it hits none.
audit Set to true to list the guards that protect each page.
filter Only routes whose path or component contains this text.
resolveLazy The route id of an unloaded lazy route, from this list. The page reads its routes without registering them, and the answer starts with the result, then lists the routes.
app On a page that runs several Angular apps with a Router, the app to read: its id or root component name, as the answer lists them. Defaults to the first app.

resolveLazy only reads, so it stays with agent.readOnly and actions.router: false.

Act on the router Action

Three tools act on the running app's router, in development only. Reads: page.

Tool What it does Arguments
navigate action: "go" goes to url, or to pattern with params, and waits for the outcome. abort stops the navigation in flight. replay runs navigation id again and compares the outcome. action (required: go, abort or replay), url or pattern + params, replaceUrl, skipLocationChange, waitFor, id
probe-route Runs the real matcher for url without navigating. It runs canMatch guards and may load lazy chunks. url (required)
record-guards Turns per-guard and per-resolver recording on (on: true, the default) or off, so explain-navigation shows each verdict and its time. on

The page's result comes back as a JSON block cut at 15,000 characters. A cut result ends with a note saying so. The result names the tab it ran on in page. After a guard or resolver redirect, outcome is redirected, finalUrl is where the app ended up, redirect holds the id and outcome of the navigation that followed, and decidedBy names the guard when guard recording (record-guards) is on.

Without page, each tool uses the one tab that reports a router. When several do, it does nothing and lists them, so call it again with page. A refused URL, a navigation the app cancelled or that failed, and an abort with nothing in flight answer with isError: true.

Only same-origin URLs that start with / are accepted. With actions.router set to false, navigate and probe-route are not registered; record-guards stays, since it only changes what the page records. All three are action tools, so agent.readOnly drops them.

waitFor sets when navigate with go answers:

Value When the tool answers
navigation When the navigation ends. The default.
stable When the navigation ends and the app has no pending tasks, such as HTTP requests or httpResource loads (the signal behind ApplicationRef.whenStable()). The result has stable: true, or stable: false with a note when 10 seconds pass first.

If a canMatch guard or the navigation error handler redirects a probe, probe-route stops the redirected navigation before it matches or renders anything, and the result names the target in redirectedTo.

NgRx actions

Dispatch an action Action

ngrx-dispatch dispatches an action to the @ngrx/store Store of the running app, in development only, and returns the new log entry: the action, its origin and the state diff. Reads: page.

Argument Value
type The action type, like [Cart] Add Item. ngrx-scan lists the types it finds in source.
payload The action props as a JSON object, like {"id": 7}. It cannot have a type key.
seq The number of an action in the log, to dispatch that action again. Use it instead of type.

Without page, the tool uses the one page that has an @ngrx/store Store. If more than one page has a Store, it dispatches nothing and lists those pages with their URLs, so you can call it again with page. While a restore holds Store DevTools on a past state, the action is logged but does not change the state, and the answer says so. Set actions.ngrx to false to drop the tool. Read the live state and log with the ngrx-store resource.

Restore a state Action

ngrx-restore restores a past state in the running app, in development only, the way Restore this state does on the NgRx Store page. A signal store gets every state key set back to its value right after the entry. @ngrx/store jumps Store DevTools to the state after that action, which needs provideStoreDevtools(), and stays paused there until you go back. The log gets a Restore #N entry. Reads: page.

Argument Value
seq The number of a restorable entry in the log.
latest true sends Store DevTools back to the latest state. Use it instead of seq.

Without page, the tool uses the one page that reports NgRx state. With several, it restores nothing and lists them. Set actions.ngrx to false to drop the tool.

Change the Store DevTools history Destructive

ngrx-store-devtools runs an operation on the @ngrx/store Store DevTools history of the running app, in development only, like the Store DevTools history controls on the NgRx Store page. It needs provideStoreDevtools(). Every operation but pause adds an entry to the log: jump with seq adds Restore #N, as ngrx-restore does, and the others add Store DevTools: …. Reads: page.

op What it does Other arguments
toggle Skips the action of an entry, so the state is computed without it, or includes a skipped one again. seq: the entry of an @ngrx/store action.
jump Shows the state after an entry, like ngrx-restore, or a Store DevTools state by its index. The store stays on it until you go back. seq, or index: 0 is the committed state.
commit Makes the current state the new starting point. Earlier entries can no longer be restored. none
reset Puts the store back on its initial state and empties the history. Earlier entries can no longer be restored. none
pause Stops recording new actions, which still change the state but cannot be restored, or starts recording again. paused: true stops, false starts. Without it, it toggles.

Without page, the tool uses the one page that has an @ngrx/store Store. With several, it changes nothing and lists them. Set actions.ngrx to false to drop the tool.

TanStack Query

These tools read the QueryClient the app provides, through the page. See TanStack Query. Reads: page.

Tool What it answers Arguments
tanstack-list-queries The clients, then the queries and mutations: id, key, status, fetch status, freshness (fresh, stale or invalidated), when the data was last updated, observers and the error. status, search, limit
tanstack-inspect-query One query or mutation by id, or the query whose key contains key: its status, freshness, staleTime, gcTime, observers and failures, then its data (and a mutation's variables), read from the page now. id, key

status is one of pending, error, success, idle, fetching or paused, and matches a status or a fetch status. search keeps keys that contain the text, ignoring case. limit sets the rows per table, 1 to 300 (default 50). Keys, errors and data are masked like other live values.

Invalidate or refetch a query Action

tanstack-run-query calls the app's own QueryClient for one query. invalidate marks it stale through invalidateQueries(), and a query with an active observer refetches at once. refetch fetches it again through refetchQueries(). Both run the query function, so the app sends its request again.

Argument Required Value
action yes invalidate or refetch.
id no A query id from tanstack-list-queries, such as q3.
key no Text the query key contains, when there is no id.

Without page, the tool refuses when more than one tab reports TanStack Query. Set actions.tanstackQuery to false to drop the tool.

Forms

All forms tools read the page. They cover Signal Forms, reactive forms and template-driven forms.

Two arguments come up in almost every tool:

Argument Value
form A form id (like Checkout.form@ab12) or part of its label (Component.property).
path A dotted field path, like address.city or items.0.qty. Empty for the form itself.

Read form state

Tool What it answers Arguments
inspect-forms Without arguments, each form with its status and error count, plus WebMCP tool state for Signal Forms that set experimentalWebMcpTool. With form, its field tree: value, status, touched, dirty and errors, and a webMcp entry with the tool name, inputs, registration status, blocking fields and recent calls. form, path, onlyInvalid, includeValues
explain-invalid-forms Which fields make a form invalid, and why: the failing validator, its message, the value and whether it was touched. Without form, every invalid or pending form. form, path
explain-field One field: where each error comes from, why validation is skipped, the binding and DOM facts like the label and visible error text. form, path, or selector (a CSS selector)
explain-submit What submit does, and why it might do nothing. Its recent submits say which fields and validators blocked or rejected them. form
inspect-form-payload What the form sends: value against getRawValue(), fields that are sent without validation, and which fields the user changed. form, path
explain-custom-control How a field is bound to its element, and what is wrong with the binding, such as value drift or a missing setDisabledState. form, path

For "why is this form invalid", call explain-invalid-forms first. The tools redact passwords and other secret-looking values.

Answers about large forms are cut to keep an agent's context small. Each cut ends with a note on what was left out and how to narrow the answer:

Tool Cap Narrow with
inspect-forms As many fields per form as fit in 20,000 characters, at most 200, taken level by level from the start of the tree. A group that lost fields carries notShown with the count. Values, error messages and metadata over 300 characters are cut. If not even one field fits, each form shows only its status and notShown. path, form or onlyInvalid
explain-invalid-forms 100 problems per form, then … and N more not shown. path
inspect-form-payload 8,000 characters per value. path
export-form The same field cap as inspect-forms for a snapshot. A fixture or a Playwright test, header included, fits in 20,000 characters. A fixture header lists at most 20 failing fields, and a Playwright test replays at most the last 200 steps. inspect-forms or inspect-form-payload with path
lint-forms 100 findings. form
explain-form-changes 100 changed fields. form or a later after marker

With path, inspect-forms, explain-invalid-forms and inspect-form-payload start at that group or field, so a cut part of the form can be read one group at a time.

The page itself reads at most 100 fields per group or array, and 8 levels deep. A group cut there carries truncated (the fields left out) and truncatedInvalid (up to 20 paths of invalid fields left out). The tools then say which group was cut, as in keeps the first 100 of 150 fields (50 more not read), and path can't reach those fields. explain-invalid-forms and explain-submit name each invalid field past the cap, with its error when a Signal Form's errorSummary has it. If the form is invalid and no field the page read has an error, explain-invalid-forms says the failing field may be past the cap.

Track changes

Tool What it answers Arguments
list-form-changes A timeline of changes, each tagged with its origin (user, code, devtools, binding, agent). Writes from these MCP tools and the panel are devtools; agent marks a write through a WebMCP form tool. Returns the current marker. form, path, type, origin, after, limit (default 50, at most 200)
explain-form-changes The net change since a marker: each field whose value or status ended up different. form, after
export-form A JSON snapshot, a test fixture with the expected status, or a Playwright test that replays the form's history. Secret values stay redacted. form, format (snapshot, fixture or playwright)
lint-forms Form bugs, NG01xxx setup errors and model-aware accessibility checks, like a missing label or error text that is not linked. form

A submit event has an outcome: ran, blocked (the Signal Forms action did not run), rejected (the action returned errors) or threw. Its detail names the fields and the validator kinds that blocked it, or the fields and messages the action rejected. See Submit view.

To wait until a form is settled, valid, not pending or submitted after a marker, call wait-for with condition: "form".

Markers let an agent check its own work: read the marker, act, then call explain-form-changes with after set to it. A marker counts events across every open page and keeps counting after a page reloads, so it stays valid when the agent works in another tab.

Act on a form

Both tools are action tools and need a development build. They don't write secret fields unless you unmask them. See Opt fields in or out. For Signal Forms, they don't write hidden, readonly or disabled fields either.

Tool What it does Arguments
run-form-action One action on a form or field. action (required), form (required, the full id), path, value, mode (code or user), confirm, force, snapshot
fill-form Fills several fields by path, through the inputs like a user would. Optionally submits afterwards. form (required), values (required, a map of path to value), mode, submit, confirm

When a write goes through a native <select> (mode: user, the default for fill-form, or any write to a template-driven form), the value must equal the value of one of its options ([ngValue] or value). A multiple select takes an array. If no option matches, the field is not written and the result says has no option with the value .... A mode: code write to a reactive form or Signal Form sets the model directly and does not check the options.

run-form-action accepts these actions: set-value, mark-touched, mark-untouched, mark-dirty, mark-pristine, touch-all, revalidate, reset, enable, disable, submit, focus, focus-first-invalid, store-as-global, snapshot, restore, instrument and try-webmcp.

try-webmcp runs the WebMCP tool linked to a Signal Form, with value as the tool's input object. The tool fills the form and submits it, so it needs confirm: true, and it is refused when actions.forms is false. inspect-forms with form returns the tool's input schema under webMcp.schema. The answer is the tool's own result text.

run-form-action and fill-form always act on the form form names. store-as-global does not overwrite a $form or $control that the page defined itself, unless you pass force.

snapshot keeps a copy of the form value, so it refuses a form whose value cannot be cloned, such as a control that holds a function. inspect-forms with includeValues: false also leaves out uncommitted input, model drift and metadata.

reset, submit and restore need confirm: true, and so do fill-form with submit and try-webmcp. Disabled reactive fields need force.

Pipes

scan-pipe-usage

scan-pipe-usage checks the pipes in your source. Reads: source. No arguments.

It finds impure pipes used inside @for, | json left in templates, pure pipes whose transform() reads a signal, and method calls piped to | async. See Lint.

Explain a pipe

explain-pipe explains one pipe: where it is declared or used, whether it is pure, live instance and call counts, the time spent in transform and the errors it threw, the last input and output, a stale-value warning, a churn warning, | async usages that resubscribe on every check or subscribe to the same source as another usage, and lint findings. Reads: source, plus the page for live counts.

Argument Required Value
name yes The pipe name as used after | in a template.
page no The tab to read. Defaults to the default page.

Live data comes from one tab: the one page names, or the default page. When more than one tab reports pipes, the answer starts with the tab it read. Live counts, times, errors, input and output appear while recording is on. Start it with record-pipes or with Record calls in the Pipes inspector.

The Live line tells these cases apart:

Case What the tool says
No page is connected There is no live data. The stdio server always reports this.
A page is connected, pipe not used No rendered component on the page uses the pipe.
Pipe in use, recording off Instance count and components, plus a hint to start recording.
Pipe in use, recording on, no calls Instance count and components, and that no calls are recorded yet.

A pipe is churning when one of its instances returned an equal result 20 calls in a row while recording: a pure pipe whose input changes reference on every check while its contents stay the same, or an impure pipe that returns an equal object or array as a new reference. An impure pipe that returns the same reference or primitive is how impure pipes run, so it never counts.

Suggest pipe migrations

suggest-pipe-migrations suggests how to move pipes to signals, with the file, line and template text of each use. Reads: source, plus the page for churn and stale findings. It changes no file: apply the suggestions by hand.

Argument Required Value
name no Only this pipe, by the name used after |.
page no The tab to read live findings from. Defaults to the default page.
Suggestion When
| async to toSignal() A template uses | async. If a use pipes a method call, the answer names it and tells you to move the Observable to a field first.
Impure pipe to computed() A custom pipe is pure: false.
Signal-reading pipe to computed() The signal-read-in-pure-pipe lint rule fires for a pure pipe.
Churning pipe While recording, the pipe churned (see Explain a pipe).
Stale pipe While recording, the experimental stale check fired.

Built-in formatting pipes such as date and currency are pure and cheap, so it suggests nothing for them. A lint rule set to false in lint.rules drops its suggestion too.

Record pipe calls Action

record-pipes starts or stops call recording on a page, the same switch as Record calls in the panel. Reads: page.

Argument Required Value
action yes start or stop.
page no The tab to record on. Defaults to the default page for start, and every page that records for stop.

start records on the tab page names, or on the default page. Other tabs stay unpatched. stop stops that tab, or every tab that records without page; with none recording it refuses. The answer names the tabs that confirmed within 3 seconds. Each recording starts from zero, and the calls recorded so far stay after a stop. Call record-pipes with action: "start", use the app, then call explain-pipe. Recording patches the page, so record-pipes is an action tool and agent.readOnly drops it. No action covers pipes, so actions leaves it in place. agent.tools.pipes: false hides it.

SSR & HTTP

These tools read the HttpClient calls that withPangular() recorded and the SSR requests that ssrMiddleware or withPangularSsr() traced in your server. See SSR & HTTP. Reads: page.

Tool What it answers Arguments
list-ssr-requests Recent traced SSR requests: id, URL, status, render mode, render time, server calls, and whether a connected page loaded the response. limit
explain-ssr-request One request end to end: timings, kept response headers, the router's guard and resolver times, each server call with its transfer cache outcome, then the browser page with its hydration result and the calls the browser made again. id, url
list-http-calls The HttpClient calls and native fetch() calls of one tab and the server render that served it, newest first: side (SSR or client), method, URL, status, duration, and flags for native fetch, mocked, faulted, cancelled, redirected, transfer cache hit, the matched rule and the Angular API that likely started it (likely httpResource(), likely resource(), likely @defer). With preview, the masked response body, for failed calls too. With view: "waterfall", the tab's client calls as a waterfall instead. url, failed, limit, preview, headers, view
lint-http Checks one tab's recorded client calls for duplicate GETs, waterfalls (calls that ran one after another and could start together) and server calls the browser made again. Each finding lists the call ids and what to try. page

explain-ssr-request picks the request by id, else the newest one for url, else the newest one. It names each hydration mismatch by the component class the node hosts when the page could read one, else by the element (<app-card>) or text node (#text).

list-http-calls lists one tab and the server calls of the SSR request that served it: the tab page names, or the default page. With no tab connected, it lists the server calls. url keeps calls whose URL contains the text. failed keeps calls with a status of 400 or more, no response, an error, or a cancel. limit defaults to 30 (at most 200). preview adds each call's response preview, including the body a failed call got back, such as a validation message or problem+json. headers adds each call's request and response headers. Secrets in URLs, errors, previews and headers are masked, and url matches the masked URL.

lint-http reads the tab page names, or the default page, and the server calls of the SSR request that served it. It leaves out transfer cache hits, mocked and cancelled calls, and reports three kinds of findings: a GET to the same URL again within 2000 ms on the same page URL, 3 or more calls where each started within 50 ms after the previous one ended, and a server call whose method, path and query the browser requested again. Each finding names the calls by the ids list-http-calls uses, the time it costs where that can be told, and a fix. URLs are masked.

list-http-calls with view: "waterfall" reads the tab page names, or the default page, and groups its client calls by navigation, newest first: each call's start offset in its navigation, duration, status and a text bar. A new navigation starts each time the page URL a call was made on changes. limit then sets how many navigations it shows, 5 by default (at most 50). url, failed and preview apply to the list only, and are refused with view: "waterfall". headers adds each call's headers. Authorization, Proxy-Authorization, Cookie and Set-Cookie are always masked, as are names that look secret or match redaction.secretNames, and JWTs and bearer tokens in any value.

Fault rules Action

These tools read and change the rules of Fault injection, the same rules the panel shows. Rules live on the devtools server and apply to every connected tab, so the tools take no page. Reads: page.

Tool What it does Arguments
list-http-rules Lists the rules in match order: id, on or off, method, URL pattern, where it applies (client, SSR or both) and its effect (status, delay, mock body). none
set-http-rule Adds a rule, or replaces the rule with id, and returns the saved rules. With preset, adds the rules of a built-in preset instead. pattern (required without preset), id, method, target, status, delayMs, body, chance, enabled, preset
remove-http-rule Removes the rule with id and returns the rules left. id (required)

set-http-rule checks its input the way the panel's form does. pattern is a substring or a glob where * matches anything, up to 500 characters. A leading ^ anchors it at the start of the URL path. target is client, server or both (the default). status is one of the statuses the panel lists, or 0 to fail the request as a network error. delayMs runs from 0 to 10000. chance is a whole percent from 1 to 99: the rule then applies to that share of matching requests, rolled per request, and the others go on to the next rule. body is JSON text or a JSON value, up to 100,000 characters. A rule needs a status, a delayMs or a body, and there can be at most 50 rules. A rule that breaks one of these is refused with the reason, and nothing changes. A rule that applies to SSR takes effect on the next page load. Patterns and bodies in the answers are masked like recorded calls. preset adds the rules of one of the panel's presets after the existing ones, as plain rules that show, change and go away like any other: offline is pattern: "*", target: "client", status: 0, slow-3g is the same with delayMs: 2000 and flaky with status: 503, chance: 30. Pass preset alone. With any other rule argument it is refused, and so is a preset that would go past 50 rules.

With actions.http set to false, set-http-rule and remove-http-rule are dropped, and list-http-rules says that no rule applies.

TransferState and SSR overrides Action

These tools read and refetch the TransferState payload a page was served with, and read and change the SSR overrides, the same overrides the panel shows. Overrides live on the devtools server and apply to every page load that matches, so the override tools take no page. Reads: page.

Tool What it does Arguments
inspect-transfer-state Lists the TransferState keys of a page with their kind (HTTP transfer cache, app state, hydration data, Analog) and size, or shows one key's value. page, key, search, limit
refetch-transfer-state Renders the page's URL again on the server, with the tab's cookies, and replaces the payload the panel and inspect-transfer-state show. page
list-ssr-overrides Lists the overrides: id, on or off, kind, page pattern and effect. none
set-ssr-override Adds an override, or replaces the one with id, and returns the saved overrides. kind (required), pattern (required), id, message, key, value, enabled
remove-ssr-override Removes the override with id and returns the overrides left. id (required)

kind is one of these:

kind What it does Arguments it takes
render-error Throws message (default Simulated render error) while the server renders a matching page. message
client-render Serves index.csr.html instead of rendering. none
state-edit Sets the TransferState entry key to value, or removes the entry when value is left out. key, value

set-ssr-override checks its input the way the panel's form does. pattern matches the page path and query like a fault rule's, up to 500 characters. message is up to 300 characters. key is up to 200 characters, with no spaces at either end, and a key with a masked part is refused because it can never match. value is JSON text or a JSON value, up to 100,000 characters. There can be at most 20 overrides. An override applies from the next full page load. Patterns, messages and values in the answers are masked like recorded calls.

inspect-transfer-state reads the default page among those that reported a payload unless page names another. search keeps keys and cached URLs that contain the text, and limit defaults to 50 (at most 500). The values are the masked and clipped copy the panel shows, so read them to find a key, and type the full value for state-edit. An HttpClient entry holds b (body), s (status), st (status text), u (URL) and rt (response type). Above the key list, it warns when the payload is over 100 KB, with its three largest entries, and names any URL the transfer cache stored under more than one key.

refetch-transfer-state asks the tab to fetch its own URL with its cookies and cache: "no-store", and reads the payload out of the HTML the server sends. The HTML is parsed into a detached document, so its scripts don't run and the tab does not reload. The refetched payload is masked like the first one, and the panel marks it Refetched until the tab reloads. It answers with the entry count and the key list, or refuses when no page reports HTTP data, the server sends no HTML or the tab doesn't answer within 15 seconds. On a platform without fetch or an HTML parser, such as a native app, it refuses.

With actions.http set to false, set-ssr-override, remove-ssr-override and refetch-transfer-state are dropped, and list-ssr-overrides says that no override applies.

Clear recordings Destructive

Resets recorded data between reproduction runs: recorded HTTP calls, router navigations, and Analog server calls. Reads: page.

Tool What it does Arguments
clear-recordings Clears recorded HTTP calls, router navigations, or Analog server calls, and broadcasts the reset to the panel. target (required), page

target is one of http, router, analog, or all. With router, page clears navigations for that browser tab only; when left out, it clears navigations for every reporting page. A page that sends no router data gets an answer that lists the pages that do, and nothing is cleared.

Each target needs three settings turned on: its write action (actions.http, actions.router or actions.analog), its agent tools (agent.tools.<target>) and its inspector (inspectors.<target>). target lists only the targets that pass, plus all, and any other value is refused. With all, the targets that pass are cleared and the others are reported as skipped. When no target passes, the tool is not listed.

Capacitor

These tools read what a Capacitor app reported: its platform, its plugins and the plugin calls it made. See Capacitor. Reads: page.

Tool What it answers Arguments
capacitor-list-calls Plugin calls, newest first: plugin and method, native or web, arguments, the result or the error with its code, and the duration. Marks not implemented calls and streams, and ends with the active listeners, their event counts and the masked payload of each one's last event. plugin, failed, slowMs, limit
capacitor-list-plugins The platform, the server URL, whether CapacitorHttp and native logging are on, the WebView user agent, and each plugin: available, imported, installed natively, its native methods, and a hint when they disagree. none

plugin keeps calls to one plugin, ignoring case. failed keeps calls that failed. slowMs keeps calls that took at least that many milliseconds, counting a pending call's time so far. limit defaults to 30 (at most 200). Without page, both tools answer for the default page among those with a native bridge, so a desktop tab of the same app doesn't hide the device, and they name the other pages that report. A long answer is cut at about 20,000 characters with a note on how to narrow it, and a plugin lists its first 20 methods. Native calls are logged on iOS and Android. Calls a web implementation answers are logged only when the app loads @pangular-inspector/devtools/capacitor-hook before @capacitor/core, and the answer says so when it doesn't. Arguments, results and errors are masked with the server's redaction too.

Errors

These tools read what a page captured: errors from Angular's ErrorHandler, uncaught errors, unhandled promise rejections and console calls. See Errors. Reads: page.

Tool What it answers Arguments
list-errors Error groups, most recent first: id, count, when last seen, the Angular error code linked to its reference page, the message, the owning component with its instance id, and the source (handler, window or promise). code, limit
explain-error One error by id: message, count, sources, the owning component, the stack of the first occurrence, and for an Angular code its reference page and a short known cause. With code instead, the reference entry and the errors that carry it. An NG0100, a hydration mismatch or a missing provider adds its explainer. id, code
list-console Console calls, newest first: when, level, the text of the arguments and the Angular code it mentions. Calls repeated in a row show once with a count. level, search, since, limit
list-server-errors Errors on the dev server that no page reports, most recent first: SSR errors (a console.error during a server render, or Angular's ErrorHandler on the server) and Vite transform and compile errors. With id, one group with its message, Angular code, code frame and stack. kind, id, limit

list-server-errors reads what the server captured in its own process, so it needs the Express hub or the Vite plugin, not the stdio MCP server; Vite errors need the Vite plugin. kind is ssr or vite, and limit goes up to 100 (default 30). A group expires 30 minutes after its last repeat. See Server errors.

The explainers are the ones the Errors tab shows. For NG0100: the binding, the template function, the previous and current value, the component fields that hold the new value, and the named signals written with it just before the check, with the code that wrote them when write stacks are on. For NG0500 to NG0503: a diff of the server HTML Angular expected and the client DOM it found. For NG0201 and NullInjectorError: the token and Angular's dependency path, to pass to explain-injection.

code accepts NG0100, ng100 or NG01203. explain-error says so when Angular's error reference has no page for a code, and gives no known cause then. Pass the owner's instance id to inspect-component for its inputs and state. list-errors takes limit up to 100 (default 30), and list-console up to 200 (default 50). since keeps the console calls made since a duration back from now (30s, 5m, 1h), an ISO date or epoch milliseconds, so you can read what one reproduction logged. A call repeated in a row counts from its last repeat. The page keeps its last 200 calls and sends them while a panel or an agent watches, so an agent call to an idle page gets what it logged meanwhile. Messages, stacks and console text are masked like other live values.

Performance

This tool reads the web vitals the page measured. See Performance. Reads: page.

Tool What it answers Arguments
web-vitals LCP, INP, CLS, FCP and TTFB with value and web.dev rating, and the element, event and component behind each, then the slowest interactions, the long task count, the total blocking time and the latest long tasks. none

A metric the browser doesn't measure, or has no entry for yet, says none yet, and the answer names the entry types the browser lacks.

Build

These tools read what the app loads. See Build.

Tool What it answers Arguments
module-graph The Vite dev server's module graph: the entries, the lazy boundaries (import()) with the modules and size each pulls in, the biggest modules, and the slowest modules with the wall-clock time Vite spent resolving, loading and transforming each. With search, matching modules with their size, time, importers, imports and import() calls. search, limit
chunk-sizes The chunks of the last production build: initial or lazy, size, gzip size, and with stats.json the entry point. limit

module-graph needs the Vite plugin, in the dev server's process; it reads nothing on the stdio MCP server. Sizes are transformed, unminified code, for modules the browser requested. chunk-sizes reads the build output on disk, so it works anywhere the project is, and says how to build when there is none. limit defaults to 20 for module-graph (at most 200) and 30 for chunk-sizes (at most 500).

Audit

audit Action

One ranked list of what is wrong on the page, gathered from the other inspectors, with an axe pass over the app on request. See Audit. Reads: page.

Each finding has a severity, an area, the component, route or URL it is about, one line on why, and the tool to call for detail, with its arguments. The answer also lists key numbers (mean and slowest change detection cycle, wasted checks, retained components, open subscriptions after destroy, errors, axe violations and failed HTTP calls) and the areas it could not read, under Coverage.

Argument Required Value
axe no true runs axe-core over the app first. Without it, the audit uses the last axe pass on the page.
session no before saves this audit as the page's baseline. after audits again and compares with the baseline. clear drops the baseline.
area no accessibility, errors, hydration, change-detection, leaks, router, forms, http or pipes. accessibility also lists the elements that break each axe rule.
severity no error, warning or info: only findings at that severity or above.
limit no Rows to list, 1 to 200. Default 30.

The audit reuses each inspector's own checks: diagnose-change-detection hints and checks slower than 16 ms, find-leaks, explain-error, hydration, lint-routes, lint-forms, list-http-calls and scan-pipe-usage. Change detection numbers need a recording from change-detection. Retention is not judged on a page whose Angular keeps DI debug data, the same as find-leaks. An area whose inspector is off, or whose agent tools are hidden with agent.tools.<name>: false, is left out, and Coverage says which. With the Components agent tools hidden, axe findings name no component or instance id.

The axe pass loads axe-core into the page on demand and changes nothing in the app. It leaves out the overlay's own elements and frames, masks selectors, attributes and summaries, and leaves out text content. With agent.readOnly, the tool has no axe argument and is marked read-only. It refuses axe: true sent anyway, and session: "clear" and a session: "before" that would replace a baseline, so it never drops one the user took. Two audits that used the same axe pass don't compare accessibility, and a note says so. A reload of the tab drops its axe pass. A session is kept per page for 30 minutes after its last use, so it survives a reload of the tab. Comparing only works within one page id. See Inspect, fix and verify for the loop.

On an Angular Native or NativeScript app, the audit reads its change detection, leaks and errors, and sessions work as on a browser page. The app has no DOM, so axe: true answers that the pass did not run and why, and Coverage lists accessibility as off.

Analog

These tools cover *Analog apps. Most read your source. Some also read what the Vite plugin recorded.

Routes and files

Tool What it answers Arguments
analog-scan-routes File routes in match order: URL pattern, page or layout file, route groups, params, the sibling .server.ts, and route meta. filter
analog-scan-url Which files render a URL (layouts, page, .server.ts load), the params, or why nothing matches. url (required)
analog-scan-api-routes Server routes under src/server/routes with method, URL and file, plus server middleware. none
analog-scan-server-functions Server functions (serverFn exports in any .server.ts under src) with name, method, file and id, how often each ran over HTTP and during server rendering, and reads called again right after hydration. none
analog-scan-content Markdown content files with slug, frontmatter, the route that serves them and parse errors, plus mismatches with the analog.contentSchema file and where the app reads content files. filter
analog-scan-build The last client build in dist/analog/public: JS and CSS totals with gzip, the entry chunk, each page's chunk with what it loads beyond the entry, its lazy chunks, and the largest files. Says to run analog build first when there is none. none
analog-scan-nitro Nitro server plugins, tasks, storage mounts in vite.config, the routes cached by isr, swr or cache rules, and the cache entries on disk. none
analog-scan-runtime-config The import.meta.env keys, Nitro runtimeConfig from vite.config with NITRO_ env overrides, and the resolved analog() options. Secret names and tokens are masked. none

The running page

Tool What it answers Reads Arguments
analog-inspect-page The open page: its files (layouts first, then pages in named outlets with the outlet name), the load() data it received, server rendering and hydration state, and hydration errors. With data: true it asks the page for the full load() value, masked, up to 200 KB, and shows the first 20,000 characters of its JSON. A longer value is marked truncated, and the Data view shows all of it. page page, data
analog-inspect-transform Transforms a page, layout or .server.ts file again on the dev server and lists each plugin that changed it, in order, with the final code and whether each server function id is in it. Vite plugin file (required, as analog-scan-routes lists it), ssr
analog-list-server-calls Recent page renders, load() fetches, form actions (with their outcome), server functions by name and API calls, with status, time and size. Flags a load() fetched twice and a seeded server function read called again. Each call names its tab when the dev server could tell. Vite plugin kind (page, load, action, fn or api), route, limit, page (only that tab's calls; leave it out for every call, untagged ones included)

Rendering

Tool What it answers Arguments
analog-explain-render-modes For each page: server rendered, prerendered, cached, redirected or client only, the route rule or config that decides it, and what the last request actually did. Says when vite.config could not be read in full. none
analog-scan-prerender prerender.routes and routeRules with prerender: true, compared with the page files and the build output. Says when vite.config could not be read in full. none
analog-inspect-render-mode Requests a page route from the dev server with Accept: text/html and compares cache-control, x-nitro-prerender, x-analog-no-ssr and the HTML with the configured mode. Dynamic segments get a sample value. Reads: Vite plugin. path (required, a page route)

Call a server route Destructive

analog-run-api sends a request to a route on the running dev server, like GET /api/v1/hello, and returns the status, time and body. path is a path on the dev server that starts with a single /, not a full URL. POST, PUT, PATCH and DELETE need confirm: true. Secret keys, tokens and Bearer values in the body are masked. Reads: Vite plugin.

path must be an API route (under the API prefix, or any route in src/server/routes), an /_analog URL or a page of the app. The tool refuses Vite internals such as /@fs/ and /@id/, Vite query flags such as ?raw, ?url and ?import, . and .. segments, and any path that names a file or folder in the project, so it can't read your source or files outside the app.

Argument Required Value
path yes An API route, an /_analog URL or a page path.
method no GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS.
body no A JSON body.
confirm no Required for methods other than GET, HEAD and OPTIONS.
headers no Extra request headers by name. host, content-length and other headers fetch or the dev server owns are refused.
cookies no Cookies by name, sent as one cookie header.

Run a Nitro task Action

analog-run-nitro-task runs a task from src/server/tasks on the dev server through Nitro's dev task route (POST /_nitro/tasks/<name>) and returns its answer, masked and clipped to 4000 characters. The route answers only with nitro.experimental.tasks on; without it the tool says so. Tasks can change data, so the tool needs confirm: true and actions.analog. It stops waiting after 30 seconds. Reads: Vite plugin.

Argument Required Value
name yes The task name as analog-scan-nitro lists it, like db:migrate.
payload no An object the task receives as its payload.
confirm yes Must be true.

Purge the Nitro cache Destructive

analog-purge-nitro-cache deletes Nitro cache entry files from disk, so the routes cached by isr, swr or cache rules render again on the next request. It needs confirm: true and actions.analog. It deletes only the .json entries analog-scan-nitro lists, in a Nitro cache folder inside the project.

Argument Required Value
confirm yes Must be true.
files no Entry paths as analog-scan-nitro lists them. Leave it out for all.

Lint

analog-lint finds Analog mistakes: two files for one URL, a missing default export, a layout without router-outlet, bad API method suffixes, prerender entries that match nothing, frontmatter errors, frontmatter that does not match the content schema (content-schema), and a vite.config it could not read in full (config-partial). It also reports live problems, like a load() fetched twice, a server function read that runs again after hydration, or a restart needed. Hydration errors and restart hints come from one page: pass page to pick it, or leave it out for the default page. If no page with that id sends Analog data, the answer says so and lists the pages that do.

analog-list-server-calls and analog-run-api need the Vite plugin. The plugin records the calls and knows the dev server address.

Plugins

These tools read the views that Pangular plugins report from the page. Both read the page.

Tool What it answers
list-plugins The page plugins each page runs, with version, status and pages, and the server plugins with their tools and tiers. Takes no arguments.
inspect-plugin One plugin's view of a page as markdown: its tables, lists, stats and trees, its status, page actions and tools. Takes plugin (required, the plugin id) and limit (rows, 1-200).

A plugin's own tools

A server plugin adds tools named plugin:<plugin id>:<tool>, which your client calls as pangular_plugin_<plugin id>_<tool>. Built-in tools never start with plugin, so a plugin can't replace one. Each tool is read unless the plugin declares action or destructive, and its answer starts with a note that it comes from the plugin and the page. agent.readOnly and actions.plugins: false drop the tools that are not read. plugins.<id>.tools: false drops all of one plugin's tools and leaves the plugin out of list-plugins and inspect-plugin. MCP clients take tool names of up to 64 characters, so the server skips a plugin whose pangular_plugin_<plugin id>_<tool> name is longer.

Shared state

devframe_state_read reads the devtools' live shared state, for data no other tool covers. Call it without arguments to list the keys with their size and the tool that reads each one, then with key to read a value as compact JSON. It answers at most maxChars characters (default 20,000, at most 50,000) from offset and says where the next part starts. It leaves out the keys a resource serves and the keys of an inspector whose agent tools are hidden (agent.tools.<name>: false).

Use it for data that has no dedicated tool, such as hydration data and TransferState payloads (pangular:http, pangular:http-payloads) or live pipe usage (pangular:pipe-usage). See Resources for every key.

Renamed tools

Tools and arguments were renamed in 1.0.0 so that each name follows one pattern: an optional library prefix (ngrx-, redux-, tanstack-, capacitor-, analog-), then a verb that says whether the tool reads source (scan), reads the page (list, inspect, explain, lint) or writes (run, set, record). The old names are not accepted.

Before Now
get-routes, get-components, get-pipes, get-signals, get-providers scan-routes, scan-components, scan-pipes, scan-signals, scan-providers
get-ngrx-store, build-meta ngrx-scan, scan-build
lint-templates, lint-pipes, explain-render-mode scan-templates, scan-pipe-usage, scan-render-mode
inspect-signal-store, signal-store-history ngrx-inspect-store, ngrx-history
dispatch-ngrx-action, restore-ngrx-state ngrx-dispatch, ngrx-restore
inspect-ngrx-entry, export-ngrx-session, import-ngrx-session, generate-ngrx-test ngrx-inspect-entry, ngrx-export-session, ngrx-import-session, ngrx-generate-test
inspect-redux-stores redux-inspect-stores
list-queries, inspect-query, query-action tanstack-list-queries, tanstack-inspect-query, tanstack-run-query
list-capacitor-calls, list-capacitor-plugins capacitor-list-calls, capacitor-list-plugins
analog-routes, analog-explain-url, analog-api-routes analog-scan-routes, analog-scan-url, analog-scan-api-routes
analog-server-functions, analog-content, analog-prerender-plan analog-scan-server-functions, analog-scan-content, analog-scan-prerender
analog-current-page, analog-server-calls, analog-call-api, analog-render-modes analog-inspect-page, analog-list-server-calls, analog-run-api, analog-explain-render-modes
form-payload, form-history, form-diff, form-action, explain-form-invalid inspect-form-payload, list-form-changes, explain-form-changes, run-form-action, explain-invalid-forms
wait-for-form wait-for with condition: "form"
navigate with action: "navigate", "probe", "instrument", "resolve-lazy" navigate with action: "go", probe-route, record-guards, list-routes with resolveLazy
export-navigation explain-navigation with format: "repro"
http-waterfall list-http-calls with view: "waterfall"
change-detection with record, flash, track or angularProfiling record-change-detection
hydration with overlay highlight with hydration
pageId page
selector naming a component component
selector naming an injector injector
signal in set-signal property
storeId store, which also takes a store name
since as a forms marker or an NgRx seq after

Where to next