All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.0.2] - 2026-11-11
- DOM-level JS tests for
loader.jsandpanel.jswiring and postMessage origin gate (ADR 06) - EXPLAIN tests on Postgres, a Postgres service in CI (ADR 08)
allowed_origins:for proxies and tunnels that rewrite the Host header (ADR 04)PhoenixDevToolbar.Report: read API over captured sessions for IEx and agents (ADR 13)- Shipped
usage-rules.mdand thephoenix-dev-toolbar-reportagent skill (ADR 13) - Standalone panel URL:
<path>/panel?path=...or the newest page, standalone mode (ADR 14) - Documented
data-pdt-*row attributes with raw values, for browser-driving agents (ADR 14) - MCP endpoint at
<path>/mcp, this machine only, read-only Report tools,mcp: false(ADR 15) - MCP
clients:option: own LAN addresses count as local, IP/CIDR allowlist,:any(ADR 15) - MCP client setup for Claude Code, Codex, Cursor and VS Code in README and usage rules (ADR 15)
- Panel sid check anchored with
\A...\z(ADR 14) - Standalone panel
?path=and newest page limited to MCP's clients rule (ADR 14) - One "this machine" rule:
actions:and Evalclients:take:local(ADR 10, ADR 12) - Eval default
clients:widened to:local, own LAN address included (ADR 12) - Agent setup guide; README
usage_rulesconfig made skills-only, block rewrite warned (ADR 13) - MCP refusals name the peer and the option; clearer "No captured page" errors (ADR 15)
[0.0.1] - 2026-11-10
First public release. A dev-only toolbar for Phoenix LiveView apps: a summary bar and panel
overlaid on the page you are working on, installed with one plug in the endpoint.
Tabs: Request, Ecto (queries, N+1 detection, EXPLAIN, JSON export), LiveView (lifecycle timings,
assigns, events, component tree), Process and System (any process, supervision trees, opt-in actions).
Opt-in Cluster and Eval plugins. Plugin API with a guide. Off outside MIX_ENV=dev.
- Project conventions: AGENTS.md, ADRs, roadmap,
mix precommit, CI matrix (ADR 00, ADR 06) PhoenixDevToolbar.enabled?/0runtime guard (ADR 01)- Bounded ETS event store: caps, flood guard, TTL sweep, LiveView DOWN cleanup (ADR 03)
- Payload truncation and key redaction helpers (ADR 03)
- Telemetry collector: plugin fan-out, crash quarantine,
$callersattribution (ADR 02) - LiveView session tracking: dead render link, reconnect, live navigation, nested (ADR 02)
- Registry based live notifications for panel subscribers (ADR 03)
- Built-in Request and Ecto collectors, default plugins (ADR 02)
PhoenixDevToolbar.Plug: page tracking, loader injection, asset serving (ADR 04)- Live panel served by the plug, no router changes: summary, Ecto and Request tabs (ADR 01, ADR 04)
- Loader (shadow DOM iframe, collapse state), panel JS and CSS, esbuild bundles (ADR 04)
mix devharness: SQLite demo app with N+1, events, Task.async and dead pages (ADR 06)- Prod compile check of a fixture host app installing the toolbar (ADR 01)
- Panel keeps following a tab after older sessions expire; no missed or out of order events (ADR 04)
- Bounded exception banners and plug options; panel asset URLs from the plug path (ADR 03, ADR 04)
- Toolbar disables itself, with a warning, in releases unless explicitly enabled (ADR 01)
- Panel UX: hide to a corner pill, HTTP/live query tags, timings, dropped badge, ARIA tabs (ADR 04)
- CI tests the minimum stack with LiveView 1.1 (ADR 06)
- Panel loads the host's own Phoenix and LiveView JS clients: no version skew (ADR 04)
- LiveView collector: callback and render timings, bounded assigns diff, push_event names (ADR 02)
- Bounded, budgeted redaction preview for assigns and LiveView params (ADR 03)
- LiveView tab: lifecycle profiler, callbacks badge and server event log (ADR 07)
- Assigns inspector: redacted snapshot through LiveView Debug, throttled refresh (ADR 07)
- Component tree, polled only while the panel is open and visible (ADR 07)
- Client event log: LiveView window events forwarded by the loader (ADR 04, ADR 07)
- JS unit tests for the loader helpers:
mix test.js, in precommit and CI (ADR 06) mix devpages: Components and Assigns (ADR 06)- Trimmed events badge in the summary bar; client event validation module (ADR 03, ADR 07)
- Public plugin behaviour,
usemacro, plugin options and config validation (ADR 05) - Per plugin event caps and a per session ceiling, limits documented in the README (ADR 03)
max_eventsnow caps each plugin per session, not the session (ADR 03)- Plugin panel shell: LiveComponent tabs, per plugin badges and trimmed notes (ADR 05)
- LiveView tab on the public panel API; PanelLive is generic glue (ADR 05, ADR 07)
- Plugin errors shown in their tab with Re-enable; panel side boundary for plugin code (ADR 05)
- Plugin guide in ExDoc, Oban example plugin, harness pages for jobs and plugin errors (ADR 05, ADR 06)
- Plugin boundary covers all of render/1; event plugin ids stamped by the collector (ADR 05)
- Panel seen seqs bounded per session; Config checks id and name; update/2 rejected (ADR 03, ADR 05)
- Ecto badge DOM id is
pdt-badge-ecto-queries(ADR 05) - Summary bar: badges that do not fit are counted in a "+N" chip that opens the panel (ADR 04)
- Callback spans:
Context.spanandEvent.span, the LiveView callback an event ran in (ADR 02) - N+1 detector: Ecto badge, groups and row tags,
n_plus_one:plugin option (ADR 08) - EXPLAIN capture: raw params of SELECTs kept in the event, bounded, never rendered (ADR 03, ADR 08)
- EXPLAIN button in the Ecto tab: rolled back, single SELECT, page scoped; SQLite test repo (ADR 08)
- N+1 groups merged by SQL and origin, Clear button, advice; EXPLAIN focus, names, Hide (ADR 08)
- Process tab: vital signs, sparklines, links and monitors, nested LiveViews; in
:defaults(ADR 09) - Process tab: GC now button, rate limited;
/memoryharness page (ADR 06, ADR 09) - Panel reload breaker: stops after 3 refused loads in 10 s, with a notice and Retry (ADR 04)
- Panel socket at
<path>/live: no host CSRF token or session needed; fixes the reload loop (ADR 04) - the plug's
:live_socket_pathoption is gone (ADR 04) - Panel socket review fixes: decoded join check, stale on unknown panels, host socket options (ADR 04)
- Panel: disconnected state, shorter cannot connect notice, inert tabs; Process tab wording (ADR 04, ADR 09)
- Docs: per-run disable recipe through
DEV_TOOLBAR=0(ADR 01) limits:overrides validated at boot; panelframe-ancestorsandnosniffheaders (ADR 03, ADR 04)- Public repo: renamed to
phoenix_dev_toolbar, GitHub install, CI badge, SECURITY.md - Stricter lint: Credo opt-in checks, Dialyzer unmatched returns; shared test page helpers (ADR 06)
- Ecto tab JSON export: short or full with EXPLAIN, download or copy (ADR 08)
- Ecto export fix: a Copy built before the LiveView joined is dropped; request path fallback (ADR 08)
- Toolbar reserves its page space so the page scrolls above it; draggable panel height (ADR 04)
- Toolbar docks: bottom, top, left, right; dock picker, sideways collapsed strip (ADR 04)
- Dock picker menu no longer clipped on side docks (ADR 04)
- Page space opt out:
reserve_spaceconfig and a dock menu toggle (ADR 04) - Ecto Copy never hangs: busy and crash answers, disabled during EXPLAIN (ADR 08)
- Ecto Download checks
rootis one of the page's sids (ADR 08) - Process addressing, protected set,
actions:loopback policy (ADR 10) Panel.navigate/3: switch to another tab with params (ADR 10)- System tab, now in
:defaults: any process by pid or name, crumbs, ancestors, state (ADR 11) - Process tab: every process is a link to the System tab (ADR 09)
- Process actions: kill (with reason), suspend 10 s with auto resume, watch, message peek (ADR 10)
- Redaction walks tuples, so queued messages and results are redacted too (ADR 10)
- System tab trees: a supervisor's children, the application list with top supervisors (ADR 11)
- System tab top: the 50 processes with the most memory, reductions or queue (ADR 11)
- System tab message trace: one process, 100 messages or 10 s, OTP 27 sessions (ADR 11)
- Cluster plugin (opt-in): connected nodes with round trip, processes, memory (ADR 12)
- Eval plugin (opt-in): read queries, code with allow: :eval, loopback by default (ADR 12)
- panel refuses host names that could be rebound; list yours in
allowed_hosts(ADR 04) - unset
enabledmeans on only in Mix:dev; prod under Mix is off (ADR 01) - panel socket requires a same-origin
Origin, whatever the hostcheck_origin(ADR 04) access-control-*headers stripped from panel and export responses (ADR 04)actions:defaults tofalse;:loopbackopts in; Eval refused only on explicit false (ADR 10, ADR 12)- Ecto params through the budgeted preview, 2 KB cap;
redact/2node budget (ADR 02, ADR 03) - Response hook catches throws and exits; injection drops a preset
content-length(ADR 04) - Collector failure path tests; hot path wording matches the code (ADR 02)
redact:adds to the defaults instead of replacing them (ADR 03)- Ecto repos default to the apps'
:ecto_repos, one warning when none (ADR 02, ADR 05) - Integer list params shown as lists, not charlists;
redact:entries validated (ADR 03) - Public moduledocs for the built-in plugins, ADR links, Setup and plugin groups in the docs (ADR 05)
- Experimental markers on the plugin API;
Truncate.changes/2andsnapshot/1are internal (ADR 05) Truncate.redact/2cuts what it does not walk instead of returning it; scalar structs redacted (ADR 03)