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

@context-qb/cli

v2.5.0

Published

context.qb drift detector CLI — checks that context.qb.yaml matches the actual repo it describes. An Industrial Semiotics project.

Readme

@context-qb/cli

CLI tooling for the context.qb format. Currently provides one command — check-qb, the drift detector — with more on the way per the format ROADMAP.

What's here

packages/qb/cli/
├── package.json
├── tsconfig.json
├── README.md            # this file
├── CHANGELOG.md         # version history (Keep a Changelog format)
└── src/
    ├── types.ts         # DriftFinding, DetectorContext, AdrStatus, etc.
    ├── loader.ts        # loadContext, lineOf (reads paths.decisions: if set)
    ├── adapters.ts      # thin re-export of three dispatchers
    ├── detectors.ts     # detectTreeDrift, detectRoutesDrift, detectDecisionsDrift
    ├── cli.ts           # parseArgs, main, isEntryPoint guard
    ├── index.ts         # public surface re-exports
    └── adapters/
        ├── workspaces/
        │   ├── pnpm.ts      # pnpm-workspace.yaml reader
        │   ├── npm.ts       # package.json#workspaces (npm + yarn classic + yarn berry)
        │   └── index.ts     # dispatcher: pnpm wins, npm fallback
        ├── routes/
        │   ├── wrangler.ts  # Cloudflare Workers (wrangler.jsonc)
        │   ├── vercel.ts    # Vercel (vercel.json)
        │   ├── netlify.ts   # Netlify (netlify.toml)
        │   ├── fly.ts       # Fly.io (fly.toml)
        │   └── index.ts     # dispatcher: aggregates all four
        └── decisions/
            └── index.ts     # configurable path via paths.decisions:

The drift detector — check-qb

check-qb reads context.qb.yaml at the repo root and compares three of its sections against authoritative sources of truth:

| Section in the qb file | Source of truth | What drift looks like | | ---------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | tree: | pnpm (pnpm-workspace.yaml) or npm/yarn (package.json#workspaces) — pnpm wins when both exist | A new workspace exists without a tree: entry, or a tree: key has no matching directory | | routes: | Cloudflare (wrangler.jsonc), Vercel (vercel.json), Netlify (netlify.toml), Fly (fly.toml) — aggregated | A config declares a route the qb file doesn't list, or vice-versa (with §5.2.1 exemptions for externally-managed routes) | | decisions: | ADRs at docs/architecture/decisions/ or the path set in paths.decisions: | A new ADR exists without a decisions: entry, or the qb file's parenthesised status disagrees with the ADR's **Status:** line |

Adapter matrix

v2.0.0 ships adapters for the following sources of truth. If your setup isn't listed, the detector skips that section gracefully (no false positives).

| Section | Config / file | Package manager / platform | Notes | | ------------ | ------------------------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------ | | tree: | pnpm-workspace.yaml | pnpm | Glob patterns evaluated against **/package.json | | tree: | package.json#workspaces | npm / yarn classic / yarn berry | Falls back when no pnpm-workspace file; supports both array and object (packages:) forms | | routes: | apps/*/wrangler.jsonc | Cloudflare Workers | Reads routes[] array | | routes: | apps/*/vercel.json | Vercel | Reads routes[].src patterns | | routes: | apps/*/netlify.toml | Netlify | Reads [[redirects]] table array | | routes: | apps/*/fly.toml | Fly.io | Reads [[services.ports]] or [http_service] | | decisions: | docs/architecture/decisions/*.md (default) | — | Matches NNNN-*.md naming convention | | decisions: | Custom path via paths.decisions: in context.qb.yaml | — | Overrides the default; useful for repos with non-standard ADR locations |

Findings are emitted lint-style:

context.qb.yaml:32  error    tree-missing-entry         workspace "apps/billing" exists but is not declared in tree:
context.qb.yaml:71  error    decisions-status-drift     decisions["0010"] qb says "accepted" but ADR file says "superseded"
docs/architecture/decisions/0099-bad.md  warning  internal-adr-missing-status  0099-bad.md is missing a parseable `**Status:**` line; ADR omitted from decisions comparison

[check-qb] 3 findings: 2 errors, 1 warning, 0 info

On a clean repo: [check-qb] no drift detected. and exit 0.

Findings are sorted by qbLine ascending (undefined last), then code alphabetical. Same sort in both human and JSON modes — diffing the two outputs is straightforward.

Exit codes

| Code | Meaning | | ---- | ----------------------------------------------------------------- | | 0 | No drift, OR only info-severity findings (wildcard routes etc.) | | 1 | At least one error or warning finding | | 2 | Malformed or missing qb file (loader-level abort) |

--json mode

pnpm check:qb --json

Emits { findings: DriftFinding[], summary: { total, errors, warnings, info } } as a single line of compact JSON on stdout. Parseable by jq. Stable shape across v1.x. Useful for CI gates, IDE integrations, and pipelines.

Example:

pnpm check:qb --json | jq '.summary.errors'

Installation

# Install as a dev dependency
pnpm add -D @context-qb/cli
# or with npm
npm install --save-dev @context-qb/cli

The package provides a contextqb binary that runs the drift detector.

Playbooks

Two operator-facing playbooks walk through the detector end-to-end:

Usage

# Run the drift detector
pnpm contextqb                             # detect drift against ./context.qb.yaml
pnpm contextqb --file path/to/other.yaml   # detect drift in a different repo
pnpm contextqb --json                      # machine-readable output for CI / IDE / jq pipelines
pnpm contextqb --help                      # usage summary

Or add a script to your package.json:

{
  "scripts": {
    "check:qb": "contextqb"
  }
}

Note on --file: when you pass --file <path>, the file's parent directory becomes the implicit repo root for adapter reads (pnpm-workspace.yaml, apps/*/wrangler.jsonc, docs/architecture/decisions/*.md). This lets you point at a fully self-contained fixture or another repository without contaminating the comparison with the current repo's sources of truth.

Internal dogfooding

This repo (contextqb) consumes its own published @context-qb/cli from npm — the root package.json lists it as a devDependency and pnpm check:qb invokes the npm-installed binary, not the local source. This ensures the same code path is exercised in development as consumers will hit in production.

Library surface

If you want to drive the detector programmatically (e.g. from a test harness or a custom workflow), the public surface is the module's exports:

import {
  loadContext,
  lineOf,
  detectTreeDrift,
  detectRoutesDrift,
  detectDecisionsDrift,
  type DriftFinding,
  type DetectorContext,
} from "@context-qb/cli";

const ctx = await loadContext(repoRoot);
const findings = [...detectTreeDrift(ctx), ...detectRoutesDrift(ctx), ...detectDecisionsDrift(ctx)];

loadContext is import-safe — pulling it in does not trigger the CLI's main() (see the isEntryPoint guard in cli.ts).

Status

| Version | What | Status | | ------- | ------------------------------------------------------------------------------------------------ | ------ | | 1.0.0 | Initial drift detector (pnpm + Cloudflare + ADR default-path) | ✓ | | 1.0.1 | Published to npm; dogfooded in this repo | ✓ | | 2.0.0 | Multi-format adapter expansion (npm/yarn, Vercel/Netlify/Fly, paths.decisions:) | ✓ | | 2.0.x | Security hardening — npm metadata, INV-PUB-1 stripping of private path leaks | ✓ | | 2.1.0 | Telemetry completeness — event_kind, subcommand, adapter_coverage, schema v2 (ADR-0028 PR) | ✓ | | 2.2.0 | Telemetry integrity model — signed requests, HMAC-SHA256 (ADR-0028, INV-INT-1) | ✓ | | 2.3.0 | project_id support — per-project counting in cooperative aggregates (ADR-0032 / 0033) | ✓ | | 2.4.0 | Always-on upgrade notice + contextqb upgrade subcommand (ADR-0034, INV-CLI-UPD-1) | ✓ | | 2.4.1 | Documentation refresh (Status table, env-vars, first-run prompt clarity) | ✓ | | 2.5.0 | project-id --accept flag + pending-suggestion guard rails (cli-upgrade-feedback-followup FB.2) | ✓ |

See the full changelog for release notes.

Design notes

  • Adapters never emit findings. They surface per-file errors as console.warn to stderr. Promoting those to real DriftFindings lands in Task 9 alongside JSON output.
  • Detectors are pure (ctx) => DriftFinding[]. They never read the filesystem directly; the loader builds ctx.pathExists as a bounded existence-check helper.
  • DNS hostnames are case-insensitive (RFC 4343). The routes detector lowercases on both sides of the comparison so a capitalised qb hostname matches a lowercase wrangler entry.
  • The index: synthetic key in decisions: is filtered out before comparison so it never fires decisions-stale-entry for lack of a 0XXX-index.md ADR file.
  • No build step required during development. tsx runs the TypeScript sources directly. The typecheck script keeps the workspace covered by pnpm typecheck. A build step + dist/ output can be added later when we want to publish to npm.

All Subcommands

The CLI provides five subcommands. check is the default if no subcommand is specified.

Usage: contextqb [subcommand] [options]

Subcommands:
  check (default)     Drift detector for context.qb.yaml
  membership <cmd>    Manage your membership (register|revoke|status|project-id)
  mcp setup           Generate MCP client config snippets
  insights <topic>    Query community insights (stack|structure|mistakes|deploy)
  upgrade             Print the install command for upgrading to the latest CLI version

Options:
  --file <path>         Use the qb file at <path>
  --json                Emit machine-readable JSON output
  --no-telemetry        Skip telemetry for this run
  --telemetry-preview   Print telemetry payload without sending
  --telemetry-debug     Show errors when telemetry fails
  --help                Show this message and exit

contextqb check (default)

Drift detector — documented in detail above.

contextqb membership

Membership management for the data cooperative (see the privacy & telemetry page for details).

contextqb membership register      # Explicitly register (rare — auto-provision is the normal path)
contextqb membership revoke        # Revoke membership and delete all server-side data (sticky opt-out)
contextqb membership status        # Show current membership info
contextqb membership project-id    # Show the current project_id
contextqb membership project-id --accept      # Write the most recently suggested UUID
contextqb membership project-id --regenerate  # Generate and write a fresh UUID

Project ID workflow: When you first run contextqb check on a project without a project_id, the CLI suggests a UUID and caches it locally. You can either copy it manually or run --accept to write it automatically. If you run --regenerate while a suggestion is pending, the CLI warns you and requires --force-fresh to proceed. Both --accept and --regenerate use yaml.Document.set, which preserves all comments and key ordering in context.qb.yaml.

Sticky opt-out (INV-6): When you revoke, the local credentials file is rewritten to { opted_out: true }. Subsequent CLI runs will not re-provision a token. To re-enable, delete the credentials file and run any contextqb command.

contextqb mcp setup

Generate a ready-to-paste MCP client config snippet with your membership token interpolated.

contextqb mcp setup                 # Default: emits both cursor and claude blocks as JSON
contextqb mcp setup --client cursor # Cursor-specific snippet only
contextqb mcp setup --client claude # Claude Desktop snippet only
contextqb mcp setup --client json   # Both snippets in a single JSON object (same as default)

contextqb insights

Query community-wide insights derived from anonymized telemetry.

contextqb insights stack              # Defaults to --dim1 lang
contextqb insights stack --dim1 mono
contextqb insights structure          # Defaults to --dim1 tree_entries
contextqb insights mistakes           # Defaults to --dim1 validation_status
contextqb insights deploy
contextqb insights stack --json       # Machine-readable output

contextqb upgrade

Print the upgrade command for the version of the CLI that's currently installed. Instructional only — does not run any installer itself.

contextqb upgrade            # Prints the right install command for your install method
contextqb upgrade --json     # Machine-readable output

The subcommand detects how the CLI was installed (npx, pnpm dlx, npm-global, pnpm-global, homebrew, local dev dependency) and prints the corresponding command. If the CLI is older than the latest published version, the upgrade notice (printed automatically on every check / membership / mcp / insights run) tells you to run contextqb upgrade for the install command.

Topics and default dimensions:

| Topic | Dimensions | Default dim1 | | ----------- | ------------------------------------- | ------------------- | | stack | lang, mono | lang | | structure | tree_entries, routes, decisions | tree_entries | | mistakes | validation_status | validation_status | | deploy | platform | (none) |

Environment Variables

CI environments are auto-detected by default — the CLI skips auto-provisioning when it sees GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, and similar signals. See the privacy page for the full list of probed env vars.

| Variable | Description | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | CONTEXTQB_NO_PROVISION=true | Manual opt-out: skip auto-provisioning of membership. Useful on dev machines where you want no telemetry at all. | | CONTEXTQB_FORCE_PROVISION=true | Override CI auto-detect: force provisioning even when a CI environment is detected. Useful for long-lived self-hosted runners you want counted as cooperative members. | | CONTEXTQB_HOME=<path> | Override the credentials directory (default resolved via env-paths v4 — see paths below). | | CONTEXTQB_UPDATE_CHECK=npm | Telemetry-opt-out users only. Re-enables the upgrade notice by polling https://registry.npmjs.org/@context-qb/cli/latest at most once every 24 hours. The cache is local and is never transmitted. Without telemetry, the server-piggybacked cli_version_latest signal does not arrive, so this is the fallback path. Opt-in only — not the default. |

Credentials file location

The CLI uses env-paths v4 with project name contextqb. Defaults per OS:

| OS | Path | | ------- | --------------------------------------------------------- | | macOS | ~/Library/Preferences/contextqb-nodejs/credentials.json | | Linux | ~/.config/contextqb-nodejs/credentials.json | | Windows | %APPDATA%\contextqb-nodejs\Config\credentials.json |

The -nodejs suffix is added by env-paths to avoid clashing with native applications. When CONTEXTQB_HOME is set, the file inside that directory is still named credentials.json.

Token Rotation

v1 does not provide an in-place token rotation endpoint. To rotate a token:

  1. Run contextqb membership revoke (deletes server-side data, writes sticky opt-out locally)
  2. Delete the credentials file (path varies by OS — see the table above)
  3. Run any contextqb command — a fresh membership is auto-provisioned

See the apps/mcp/README on GitHub for server-side documentation.

About

ContextQB is a methodology and tooling project for building software with AI agents — principles, playbooks, audits, prompts, and the context.qb format that gives agents a stable, machine-validated map of your repo. Made by the technologists at Industrial Semiotics. Learn more at contextqb.com.

License

MIT.