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

@matthamlin/dash

v0.0.2

Published

Dash is a local-first attention dashboard. It collects signals from plugins, stores them as normalized attention items, ranks the active inbox, and gives a small web UI for reviewing, snoozing, dismissing, completing, or opening the source of each item.

Readme

Dash

Dash is a local-first attention dashboard. It collects signals from plugins, stores them as normalized attention items, ranks the active inbox, and gives a small web UI for reviewing, snoozing, dismissing, completing, or opening the source of each item.

The app is packaged as @matthamlin/dash. In local use it runs as a Node/Bun CLI-backed web app with a SQLite database under the user's data directory. The same Hono API can also run as a Cloudflare Worker with a D1 database binding for deployed API persistence.

What Dash Does

Dash is intended to answer one question: "What needs my attention now?"

It does that by:

  • Registering source plugins such as Codex sessions, GitHub, Dodo, and command harnesses.
  • Refreshing plugins into a shared attention item model.
  • Ranking active items by priority, due dates, source urgency, recency, snoozes, pins, and manual boosts.
  • Recording plugin refreshes, plugin actions, and schedule runs as auditable run records.
  • Producing scheduled Morning Brief items from the current inbox, optionally through a harness plugin such as Codex, Claude, Pi, or OpenCode.

The dashboard UI has two main routes:

  • / shows the ranked inbox, selected item details, item actions, and recent runs.
  • /settings shows plugin health/toggles and Morning Brief schedule settings.

Getting Started

Install dependencies from the repo root:

bun install

Build Dash:

bun run --cwd apps/dash build

Start the packaged local app:

bun run --cwd apps/dash start -- --port 3867

Dash starts on http://127.0.0.1:3867/ by default and opens the browser automatically. Use --no-open for automation:

bun run --cwd apps/dash start -- --no-open --host 127.0.0.1 --port 3867

For UI development, use the Vite dev server:

bun run --cwd apps/dash dev

The CLI command loads the built RSC server from dist/rsc/index.js, so run the build before using dash start or the package-local start script.

Local Data

Local Dash uses SQLite through bun:sqlite when running under Bun and node:sqlite otherwise. The database file is named dash.sqlite.

The default data directory is resolved in this order:

  • DASH_DATA_DIR, when set.
  • $XDG_DATA_HOME/dash, when XDG_DATA_HOME is set.
  • ~/Library/Application Support/dash on macOS.
  • %APPDATA%/Dash on Windows.
  • ~/.local/share/dash on other platforms.

For isolated testing or demos, set DASH_DATA_DIR:

DASH_DATA_DIR="$(mktemp -d)" bun run --cwd apps/dash start -- --no-open

Available Commands

Run these from the repo root unless noted.

| Command | Purpose | | -------------------------------------------- | ---------------------------------------------------------- | | bun run --cwd apps/dash dev | Start the Vite development server. | | bun run --cwd apps/dash build | Build the RSC app and CLI entrypoint into dist/. | | bun run --cwd apps/dash start -- --no-open | Start the built local dashboard without opening a browser. | | bun run --cwd apps/dash test | Run Dash unit and Node test suites. | | bun run --cwd apps/dash type-check | Type-check the app. | | bun run e2e:dash | Build Dash and run the Playwright dashboard smoke suite. | | bun run format:updated | Format changed files. | | bun run ci | Run the repo quality gate. |

Before handing off changes in this repo, run:

bun run format:updated
bun run ci

Architecture

Dash has a deliberately small runtime split:

  • src/server.tsx creates the Worker-compatible Hono app, mounts API routes, then delegates page rendering to Guava RSC routes.
  • src/local-server.ts wraps the built app with a Node server, static asset serving, local storage, local built-in plugins, and the in-process scheduler.
  • src/cli.ts is the published dash executable. It finds an available port, loads the built app, starts the local server, and handles shutdown.
  • src/dash-api.ts owns the HTTP API shared by local and Worker runtimes.
  • src/dash-store.ts owns the persistence model and database queries.
  • src/dash-local-database.ts adapts Bun/Node SQLite to the store interface.
  • src/worker-api.ts adapts a Cloudflare D1 binding named DB to the same store interface.
  • src/dash-plugin.ts defines the plugin contract, registry, refresh flow, actions, health state, and config defaults.
  • src/dash-inbox.ts ranks items and maps item actions to state patches or source targets.
  • src/dash-scheduler.ts owns the Morning Brief schedule and the timer-backed local scheduler.
  • src/dash-dashboard.tsx and src/dash-client-data.tsx provide the client UI and API-backed client state.

The UI uses React 19, Guava RSC, Hono, Tailwind CSS, Vite, and the local Switchboard package for client-side data state.

Persistence Model

The store creates and maintains these tables:

  • items: source-owned attention items keyed by plugin/source identity.
  • item_state: user-owned state for read, done, dismissed, snoozed, pinned, and manual boost data.
  • plugins: registered plugin metadata, enablement, health, and last refresh time.
  • plugin_config: persisted plugin configuration JSON.
  • settings: app-level settings such as the default harness plugin.
  • schedules: schedule definitions, currently including the default Morning Brief.
  • runs: plugin refresh, plugin action, and schedule run history.
  • schema_migrations: lightweight schema bookkeeping.

Source data and user state are split so a plugin can refresh an item without erasing local review state.

HTTP API

The API is mounted under /api/v1.

| Route | Purpose | | --------------------------------------- | ------------------------------------------------------------------------------------------ | | GET /health | Health check. | | GET /items | List stored attention items. | | GET /inbox | List ranked inbox items. Supports includeDone, includeDismissed, and includeSnoozed. | | POST /items/refresh | Upsert items for a plugin. Useful for manual ingestion and tests. | | PATCH /items/:itemId/state | Apply item state directly. | | POST /items/:itemId/actions/:actionId | Run a built-in item action, source open action, or plugin action. | | GET /plugins | Sync and list registered plugins. | | PUT /plugins/:pluginId | Update plugin metadata and enabled state. | | GET /plugins/:pluginId/config | Read stored plugin config. | | PUT /plugins/:pluginId/config | Replace stored plugin config. | | POST /plugins/:pluginId/refresh | Refresh one plugin. | | POST /plugins/refresh | Refresh every registered plugin. | | GET /runs | List recent run records. | | GET /settings | Read app settings. | | PUT /settings | Update app settings. | | GET /schedules | Ensure and list schedules. | | PUT /schedules/:scheduleId | Create or update a schedule. | | POST /schedules/:scheduleId/run | Run a schedule immediately. |

When the Worker runtime has no DB binding, API routes that need storage return 503 Dash API store is not configured.

Plugins

Plugins turn external or local signals into attention items. A plugin is an object with:

  • pluginId: stable source identifier.
  • name: display name.
  • description: optional display/help text.
  • configSchema: typed config fields and defaults.
  • refresh(context): returns attention items, health, and optional run output.
  • actions: optional item or harness actions.

The registry persists plugin defaults on sync, skips disabled plugins during refresh, catches failed plugins without stopping the rest of a refresh-all run, updates plugin health, and records each refresh/action in runs.

Built-in Plugins

The Worker registry currently includes only:

  • manual: stores attention items submitted directly through the API.

The local server registry includes the Worker plugins plus:

  • codex-harness: scans local Codex session logs and can run prompt actions through codex.
  • claude-harness: runs scheduled prompts through the Claude CLI.
  • pi-harness: runs scheduled prompts through the Pi CLI.
  • opencode-harness: runs scheduled prompts through the OpenCode CLI.
  • github: collects GitHub issues and pull requests through the local gh CLI.
  • dodo: collects local repo tasks from .dodo/tasks.jsonl files.

Harness plugins expose the shared run-harness-prompt action. The Morning Brief schedule can call that action to turn ranked dashboard data into a generated brief.

Adding A Plugin

Create a plugin factory that returns AttentionPlugin, then register it in the appropriate registry:

  • Add deploy-safe plugins to src/builtin-plugins.ts.
  • Add local-only plugins that shell out, scan local files, or depend on local credentials to src/local-built-in-plugins.ts.

Minimal shape:

import type { AttentionPlugin } from "./dash-plugin.ts";

export function createExamplePlugin(): AttentionPlugin {
  return {
    pluginId: "example",
    name: "Example",
    description: "Collects example attention items.",
    configSchema: {
      fields: [
        {
          key: "maxItems",
          label: "Max items",
          type: "number",
          defaultValue: 10,
        },
      ],
    },
    async refresh(context) {
      let maxItems = typeof context.config.maxItems === "number" ? context.config.maxItems : 10;

      context.log("Refreshing example plugin", { maxItems });

      return {
        items: [
          {
            pluginId: context.pluginId,
            sourceId: "example-1",
            kind: "example",
            title: "Example item",
            priority: "normal",
            metadata: {
              sourceUrgency: 1,
            },
          },
        ],
        health: {
          status: "healthy",
          message: "Example plugin refreshed",
        },
      };
    },
  };
}

Use stable sourceId values. Reusing the same pluginId and sourceId lets Dash update an item in place while preserving its user state.

Plugin Item Guidance

Good attention items include:

  • A stable sourceId.
  • A compact kind such as github.pr, dodo.task, or codex.session.
  • A clear title.
  • body text that explains why the item matters.
  • url or metadata such as sourcePath, filePath, or path when the item can be opened.
  • priority when the source has a strong signal.
  • dueAt when the source has a real deadline.
  • metadata.sourceUrgency for source-specific ranking pressure.
  • metadata.dashActions when the item should expose plugin-backed actions.

Avoid using refresh output as a side-effect channel. A refresh should collect and normalize signals; actions should perform mutations or external follow-up work.

Scheduling

Dash currently ships one default schedule: morning-brief.

The schedule:

  • Is created lazily by ensureDefaultSchedules.
  • Starts disabled.
  • Runs daily after its configured local time.
  • Refreshes selected source plugins, or all non-manual non-harness source plugins if no selection is configured.
  • Ranks the current inbox and builds a prompt from the top items.
  • Optionally sends that prompt to the selected/default harness plugin.
  • Stores the result as a manual brief.morning attention item.
  • Records the schedule run in runs.

The local server starts startDashScheduler, which checks due schedules every minute while dash start is running. That timer is the local runtime path. A future cron or OS scheduler should call the same runDueSchedules(...) logic rather than replacing the in-process local behavior.

Deployment

Dash is configured as a Cloudflare Worker app in wrangler.jsonc.

To deploy persistent API routes, configure a D1 database binding named DB:

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "dash",
      "database_id": "...",
    },
  ],
}

Then run:

bun run --cwd apps/dash deploy

Local-only plugins are intentionally not registered in the Worker runtime because they depend on local files, local CLIs, or local credentials. Promote a plugin to builtin-plugins.ts only when it is safe and useful in the Worker environment.

Testing

Dash has focused tests around:

  • CLI option parsing.
  • API behavior.
  • Local server behavior.
  • Store persistence and item state.
  • Inbox ranking and item actions.
  • Plugin registry refresh/action behavior.
  • Built-in plugins.
  • Scheduler and Morning Brief behavior.
  • Package metadata for the published CLI.

Run the app suite:

bun run --cwd apps/dash test

Run the app E2E suite:

bun run e2e:dash

The E2E suite builds the app, starts the packaged CLI with an isolated temporary DASH_DATA_DIR, seeds an inbox item through the API, and verifies the dashboard can complete it.

Maintenance Notes

  • Keep published runtime dependencies free of workspace:* entries. Local workspace packages used for build/test integration belong in devDependencies; src/__tests__/package.test.ts enforces that the published CLI has no workspace runtime dependencies.
  • Keep local-only behavior in local-server.ts or local-built-in-plugins.ts. The Worker path should remain deploy-safe and not assume access to local files, local shells, or user credentials.
  • Preserve the shared API/store boundary. Local SQLite and Worker D1 both adapt to the DashDatabase interface used by createDashStore.
  • Make plugin refreshes idempotent. Use stable source identities and return the current source state instead of appending duplicate items.
  • Record external mutations as plugin actions. Actions get their own run records and can return itemStatePatch when the UI should update the item after the action succeeds.
  • Update tests near the layer being changed. Plugin contract changes should cover dash-plugin.test.ts; ranking changes should cover dash-inbox.test.ts; schedule changes should cover dash-scheduler.test.ts; local server packaging changes should cover E2E where possible.
  • Keep scheduler changes compatible with local dash start. The current app expects due schedules to run while the local server is alive.
  • When adding config fields, provide defaults in the plugin schema and consider whether the current settings UI needs a new editor surface. Plugin config can already be read/written through the API.

Troubleshooting

Dash has not been built. Run bun run build before dash start.

Build the app first:

bun run --cwd apps/dash build

Dash API store is not configured

The Worker runtime does not have a DB binding. Add the D1 binding in wrangler.jsonc, or run the local CLI-backed server.

No available port found starting at 3867

Pass a different port:

bun run --cwd apps/dash start -- --port 5195

Plugin refresh reports an auth or command failure.

Check the plugin's config through the settings/API and verify the local CLI it uses is installed and authenticated. The github plugin requires gh auth status to pass before it collects items.