Directory → SKILL
SKILLbundledHermes Bundled Skills

Node Inspect Debugger

Debug Node.js via --inspect + Chrome DevTools Protocol CLI

debuggingnodejsnode-inspectcdpbreakpointsui-tuiBundledHermes skill
Last registry verification2026-08-18v1.0.0Hermes Agent
Plain meaning

What does it add to Hermes?

Debug Node.js via --inspect + Chrome DevTools Protocol CLI

Node Inspect Debugger is a skill related to the web and browser automation. It can let the agent open pages, read websites, or perform browser steps, depending on the tools the resource exposes.

This plain-language explanation is based on the publisher description. The original text remains visible for verification.

Use it when

Use it when your goal in the web and browser automation is clear and you can limit it to the data and actions it actually needs.

Skip it when

Do not add it merely to experiment when Hermes already has a simpler path, or when you cannot review its source and permissions.

Who is it for?

Best for users who want a repeatable way of working inside Hermes.

Safe first test

Start on a public site without signing in, and extract one heading before allowing clicks or typing.

Original publisher description

Debug Node.js via --inspect + Chrome DevTools Protocol CLI

✓
Data source

This entry was indexed from Hermes Bundled Skills. Our explanation interprets the type and domain without inventing a capability not present upstream.

!
Security review

The source is official or editorially reviewed, but you still need to review permissions and version compatibility.

Safe setup path

Inspect, install, then test.

  1. 01
    Open the source

    Match the publisher, license, and description to your need. Check the real update history.

  2. 02
    Review permissions and secrets

    Never paste a secret value into this site. Use environment-variable names and grant the smallest scope.

  3. 03
    Copy setup only after review

    The controls below copy text. They do not execute commands on your device.

  4. 04
    Test with a non-sensitive task

    Inspect the visible tools, then exclude write or delete tools you do not need.

Setup method

Already installed with Hermes.

This skill ships with Hermes and loads when the agent decides it is relevant. There is nothing to install; read the definition below so you know what it will do.

Open the official page ↗
The full skill definition

Exactly what Hermes loads when this skill runs.

Reproduced from the official documentation. Read it before enabling the skill: this text becomes the agent's instructions.

Debug Node.js via --inspect + Chrome DevTools Protocol CLI.

Skill metadata

A lookup table. Do not read it all; find the row that applies to you.

SourceBundled (installed by default)
Pathskills/software-development/node-inspect-debugger
Version1.0.0
AuthorHermes Agent
LicenseMIT
Platformslinux, macos, windows
Tagsdebugging, nodejs, node-inspect, cdp, breakpoints, ui-tui
Related skillssystematic-debugging, python-debugpy

Reference: full SKILL.md

Explains the idea itself. Read it slowly; the later sections build on it.

Overview

Explains the idea itself. Read it slowly; the later sections build on it.

When console.log isn't enough, drive Node's built-in V8 inspector programmatically from the terminal. You get real breakpoints, step in/over/out, call-stack walking, local/closure scope dumps, and arbitrary expression evaluation in the paused frame.

Two tools, pick one:

  • node inspect — built-in, zero install, CLI REPL. Best for quick poking.
  • ndb / CDP via chrome-remote-interface — scriptable from Node/Python; best when you want to automate many breakpoints, collect state across runs, or debug non-interactively from an agent loop.

Prefer node inspect first. It's always available and the REPL is fast.

When to Use

Explains the idea itself. Read it slowly; the later sections build on it.

  • A Node test fails and you need to see intermediate state
  • ui-tui crashes or behaves wrong and you want to inspect React/Ink state pre-render
  • tui_gateway child processes (_SlashWorker, PTY bridge workers) misbehave
  • You need to inspect a value in a closure that console.log can't reach without patching
  • Perf: attach to a running process to capture a CPU profile or heap snapshot

Don't use for: things console.log solves in under a minute. Breakpoint-driven debugging is heavier; use it when the payoff is real.

Quick Reference: `node inspect` REPL

A lookup table. Do not read it all; find the row that applies to you.

Launch paused on first line:

Shell3 lines
node inspect path/to/script.js
# or with tsx
node --inspect-brk $(which tsx) path/to/script.ts

The debug> prompt accepts:

CommandAction
c or contcontinue
n or nextstep over
s or stepstep into
o or outstep out
pausepause running code
sb('file.js', 42)set breakpoint at file.js line 42
sb(42)set breakpoint at line 42 of current file
sb('functionName')break when function is called
cb('file.js', 42)clear breakpoint
breakpointslist all breakpoints
btbacktrace (call stack)
list(5)show 5 lines of source around current position
watch('expr')evaluate expr on every pause
watchersshow watched expressions
repldrop into REPL in current scope (Ctrl+C to exit REPL)
exec exprevaluate expression once
restartrestart script
killkill the script
.exitquit debugger

In the repl sub-mode: type any JS expression, including access to locals/closure variables. Ctrl+C exits back to debug>.

Attaching to a Running Process

Explains the idea itself. Read it slowly; the later sections build on it.

When the process is already running (e.g. a long-lived dev server or the TUI gateway):

Shell8 lines
# 1. Send SIGUSR1 to enable the inspector on an existing process
kill -SIGUSR1 <pid>
# Node prints: Debugger listening on ws://127.0.0.1:9229/<uuid>

# 2. Attach the debugger CLI
node inspect -p <pid>
# or by URL
node inspect ws://127.0.0.1:9229/<uuid>

To start a process with the inspector from the beginning:

Shell3 lines
node --inspect script.js           # listen on 127.0.0.1:9229, keep running
node --inspect-brk script.js       # listen AND pause on first line
node --inspect=0.0.0.0:9230 script.js   # custom host:port

For TypeScript via tsx:

Shell3 lines
node --inspect-brk --import tsx script.ts
# or older tsx
node --inspect-brk -r tsx/cjs script.ts

Programmatic CDP (scripting from terminal)

Settings you configure once. Change one at a time so you can see what each does. Set NODE_PATH in your environment, not in the chat.

When you want to automate — set many breakpoints, capture scope state, script a repro — use chrome-remote-interface:

Shell3 lines
npm i -g chrome-remote-interface        # or project-local
# Start your target:
node --inspect-brk=9229 target.js &

Driver script (save as /tmp/cdp-debug.js):

JavaScript45 lines
const CDP = require('chrome-remote-interface');

(async () => {
  const client = await CDP({ port: 9229 });
  const { Debugger, Runtime } = client;

  Debugger.paused(async ({ callFrames, reason }) => {
    const top = callFrames[0];
    console.log(`PAUSED: ${reason} @ ${top.url}:${top.location.lineNumber + 1}`);

    // Walk scopes for locals
    for (const scope of top.scopeChain) {
      if (scope.type === 'local' || scope.type === 'closure') {
        const { result } = await Runtime.getProperties({
          objectId: scope.object.objectId,
          ownProperties: true,
        });
        for (const p of result) {
          console.log(`  ${scope.type}.${p.name} =`, p.value?.value ?? p.value?.description);
        }
      }
    }

    // Evaluate an expression in the paused frame
    const { result } = await Debugger.evaluateOnCallFrame({
      callFrameId: top.callFrameId,
      expression: 'typeof state !== "undefined" ? JSON.stringify(state) : "n/a"',
    });
    console.log('state =', result.value ?? result.description);

    await Debugger.resume();
  });

  await Runtime.enable();
  await Debugger.enable();

  // Set a breakpoint by URL regex + line
  await Debugger.setBreakpointByUrl({
    urlRegex: '.*app\\.tsx$',
    lineNumber: 119,       // 0-indexed
    columnNumber: 0,
  });

  await Runtime.runIfWaitingForDebugger();
})();

Run it:

Shell1 line
node /tmp/cdp-debug.js

Hermes-specific note: chrome-remote-interface is NOT in ui-tui/package.json. Install it to a throwaway location if you don't want to dirty the project:

Shell2 lines
mkdir -p /tmp/cdp-tools && cd /tmp/cdp-tools && npm i chrome-remote-interface
NODE_PATH=/tmp/cdp-tools/node_modules node /tmp/cdp-debug.js

Debugging Hermes ui-tui

A troubleshooting section. Find the symptom that matches yours rather than reading it end to end. Commands here: npm run build.

The TUI is built Ink + tsx. Two common scenarios:

Debugging a single Ink component under dev

ui-tui/package.json has npm run dev (tsx --watch). Add --inspect-brk by running tsx directly:

Shell5 lines
cd <hermes-agent-repo>/ui-tui
npm run build    # produce dist/ once so transpile isn't needed on first load
node --inspect-brk dist/entry.js
# In another terminal:
node inspect -p <node pid>

Then inside debug>:

Text2 lines
sb('dist/app.js', 220)     # or wherever the suspect render is
cont

When it pauses, repl → inspect props, state refs, useInput handler values, etc.

Debugging a running hermes --tui

The TUI spawns Node from the Python CLI. Easiest path:

Shell12 lines
# 1. Launch TUI
hermes --tui &
TUI_PID=$(pgrep -f 'ui-tui/dist/entry' | head -1)

# 2. Enable inspector on that Node PID
kill -SIGUSR1 "$TUI_PID"

# 3. Find the WS URL
curl -s http://127.0.0.1:9229/json/list | jq -r '.[0].webSocketDebuggerUrl'

# 4. Attach
node inspect ws://127.0.0.1:9229/<uuid>

Interacting with the TUI (typing in its window) continues to advance execution; your debugger can pause it on a breakpoint at any sb(...).

Debugging SlashWorker / PTY child processes

Those are Python, not Node — use the python-debugpy skill for them. Only Node portions (Ink UI, tui_gateway client, tsx-run tests under ui-tui/) use this skill.

Running Vitest Tests Under the Debugger

A troubleshooting section. Find the symptom that matches yours rather than reading it end to end.

Shell3 lines
cd <hermes-agent-repo>/ui-tui
# Run a single test file paused on entry
node --inspect-brk ./node_modules/vitest/vitest.mjs run --no-file-parallelism src/app/foo.test.tsx

In another terminal: node inspect -p <pid>, then sb('src/app/foo.tsx', 42), cont.

Use --no-file-parallelism (vitest) or --runInBand (jest) so only one worker exists — debugging a pool is painful.

Heap Snapshots & CPU Profiles (Non-interactive)

Explains the idea itself. Read it slowly; the later sections build on it.

From the CDP driver above, swap Debugger for HeapProfiler / Profiler:

JavaScript7 lines
// CPU profile for 5 seconds
await client.Profiler.enable();
await client.Profiler.start();
await new Promise(r => setTimeout(r, 5000));
const { profile } = await client.Profiler.stop();
require('fs').writeFileSync('/tmp/cpu.cpuprofile', JSON.stringify(profile));
// Open /tmp/cpu.cpuprofile in Chrome DevTools → Performance tab
JavaScript6 lines
// Heap snapshot
await client.HeapProfiler.enable();
const chunks = [];
client.HeapProfiler.addHeapSnapshotChunk(({ chunk }) => chunks.push(chunk));
await client.HeapProfiler.takeHeapSnapshot({ reportProgress: false });
require('fs').writeFileSync('/tmp/heap.heapsnapshot', chunks.join(''));

Common Pitfalls

Explains the idea itself. Read it slowly; the later sections build on it.

  1. Wrong line numbers in TS source. Breakpoints hit the emitted JS, not the .ts. Either (a) break in the built dist/*.js, or (b) enable sourcemaps (node --enable-source-maps) and use sb('src/app.tsx', N) — but only with CDP clients that follow sourcemaps. node inspect CLI does not.
  1. --inspect vs --inspect-brk. --inspect starts the inspector but doesn't pause; your script races past your first breakpoint if you attach too late. Use --inspect-brk when you need to set breakpoints before any code runs.
  1. Port collisions. Default is 9229. If multiple Node processes are inspecting, pass --inspect=0 (random port) and read the actual URL from /json/list:
Shell1 line
   curl -s http://127.0.0.1:9229/json/list   # lists all inspectable targets on the host
  1. Child processes. --inspect on a parent does NOT inspect its children. Use NODE_OPTIONS='--inspect-brk' node parent.js to propagate to every child; be aware they all need unique ports (Node auto-increments when NODE_OPTIONS='--inspect' is inherited).
  1. Background kills. If you Ctrl+C out of node inspect while the target is paused, the target stays paused. Either cont first, or kill the target explicitly.
  1. Running node inspect through an agent terminal. It's a PTY-friendly REPL. In Hermes, launch it with terminal(pty=true) or background=true + process(action='submit', data='...'). Non-PTY foreground mode will work for one-shot commands but not for interactive stepping.
  1. Security. --inspect=0.0.0.0:9229 exposes arbitrary code execution. Always bind to 127.0.0.1 (the default) unless you have an isolated network.

Verification Checklist

Explains the idea itself. Read it slowly; the later sections build on it.

After setting up a debug session, verify:

  • [ ] curl -s http://127.0.0.1:9229/json/list returns exactly the target you expect
  • [ ] First breakpoint actually hits (if it doesn't, you likely missed --inspect-brk or attached after execution completed)
  • [ ] Source listing at pause shows the right file (mismatch = sourcemap issue, see pitfall 1)
  • [ ] exec process.pid in repl returns the PID you meant to attach to

One-Shot Recipes

Explains the idea itself. Read it slowly; the later sections build on it.

"Why is this variable undefined at line X?"

Shell9 lines
node --inspect-brk script.js &
node inspect -p $!
# debug>
sb('script.js', X)
cont
# paused. Now:
repl
> myVariable
> Object.keys(this)

"What's the call path into this function?"

Text4 lines
debug> sb('suspectFn')
debug> cont
# paused on entry
debug> bt

"This async chain hangs — where?"

Text4 lines
# Start with --inspect (no -brk), let it run to the hang, then:
debug> pause
debug> bt
# Now you see the stuck frame