npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

app-hud

v0.8.0

Published

Review your running app, understand its structure, and plan changes with coding agents.

Readme

App HUD

Review your running app, understand its structure, and plan changes with coding agents. Preview pages live, pin feedback, inspect a source-backed map, and export decisions as work an agent can pick up and verify.

Migrating from Route Planner? App HUD uses new commands and .app-hud/ configuration. Follow the migration guide before opening an existing workspace.

App HUD on the example app

It keeps two layers apart:

  1. What the app is. Pages, layouts, links, menus, access rules and data calls, read from the code by a static scanner. Regenerated whenever you like (map.json).
  2. What people want it to be. Versions, notes, decisions, new pages, menu edits, roles and workflows. Stored as files in your repo (overlay/) and never overwritten by a scan.

The viewer draws layer 2 on top of layer 1. Export turns the difference into a plan and a list of change items, and check rescans the code to mark items done.

Every generated fact carries its source (file:line) and whether it's certain or inferred. Access rules and roles are always marked inferred: the scanner reads code and doesn't run it.

Supported frameworks

| Framework | Scanner | Notes | |---|---|---| | Next.js App Router, Vinext | scanner-next | app/ or src/app/, route groups, dynamic / catch-all / parallel / intercepting routes, route handlers, middleware / proxy.ts | | React Router 7 (framework mode) | scanner-react-router | app/routes.ts (route, index, layout, prefix), flatRoutes() file naming | | React Router 6/7 in code (library / data mode) | scanner-react-router | createBrowserRouter, useRoutes, <Routes><Route>, lazy routes, <Navigate>, basename, nested <Routes> under path="x/*", relative links | | Monorepos (turbo, pnpm / npm / yarn workspaces) | monorepos | Every app in one map, each in its own columns | | single-spa | scanner-single-spa | registerApplication and single-spa-layout; each micro-frontend's routes mounted under its prefix, links followed across apps, a navbar app shown as a menu on every page |

Other frameworks can be added behind the same interface; see adding a scanner.

Quick start

In your app's folder (the one with its package.json):

npx app-hud open

That's the whole setup. open:

  1. runs init if there's no .app-hud/ yet: it detects the framework, scans the app, and seeds roles and workflows;
  2. finds your app. If something already answers at the dev server it used last time (devServer in the config), it uses that. Otherwise it runs your dev script (directly, with node_modules/.bin on the PATH, so no package-manager install checks run first), shows its output, and waits until the URL it prints answers;
  3. starts a local proxy (default http://localhost:7420) with the viewer at /__app-hud/ and everything else forwarded to your app, and opens the viewer.

The preview runs on the same origin as the viewer, so your session cookie is sent and the viewer can read the page. Sign in through the proxy's address once. Ctrl+C stops the proxy and any dev server open started.

Pages behind a sign-in. Hosted sign-in pages (WorkOS AuthKit, Auth0, Clerk, Okta…) refuse to load inside frames. When a page in the preview redirects to one, the preview says so instead of showing "refused to connect". Click Sign in in a new tab, sign in there, then come back: the preview reloads on its own. The session cookie is shared with the preview even if the app's sign-in callback returns to its own port. Still sent to sign-in after that? The session probably expired or failed to refresh (two tabs refreshing at once can do it): sign out of the app and sign in again.

| You want | Run | |---|---| | A dev server that's already running somewhere else | npx app-hud open --target https://localhost:3000 (never starts anything) | | A different start command | set "devCommand": "pnpm run dev:all" in .app-hud/config.json, or pass --dev-command "…" once | | The whole stack from a monorepo root | set "devCommand": "pnpm dev", "devCwd": ".", or pass --dev-command "pnpm dev" --dev-cwd . once | | The viewer without the app | npx app-hud open --no-dev | | A monorepo root | npx app-hud open maps every app (or the single-spa setup); preview one of several separate apps with --app <id>. See monorepos. | | Just one app of a monorepo | npx app-hud init --app packages/web |

open prints the exact command before running it. A dev script with side effects (building assets, killing ports) runs as usual, so point devCommand at something narrower if you need to. If your pages need other services (an API, a database), start them too: have devCommand start the whole stack, or start it yourself and use --target.

A monorepo whose root dev script starts the backend too. By default, devCommand runs in the selected app's directory. pnpm dev in packages/web may start only the web app, while the same command at the repo root starts its platform/API services too. Set devCwd relative to the directory containing .app-hud/:

In .app-hud/config.local.json:

{
  "devCommand": "pnpm dev",
  "devCwd": ".",
  "devServer": "http://localhost:3000"
}

This starts the repo's dev command while keeping root: "packages/web" as the app being scanned. If the stack prints several server URLs, a configured devServer (or devServers[appId] for separate apps) takes priority when starting outside the selected app directory. open waits for an HTTP response, including an error status; it doesn't check backend health.

If the app works with your usual startup command but the preview reports backend 503s, start the repo normally and use npx app-hud open --target http://localhost:3000. If that still fails only through the proxy, the startup directory is no longer the cause; compare authentication and the failing requests on the app and proxy origins.

Then:

npx app-hud scan                      # after code changes (your notes are kept)
npx app-hud export --version <id>     # plan (.md) + change list (.json) in .app-hud/exports/
npx app-hud check  --version <id>     # rescan; mark change items the code now satisfies as done
npx app-hud versions                  # list versions

What you can do in the viewer

The viewer has five workspaces (top bar) and a lens that decides what the page inspector shows first. Everyone sees the same data; the lens only changes the order.

  • Review (the default): walk the app one page at a time. On the left, the page list, by area, with filters (all, decided, pins, scan issues, orphans). In the middle, the live page, through the proxy and signed in. On the right, the inspector: the decision (keep / change / merge / remove) first, then notes, comments and pins, scan findings to tick for the plan, page fields (URL, title, group, tier, access, locked state), access rules and code facts with their file:line, links in and out, menus, the live scan, and the agents' progress on the page. J / K step through the list, 1–4 decide, / searches.
  • Lenses: Engineer (code, access rules, links, what the page fetches), Design (the page and its comments), Lead (scan findings, tier, access, menus), Team (open pins and replies, notes, agent work; the list shows pages with pins).
  • Live page: desktop / tablet / mobile widths and two-way sync (pick a page → it loads; navigate in the page → the list follows). Scan compares the page's links with the map and records every fetch (Convex-style calls labelled module:function) with counts and polling rate, saved as observed data. Dynamic routes remember a sample URL.
  • Map: pages as cards in area columns with arrows for links; drag, pan, zoom, fit, auto-layout; filter by tier, choose which links to draw, hide removed pages, view as a role (dims pages it can't open). Selecting a page opens the same inspector.
  • Menus: each menu in the order the code renders it, with add, remove, reorder, notes, and whether it hides entries from roles that can't open them.
  • Roles & flows: each role's intent, the menus it sees, and entries it sees but can't open. Workflows are step lists (page + action) checked against the current version: can the role open each step, and how does it get there (link, menu, longer path, or no route)? Pick one to trace it on the map beside it.
  • Plan: the version's goals and changes from the baseline, the Markdown plan (copy, download, or save to exports/), and the change list agents can claim (see below).
  • Versions (the menu next to the app name): the baseline (the scanned app) is read-only; your first edit creates "Draft N". New, rename and delete versions, start a suggested draft built from what the scan noticed, or export / import a version as JSON. Each version is one file in overlay/versions/.

Files it writes

.app-hud/
  .gitignore           keeps out the two machine-specific parts below
  config.json          framework, app root, menu and role hints, sample URLs (shared)
  config.local.json    this machine's dev server and start command (ignored)
  map.json             generated facts; regenerate with `scan`
  overlay/
    versions/<id>.json one file per version: only the differences from the scan
    roles.json         roles (seeded from the code, marked inferred)
    workflows.json     workflows (seeded from menus and locked pages, marked inferred)
    layout.json        card positions
  observed/            what the live preview saw on this machine (ignored)
  exports/             plans and change lists agents work from

Commit the whole folder. Its own .gitignore leaves out observed/ and config.local.json; app-hud never edits your repo's .gitignore. JSON is written with sorted keys so it diffs cleanly, one file per version means two people editing different versions don't conflict, and a rescan that finds no route changes doesn't touch map.json, so its diffs show real route changes in pull requests. Page ids are URL patterns, so decisions survive rescans; a page that disappears keeps its notes and shows up as not in scan. The formats are described in docs/format.md.

Handing work to agents

export writes exports/<version>-<date>.json: a list of change items (remove, merge, change, add-page, nav-edit, link-add, link-remove, access-change). Each item has the files involved (from the scan), the notes people wrote, and acceptance checks phrased so a rescan can verify them:

  • "The scan shows a link /projects/[id] → /dashboard"
  • "/admin/billing has access owner"
  • "The scan no longer lists /legacy"

check rescans and marks an item done when all of its automatic checks pass. Checks that need a person ("the notes above are done") are listed but don't block.

MCP server

app-hud mcp runs an MCP server on stdio with these tools:

| Tool | What it does | |---|---| | map_summary | App, counts, menus, roles, orphans, versions and change-list progress | | get_page | One page: file, layouts, access rules, links in/out, menus, data calls, decisions and notes | | list_changes, get_change | The work a version implies (exported on first use) | | claim_change | Mark an item claimed by an agent | | complete_change | Rescan and run the item's checks; done only if they pass | | add_note, propose_change | Write notes or proposed decisions into an "Agent proposals" version, marked as coming from an agent | | list_pins, reply_to_pin | Read the comments, ideas and bugs pinned to the live app; reply with what changed and resolve them | | services | Backend services in the repo (Spring Boot) as JSON: endpoints, calls, data, topics, deployments and sidecars, each with its file and line | | diagnose | The app-hud diagnose report as JSON: this machine, its agents, the repo and app-hud's setup (pick sections with only) |

Register it with Claude Code from the repo that has .app-hud/:

claude mcp add app-hud -- npx app-hud mcp
# or, from a local checkout of this repo:
claude mcp add app-hud -- node /path/to/app-hud/packages/cli/dist/cli.js mcp --dir "$PWD"

A typical loop: list_changes → claim_change → edit the code → complete_change (or app-hud check) → the viewer's Changes tab shows it done.

Configuration

.app-hud/config.json (shared):

{
  "schema": 1,
  "root": "packages/web",          // app root, relative to the repo
  "framework": "vinext",           // next-app | vinext | react-router (detected by init)
  "appDir": "src/app",
  "menuFiles": ["src/components/AppSidebar.tsx"],  // when menu detection misses one
  "ignoreMenuFiles": [],
  "roles": ["viewer", "member", "admin"],         // lowest first, when role detection misses
  "entryPages": ["/"],             // never reported as orphans
  "devCommand": "pnpm run dev:all",  // optional team default for what `open` runs (default: the `dev` script)
  "devCwd": ".",                   // optional working directory relative to the repo; defaults to the app root
  "samples": { "/games/[gameId]": "/games/123" }  // captured by the preview
}

.app-hud/config.local.json (this machine, git-ignored) overrides it:

{
  "devServer": "https://localhost:3000",   // remembered by `open`; reused when it answers
  "devCommand": "BACKEND_URL=http://localhost:18787 vinext dev"   // only on this machine
}

Development

pnpm install
pnpm test          # fixtures in examples/, plus acceptance tests against local projects when present
pnpm typecheck
pnpm build         # core, scanners, viewer, CLI (the CLI bundles the viewer)
node packages/cli/dist/cli.js --help

Only packages/cli is published, as app-hud; it bundles the other packages (all marked private) and ships the built viewer. To release: pnpm build && cd packages/cli && npm publish.

Packages: core (formats, merging, analysis, plan, change checks), scanner-shared (import resolution, a small static evaluator, link / menu / gate extraction), scanner-next, scanner-react-router, viewer, dev-proxy, mcp, cli. The example in examples/next-app has a committed .app-hud/ you can open with node packages/cli/dist/cli.js open --dir examples/next-app.

Pins

Right-click an element in the live preview and pin a comment, idea or bug to it. Pins are for the team, so they're saved in the repo: one file each in .app-hud/overlay/pins/. Commit them with the rest of the overlay.

  • Whenever a pinned element is on screen in the preview, a marker sits on it. That includes elements that only appear later, like an opened dialog or a panel. Markers new to you pulse. Hover to outline the element, click to read the thread, reply or resolve.
  • Pins on shared navigation (nav, header, footer, sidebar) show on every page the element appears on.
  • Elements are found again by test id, stable id, selector with the same text, aria-label, then text, so they survive reloads and most code changes. A dashed marker means the element's text changed since it was pinned.
  • The page list and map cards show the number of open pins, and the inspector's Comments & pins section lists them. You can also pin a note to a whole page there, or by right-clicking the page in the list or on the map. The bar above the live page counts the pins on the current page, including any whose element isn't there.
  • Open pins go into exported plans, and agents can read, answer and resolve them over MCP (list_pins, reply_to_pin). Send to tracker… on a pin turns it into a prompt for your team's tracker (see below).
  • Names come from git config user.name.

Feedback

Right-click anything in the viewer (or use the Feedback buttons). Right-clicks come in through anyclick. Shift + right-click, and right-clicks in text fields, still give you the browser's own menu.

  • About app-hud itself (anywhere in the viewer): write what's wrong or what would be better, then review the issue. It goes to app-hud's GitHub repo: Submit with gh files it directly if the GitHub CLI is signed in, or Review on GitHub opens it prefilled in your browser. It includes the viewer area, the button you clicked, the version, framework and page count. It never includes your routes or page contents, and your home folder appears as ~.
  • About your app (a page card, or anything inside the preview): app-hud doesn't decide where your team tracks feedback. Pick the tracker (GitHub Issues, Linear, Jira or other) and the repo, team or project; it's saved in config.json as feedback. You get a prompt to copy to your agent. The prompt includes your note, the page, its source file, the URL, the element you clicked and the version's plan for that page. The agent files it with the tools it has (gh, a Linear or Jira MCP server). app-hud never connects to your tracker.

Backend services

npx app-hud services maps the backend services in a repo. Spring Boot is supported today, in Java or Kotlin, with Maven or Gradle, including multi-module builds. For each service it reports:

  • Identity: name (spring.application.name), module, build tool, Spring Boot and Java versions, port, context path, profiles.
  • API: every endpoint, with class-level prefixes (@RequestMapping on the controller) and the handler. It includes endpoints from modules the service depends on, and WebFlux router functions.
  • Calls: the other services and public APIs it calls, through Feign clients, HTTP interfaces, Spring Cloud Gateway and Zuul routes, URLs in config (orders.base-url) and URLs in code. Calls to another service in the repo are linked to it by name, lb:// name, Kubernetes or compose name, or localhost:<port>. Anything on the public internet is marked as a public API.
  • Data: databases (the JDBC URL says which one, per profile), MongoDB, Redis, Elasticsearch, Cassandra and cloud storage. Also entities and tables, repositories, and Flyway or Liquibase migrations.
  • Messaging: Kafka topics, RabbitMQ exchanges and queues, JMS and SQS, published and consumed, with consumer groups. Topic names written as constants, ${placeholders} and Spring Cloud Stream bindings are resolved. The summary shows each topic from producer to consumers.
  • Platform: Eureka or Consul, the config server, the OAuth2 issuer or provider, tracing (Zipkin, OpenTelemetry, Loki) and mail. When one of these is a service in the repo (a registry, a config server, an auth service), it's linked.
  • Runs as: Dockerfiles, docker compose, Kubernetes manifests and Helm charts, including ports and where the service is exposed (Ingress hosts, Istio routes, compose ports). Sidecars come from extra containers (Cloud SQL proxy, Fluent Bit, Envoy, oauth2-proxy…), init containers, annotations (Istio, Linkerd, Dapr, Vault agent, Consul) and namespaces labeled for injection.
  • Infrastructure: databases, brokers and caches defined in compose or Kubernetes, and which services use them.

Config is read from each module's application*.yml/.properties and bootstrap*, from YAML documents activated by a profile, from config-server files named after the service (shared/orders.yml), and from environment set by compose, Kubernetes and ConfigMaps (SPRING_DATASOURCE_URL counts as spring.datasource.url). If config or manifests live in another repo (a config-server repo, a GitOps repo), add it with --include ../config-repo,../deploy.

Values of password, secret, token and key settings are never read, and credentials are stripped from connection strings. Only src/main is scanned, since tests are full of localhost. Every fact carries the file and line it came from.

--mermaid prints a diagram of services, stores, topics and public APIs. --markdown prints the report and the diagram together, for docs or an agent. --json prints everything, and --all lists every endpoint. app-hud diagnose says when a repo has Spring Boot modules.

Diagnosing a setup

npx app-hud diagnose prints what app-hud (or an agent setting things up) needs to know about this machine and this repo:

  • Machine: OS and version, architecture (including Node running under Rosetta), CPU, memory, shell, and what it's running in (a terminal, Claude Code, Codex, CI).
  • Toolchain: Node, where it came from and version managers; npm, pnpm, yarn, bun and whether they match the repo's packageManager; git; gh and whether it's signed in; other runtimes (Python, Go, Rust, Ruby, Java, PHP, .NET, Deno, Docker).
  • Agents: Claude Code, Codex, Gemini CLI, Cursor, and the Claude, Codex and ChatGPT desktop apps: versions, and the context each one loads. That means skills by name (user, synced, plugin and project), commands, subagents, plugins, hooks, MCP servers, CLAUDE.md / AGENTS.md, Claude Code's memory for this project, and the agent instruction files in the repo.
  • Browsers: the default browser and its version, other installed browsers, and Playwright's browsers.
  • This repo: git state, lockfiles and monorepo tools, languages, each package's framework and whether app-hud can map it, libraries by category (data, state, auth, UI, server, database, testing, build, platform), other ecosystems (Python, Go, Rust, Ruby, PHP, Java, Elixir, Dart), API leads (OpenAPI, GraphQL, route folders), and deploy config. .env files are listed by name and never read.
  • app-hud: the CLI version and whether it's the latest, .app-hud/ and whether config.json loads, framework detection, how fresh the map is, pins and versions, the dev server, the viewer port, and which agents have the MCP server registered.

It reads names, versions and counts, never file contents, and changes nothing. Everything runs at once, and each check has a time limit, so it takes about a second. --json prints the same report for agents and scripts (agents can also call the MCP server's diagnose tool), --only agents,repo picks sections, and --offline skips the npm version check.

The report shows real paths and names: it's for you. To share it, use --share. It prints markdown with the names of your projects, packages, branches, skills, plugins and MCP servers replaced by counts ("25 user skills", "package 3"). Your home folder appears as ~, and dev commands and the time zone are left out. Frameworks, libraries and tool versions stay, since those are what a bug report needs.

Reporting problems

When a command fails in a way app-hud should have handled (it couldn't find your app, a crash), it offers to report it as a GitHub issue:

  • It shows the full report first: the error, versions, OS, the command, lockfile, counts of workspace packages and detected apps, and the output of diagnose --share (collapsed). It includes no file contents or package names, and your home folder appears as ~.
  • Default: open the issue in your browser to review, edit and submit. With the GitHub CLI (gh) signed in, you can submit straight from the terminal instead. If an open issue already has the same title, it links to that one.
  • It only asks in an interactive terminal: never under CI, MCP or scripts. Set APP_HUD_NO_REPORT=1 to turn it off.
  • Mistakes in how the tool was run (no init yet, a taken port, dependencies not installed) just print what to do.

To report something by hand: npx app-hud report "what went wrong".

Security

The proxy is for local development only. It binds to 127.0.0.1, accepts self-signed certificates from your dev server, and relaxes X-Frame-Options / frame-ancestors to same-origin so the app can be framed next to the viewer. Don't expose it to a network. The scanner reads source files statically: it never runs your app's code and doesn't read .env files, so plans and exports can't contain your secrets. See SECURITY.md.

License

MIT