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

@brightmotion/agenthog

v0.11.0

Published

AgentHog analytics CLI — `ah login`, then query traffic, sessions, funnels and more from the terminal

Readme

ah — the AgentHog CLI

The agent-friendly read surface for AgentHog analytics: dense, aligned, LLM-friendly terminal reports — traffic, sessions, funnels, campaigns, retention, and more. Every command also takes --json.

Install & authenticate

npm i -g @brightmotion/agenthog

ah login          # opens your browser — sign in, authorize, done
ah digest         # you're in business

ah login stores a scoped API token in ~/.config/agenthog/config.json (mode 0600). Prefer env-only auth (CI, unattended agents)? Mint a token in the dashboard (or via ah login on your machine and copy it) and set AH_TOKEN — it takes precedence over the config file and never needs a browser:

AH_TOKEN=ah_tok_… ah digest --json

Self-hosted AgentHog? ah login --host https://your-agenthog.example (or set AH_API_URL alongside AH_TOKEN).

ah whoami         # which account/token/scope am I using?
ah version        # which ah is installed (--check asks npm for the latest)
ah logout         # revoke the login token and forget it

Staying up to date

When it's talking to a real terminal, ah asks the npm registry once a day whether a newer release exists, and prints this after the command until you update:

ah: update available — 0.2.0 → 0.3.0 (update with: npm i -g @brightmotion/agenthog)
    silence this with AH_NO_UPDATE_CHECK=1

The answer is cached in ~/.config/agenthog/update-check.json, so 23 of every 24 hours the notice costs nothing at all. On the one run that does probe, the request overlaps your command and is abandoned 750ms after the command finishes — a registry that is slow, offline, or silently dropping packets can delay ah by that much and no more, and the attempt is recorded either way so it won't retry until tomorrow.

It stays off for anything that isn't a human: AH_NO_UPDATE_CHECK=1, CI, non-tty stderr (so agents and pipelines never see it), and repo checkouts. ah version --check asks on demand.

Global flags

| flag | meaning | |---|---| | --project <key\|name> | which site (optional if only one project is in scope) | | --since 24h\|7d\|30d\|Nd\|YYYY-MM-DD | time window (default 7d) | | --all | include crawler + suspected-bot + test sessions (default: humans only) | | --server | the default PLUS server sessions (token-authed relays) — for a funnel or campaign whose steps are relayed from a backend into one session, without admitting crawlers | | --bots | ONLY crawler + suspected-bot sessions | | --test | ONLY sessions from your listed test IPs (your own dev/QA traffic) | | --json | raw JSON instead of tables |

Default filtering is humans + unknown — bots, crawlers and test traffic are excluded from aggregates unless you pass --all.

Verbs

| verb | what it answers | |---|---| | traffic | per-day sessions by classification + by-source breakdown | | active [--weekly\|--monthly] | DAU/WAU/MAU (--by <dim> for breakdowns) | | retention [--cohort day\|week\|month] | cohort retention triangle | | campaigns [--source X] | per-campaign sessions, conversion %, junk % (bot share) | | referrers | sources ranked by engaged-visitor rate | | events [--name N] / events top | recent events / event names ranked by count | | sessions list [filters] | session rows (--converted --returning --bounced --utm-source --utm-campaign --variant) | | sessions show <id> | one session as a readable timeline (the narrative input) | | funnel <name \| step1 step2 …> | ordered-subsequence funnel; --per-session, --by <dim> | | funnels save <name> <steps…> / funnels list | persist a funnel definition | | paths --to <event> | common event paths ending at a target (funnel discovery) | | user <email\|anonId> | one person across all their sessions | | users [--tag T] [--returning] | identity rows | | clicks <path> | click targets on a page + dead clicks + rage clicks | | crawlers | request-log crawler hits incl. AI-crawler subtotal | | digest | one dense report: totals, deltas, top campaigns/sources/pages/events, friction | | changes list/add/show/… | a changelog timeline to line up against traffic | | track <event> [--at …] [--person …] [--prop k=v] | write one event, now or backdated (write token) | | track --file <csv\|ndjson> … | bulk-import history from a file — --dry-run first (write token) | | goals set <name> <event> / goals list | define a conversion goal | | reports create <slug> --file report.md / reports read <slug> | publish a shared report (markdown + live ```widget fences) the whole org can open; read prints it resolved, preview validates a file first (create/update/delete need a write token) | | projects list / projects create <name> --domains a,b | manage sites (create needs a write token; in early access new sites are approval-gated — request one from the dashboard) | | sql "<query>" | SQL escape hatch (token mode: read-only, scoped to your projects) | | version [--check] | which ah is installed; --check asks npm whether it's current |

Examples

ah digest --since 30d                              # the daily standup view
ah campaigns --since 30d                           # which ad is actually working
ah sessions list --converted                       # who converted
ah sessions show 831ac66d                          # one person's full visit
ah paths --to "form_submit: waitlist"              # discover the funnel
ah track deploy_completed --prop version=1.9.2     # record something no SDK saw (write token)
ah track --file hours.csv --event time_logged --ts-col Date --dry-run   # import history
ah clicks /                                        # what people click (incl. dead clicks)
ah reports preview --file weekly.md                # validate a report + run its live widgets
ah reports create weekly-growth --file weekly.md   # publish it to the org (write token)
ah reports read weekly-growth                      # the resolved report, as a human sees it

How agents use it

The CLI is the contract: event names are deterministic and human-readable (click: Join the waitlist, form_submit: waitlist, pageview: /pricing), so an agent can compose questions in plain English → CLI flags → SQL without re-deriving the schema. The typical loop:

  1. ah digest to get the lay of the land
  2. ah paths --to <goal event> to discover the real funnel, ah funnels save to keep it
  3. ah funnel <name> --by device_type to see where it breaks down
  4. ah sessions show <id> to read individual stories behind the numbers

Operator mode (developing AgentHog itself)

With a repo checkout, DATABASE_URL connects the CLI straight to Postgres — no token — and unlocks the operator-only verbs (sweep, tokens, raw sql, --account):

bun packages/cli/src/index.ts projects list

DATABASE_URL beats the ah login config file, so a login never changes operator behavior; AH_TOKEN beats both.

Building & publishing to npm

The shipped package is a single HTTP-only bundle — no schema, no query engine, no drizzle. Everything runs from packages/cli/.

bun run build          # bundle src/index.ts → dist/index.js (HTTP-only, the shipped shape)
bun run typecheck      # tsc --noEmit

build externalizes @agenthog/db, @agenthog/queries, drizzle-orm, and postgres and defines __HTTP_ONLY__=true, so the operator engine is compiled out. build:operator is the local-dev counterpart (__HTTP_ONLY__=false, no externals) — it must never be published.

Publishing:

npm version patch      # bump 0.1.1 → 0.1.2 (or minor/major); commits + tags
npm publish            # runs prepublishOnly → build + assert-no-engine, then ships

prepack and prepublishOnly rebuild automatically, so a stale or operator dist/ can't be published by accident. assert-no-engine scans the actual dist/index.js and exits non-zero if it finds any schema, engine, or drizzle markers — run it standalone anytime with bun run assert-no-engine. publishConfig.access is public, so no --access flag is needed for the scoped @brightmotion/agenthog name.