Inspector

The Inspector is a browser UI for looking at a running B4.run app's runtime state. It ships as its own package, @b4run/inspector, and opens with b4 inspect. The first panel is Memory, where you browse, search and govern the app's long-term memory records.

LaunchingCopy link to section: Launching

bash
b4 inspect

The CLI starts the inspector's server on 127.0.0.1 at a free port, prints the URL and opens your browser. It takes these flags:

  • --cwd <path>: inspect a different app root (defaults to the current directory).
  • --port <number>: bind to a stable localhost port instead of a free one.
  • --env-file <path>: load a .env file before resolving the store. It overrides b4.config.ts env and the default ./.env, the same precedence as b4 dev.

Apps scaffolded with create-b4-app ship the inspector as a devDependency. In an existing app, install it once:

bash
npm i -D @b4run/inspector

b4 inspect resolves the package from the app's own node_modules. If it's missing, the command prints the install hint and exits.

Which store it inspectsCopy link to section: Which store it inspects

The inspector serves the app's live memory store. It loads your b4.config.ts and uses config.memory.store just as the dev server does. The default SQLite store, the pgvector backend and custom MemoryStore implementations all work unchanged.

The inspector runs as a separate process, so two caveats apply:

  • It constructs a second store instance from your config. For SQLite that's a second connection to the same database file. For Postgres it's a second connection pool. Both are safe, but count it against connection limits.
  • The store must be constructible from config alone. If a store closes over live objects created elsewhere in your server process, the inspector can't re-create it.

The Memory panelCopy link to section: The Memory panel

  • Browse and filter: every record across namespaces and statuses (not only candidates), with facet counts by status, kind, namespace and source type.
  • Search: ranked search that matches recall. It runs the same IDF-weighted keyword ranking as the agent's recall tool. When your config declares a vector embedder and the provider key is available (for example via --env-file), it runs the same hybrid keyword + vector fusion.
  • Live refresh: lists and facet counts poll every 2 seconds while the tab is visible, so agent writes show up as they happen.
  • Detail sheet: the full record (data, tags, confidence, source, supersession links) with the governance actions below.
  • Approve: promotes a candidate with the same supersede-aware reconciliation as b4 memory approve. A contradicting active record with the same identity is superseded (history preserved), an identical one dedupes the candidate, and otherwise the candidate activates. When approving would supersede an active memory, the sheet shows a callout and the button reads Approve & supersede.
  • Reject / Forget: hard-delete a candidate or any record, each behind a confirmation prompt.

Timeline viewCopy link to section: Timeline view

With episodic memory enabled, the panel's list/timeline toggle switches to a timeline of what the agent did: records grouped by day, each row showing the time it happened, an outcome badge (ok/error for auto-recorded runs, authored for agent-written episodes), the episode summary, and the run duration. A window select (24h / 7d / 30d / all) narrows the timeline, and the kind filter defaults to episodic there. Clicking a row opens the same detail sheet as the list.

Like agent recall, the panel excludes expired episodes. Search always excludes them, because it mirrors what the agent's recall can see. To debug retention, the list API accepts includeExpired=1 to reveal rows that are past their TTL but not yet pruned.

Security postureCopy link to section: Security posture

The inspector is a local development tool:

  • The server binds to 127.0.0.1 only, so it's never reachable from the network.
  • Every API route verifies the Host header and rejects state-changing requests with a foreign Origin. This protects against CSRF and DNS rebinding from other pages open in your browser.
  • Destructive actions (reject, forget) require an explicit confirmation in the UI.