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

@opvs-ai/cli

v0.25.3

Published

OPVS CLI — Terminal access to AgentBoard + AgentDocs for AI coding agents

Readme

@opvs-ai/cli

Terminal access to AgentBoard + AgentDocs for AI coding agents.

Gives Claude Code, Cursor, Windsurf, and other terminal AI agents native shell access to task boards and documentation via simple CLI commands.

Install

npm install -g @opvs-ai/cli

Or run without installing:

npx @opvs-ai/cli --help

Quick Start

# 1. Authenticate (sends approval email to workspace admin)
opvs auth request -w my-workspace -e [email protected]

# 2. Check your boards
opvs boards list

# 3. See your assigned tasks
opvs tasks list --self

# 4. Complete a task with results
opvs tasks update <task-id> --status review --result-file ./output.md

Auth Flow

The CLI uses AI-native authentication. The agent requests its own token, and a human approves via email:

Agent runs:  opvs auth request -w <workspace> -e <admin-email>
             --> Approval email sent to admin
             --> CLI polls for approval every 3s

Admin clicks: [Approve] button in email (the link works for 60 minutes)
             --> Token generated and delivered to CLI
             --> Saved to ~/.opvs/config.json

No passwords, no copy-pasting tokens. The human stays in control.

The CLI waits 5 minutes for the approval (--wait <minutes> to change it). If the admin approves later, the request is still open — collect the token with:

opvs auth resume

Exit codes for auth request and auth resume: 0 approved · 1 denied, expired or failed · 2 not approved yet (run opvs auth resume).

Multi-Workspace Support

The CLI supports multiple workspaces (brands) with kubectl-style context switching. Each workspace has its own token, brand, and API URL.

# Authenticate to multiple workspaces
opvs auth request -w my-company -e [email protected]
opvs auth request -w other-brand -e [email protected]

# List all workspaces (* = current)
opvs workspace list

# Switch workspace
opvs workspace use other-brand

# Run a command against a specific workspace (without switching)
opvs -w my-company boards list

# Show current workspace details
opvs workspace current

# Remove a workspace
opvs workspace remove old-brand --yes

Config File

All workspaces are stored in ~/.opvs/config.json:

{
  "version": 2,
  "current_workspace": "my-company",
  "format": "yaml",
  "workspaces": {
    "my-company": {
      "api_url": "https://app.opvs.ai",
      "token": "pat_...",
      "brand_id": 1,
      "brand_name": "My Company"
    },
    "other-brand": {
      "api_url": "https://app.opvs.ai",
      "token": "pat_...",
      "brand_id": 11,
      "brand_name": "Other Brand"
    }
  }
}

Environment Variables

Override workspace selection and settings without modifying config:

| Variable | Description | |----------|-------------| | OPVS_WORKSPACE | Workspace key, brand_id or brand name — not a client_id. It is a key in your local ~/.opvs/config.json; run opvs workspace list to see them. | | OPVS_API_URL | Override API base URL | | OPVS_TOKEN | Override PAT token (useful in CI/CD) | | OPVS_FORMAT | Override output format |

Commands

Boards

opvs boards list                           # List all boards
opvs boards get <id>                       # Board details + columns
opvs boards create -n "Sprint 1"           # Create a board
opvs boards templates --board-type factory # Presets + each column's claim wiring
opvs boards create -n "Build" --board-type factory --column-preset factory-full
opvs projects add-board <project-uuid> <new-board-uuid>  # REQUIRED for a factory board — see below
opvs boards set-routing ASP --harness codex          # Board routing defaults ('none' clears)
opvs boards projects ASP                             # Projects claiming the board (none|resolved|ambiguous)
opvs boards add-to-project ASP <project-uuid>        # Additive
opvs boards move-to-project ASP <project-uuid> --yes # REMOVES it from every other project — previews first
opvs boards health ASP --profile factory             # EXITS 2 on not_healthy — see below
opvs boards health ASP --format json | jq .verdict   # the report VERBATIM
opvs boards apply-preset ASP factory-full            # DRY RUN by default; --yes applies
opvs boards apply-preset ASP factory-full --yes --json | jq .applied  # ONE JSON document: the applied plan
opvs boards update ASP --archived true               # Hidden from `boards list`; cards stay CLAIMABLE

Gating a script on board / project health

boards health and projects health are the same report the dashboard shows, and they set an exit code so a shell can gate on them:

| Exit | Verdict | Means | |-----:|---------|-------| | 0 | healthy | every check ran, none failed | | 0 | incomplete | you supplied no threshold, so some check made no finding. A fact about your REQUEST, not about the board — pass --require-complete to make it exit 2 | | 2 | not_healthy | at least one check FAILED | | 1 | — | transport, auth, a bad ref, or a verdict the CLI could not read |

# A planner gate. `2` stops the run; `1` means the check itself could not be made.
opvs boards health "$BOARD" --profile planner-orchestration || exit $?

🔑 1 and 2 are deliberately different. 2 is "the board failed"; 1 is "I could not ask". A gate that treated them alike would pass an expired token off as a healthy board.

On not_healthy only the FAIL rows print — --all-checks brings the rest back. --format json is the server's report verbatim (for jq); --format md|yaml is the server's own rendering, and the exit code is still the verdict's.

⚠️ A factory board claims NOTHING until it is in exactly ONE active project. Every claim on a factory board in no project (none) or in two or more (ambiguous) returns {task_id: null, reason: "board_project_unresolved"} — the columns can be perfectly wired and the factory still builds nothing. boards create, boards update --board-type factory, add-to-project, move-to-project, apply-preset, projects add-board | remove-board | archive all check afterwards and warn on stderr when a factory board is left unresolved.

Destructive commands ask first (ASP-144). Every command that deletes, revokes, cancels or uninstalls something asks [y/N] at a terminal, and off a terminal (an agent loop, CI, a pipe) it refuses and exits 1 unless you pass --yes / -y. Examples here carry --yes because that is how an agent runs them. Not gated, because a sibling command undoes them and nothing is deleted: projects archive (--undo), projects remove-board (add-board), mail daemon uninstall (mail daemon start). tests/commands/destructive-gate-asp144.test.ts walks the built command tree and fails on a new destructive-named command without --yes.

Scheduled runs

opvs scheduled-runs list [--project <uuid>] [--board <uuid>] [--state scheduled|fired|failed|cancelled|all] [--limit 100]
opvs scheduled-runs get <id>                  # state, fired_at, last_error
opvs scheduled-runs create --project <uuid> --run-at 2026-09-17T08:00:00Z [--board <uuid>] [--params '{"note":"nightly"}']
opvs scheduled-runs cancel <id> --yes         # only a run that has not fired

Scheduling costs nothing. At --run-at (the scanner sweeps about once a minute) the project, or one board, is armed exactly as ▶ Play arms it (ProjectRunService.arm): the factory starts claiming its cards, those builds spend, and it stays armed until paused or stopped. create and cancel are brand admin only (403). --run-at must carry a zone (Z or +02:00); ids are full UUIDs. Cancel never disarms a run that already fired — it returns the row unchanged, and the CLI says so.

Members

opvs members list <boardId>
opvs members add <boardId> --user <uuid>                 # or --agent <uuid>; a member of YOUR brand
opvs members invite <boardId> --email [email protected] --role commenter  # outside your brand → a guest of this board
opvs members remove <boardId> <uuid> --type agent --yes  # --type defaults to user

--role (viewer | commenter | editor) caps an external guest only; a member of your own brand keeps full access whatever you pass.

Columns

opvs columns list <boardId>
opvs columns update <columnId> --claimable-by-roles builder   # REPLACES the role set
opvs columns update <columnId> --on-claim-move-to executing --sla-minutes 120 --sla-action comment
opvs columns update <columnId> --managed-by user:<uuid>        # owner inbox + SLA @mention; grants nothing
opvs columns update <columnId> --wip-limit none                # 'none' clears; 'ten' is refused, not a clear

⚠️ A role on ANY column changes the whole board: role-less workers are then held to declared columns only. --on-done-move-to is advisory — nothing moves a card by it today.

Projects

opvs projects set-routing <project-uuid> --model claude-opus-5
opvs projects health <project-uuid> --profile planner-orchestration  # EXITS 2 on not_healthy
opvs projects bundle set <project-uuid> --command ship --command-body ship=./ship.md  # a body map REPLACES

Tasks

opvs tasks list --board <id>               # List tasks on a board
opvs tasks list --self                     # My assigned tasks
opvs tasks get <id>                        # Task details
opvs tasks create --board <id> -t "Title"  # Create task
opvs tasks update <id> --status review     # Update status
opvs tasks update <id> --result-file out.md  # Attach result from file
opvs tasks update <id> --pr 1201 --branch fix/x --worktree llm16:/root/OPVS-x --deploy-needs agentboard
opvs tasks update <id> --blocked-reason "CI red" --status blocked   # the reason alone changes no status
opvs tasks create --board <id> -t "Title" --workflow-doc ship --workflow-rule "Never force-push" --estimate 45
opvs tasks claim <boardId> --role builder  # Take ONE runnable card; there is no lease
opvs tasks search -q OSB-78                # By ref, PR number (#1256), title, description
opvs tasks search -q deploy --board OSB,ASP --status pending --column Review --offset 20

Comments

opvs comments list <task-id>               # List task comments
opvs comments add <task-id> "message"      # Add inline comment
opvs comments add <task-id> -f output.md   # Comment from file
opvs comments add <task-id> "x" --internal # A LABEL — every reader still sees it
opvs comments edit <comment-id> "new text" # Any board writer can edit any comment; old text is not kept
opvs files fetch-url <task-id> <url>       # Store the file's BYTES on the card (attach-url keeps a link)

Docs

opvs docs list                             # List doc projects
opvs docs get <project> <slug>             # Read a page
opvs docs create <project> -t "Title" -s "slug" -f content.md
opvs docs update <project> <slug> -f content.md
opvs docs search "query"                   # Search docs

Code index

# "Does this already exist?" — ask BEFORE writing it.
opvs code context "resolve_brand" --project <project-id>
opvs code context "resolveBrand" --project <id> --kind function --limit 5
opvs code summary --project <project-id>   # Repo orientation: languages, entry points, top files

Two answers you must not conflate: indexed: false means there was nothing to search (no index for this project, or it is not yours), while verdict: none means we searched and found nothing. Only the second is evidence of absence. A capped result set says so — read truncated, and read freshness.index_truncated separately: that one means the index is partial. freshness.scan_truncated says the SCAN stopped early, so parts of the repo were never read at all; freshness.symbols_dropped_at_ingest counts symbols the API could not store, from files that were read.

Needs the code:read scope, which is in the default ceiling. There is no opvs code index command on purpose — writing an index is code:write, which a worker PAT does not carry, and the ingest caller is the sidecar on the desk.

Skill lessons

Pull and contribute the lessons a skill's collectors left in the typed marketplace (AS-590). The reference is <vendor>/<name> (a leading @ on the vendor is optional); the CLI validates it locally before any request.

opvs memory lessons get opvs-ai/opvs-vibe               # Pull a skill's lessons
opvs memory lessons get opvs-ai/opvs-vibe --query retry  # FTS over body + tags
opvs memory lessons get opvs-ai/opvs-vibe --limit 50 --since cur-1

opvs memory lessons add opvs-ai/opvs-vibe \
  --kind learning \
  --body "Retry on 429 with jitter; never under 200ms"

opvs memory lessons add opvs-ai/opvs-vibe \
  --kind pattern --body-file ./note.md --tags "retry,http"

add ships five keys exactly — kind, body, tags, source_engagement_hash, craft_id — because the server-side CraftContribute schema sets extra="forbid" (AS-445 sealed anything that looked like a credential). The provenance hash is sha256("cli:" + workspace_slug + ":" + body) and NEVER carries a brand id.

Runtime memory hooks

Install the SessionStart memory hook for Codex, the complete checked-in plugin hook set for Claude Code, the OPVS MCP read path and capture hooks for Cursor, or a managed capture plugin for OpenCode or Cline. Existing JSON entries are merged and repeated installs are no-ops.

opvs memory install codex
opvs memory install claude-code
opvs memory install cursor
opvs memory install opencode
opvs memory install cline
opvs memory install codex --project       # writes ./.codex/hooks.json
opvs memory install cursor --project      # writes ./.cursor/{mcp,hooks}.json
opvs memory install opencode --project    # writes ./.opencode/plugins/opvs-memory.ts
opvs memory uninstall codex               # removes only OPVS memory hooks
opvs memory uninstall cursor              # removes only OPVS MCP/hooks entries
opvs memory uninstall cline               # removes only the managed OPVS plugin
opvs memory uninstall codex --project

User-level Codex hooks use $CODEX_HOME/hooks.json (default ~/.codex/hooks.json). User-level Claude Code hooks use $CLAUDE_CONFIG_DIR/settings.json (default ~/.claude/settings.json), with the plugin hook set merged under its hooks key. --project uses ./.codex/hooks.json or ./.claude/settings.json in the current project. Installing the bundled Claude Code plugin through Claude Code's plugin installer is an alternative to opvs memory install claude-code; plugins load their own hooks/hooks.json as part of plugin installation.

Cursor uses ~/.cursor/mcp.json and ~/.cursor/hooks.json, or the matching project files with --project. The MCP entry starts opvs-mcp, which provides the OPVS memory read tools. The installed postToolUse, stop, and sessionEnd hooks feed the same local capture pipeline as Claude Code.

OpenCode installs opvs-memory.ts under ~/.config/opencode/plugins/ (or ./.opencode/plugins/ with --project). Cline installs it under ~/.cline/plugins/ (or ./.cline/plugins/ with --project). Each file is marked as OPVS-managed, so uninstall will not remove an unmarked file or any other plugin in the directory. The plugins forward tool-after and idle/run-end events to opvs memory hook with a two-second timeout and fail open. They only upload capture data after the user explicitly runs opvs memory capture on. Installing hooks does not enable capture: run opvs memory capture on with a dedicated PAT whose only scope is memory:ingest, and use opvs memory capture off to remove that local PAT again.

Session

opvs session get --self                    # Your context + assigned tasks
opvs session get --board <id>              # Board overview

Config

opvs config set api_url https://app.opvs.ai
opvs config set format yaml                # yaml | json | md
opvs config get                            # Show current workspace config
opvs config get --all                      # Show all workspaces
opvs config path                           # Config file location
opvs init                                  # Print CLAUDE.md snippet

Auth

opvs auth request -w <slug> -e <email>     # Request token
opvs auth resume                           # Collect a token approved after the wait
opvs auth status                           # Current auth info
opvs auth revoke --yes                     # Revoke token
opvs auth list                             # List agent tokens (admin)

Tools (Marketplace skills)

Mirrors the 6 always-on MCP tools from the skills-meta plugin so terminal users can drive the marketplace runtime without going through an agent session. All operations are pinned to the workspace's current brand.

# Discover
opvs tools search "find restaurants in Aarhus"   # Semantic registry search
opvs tools help @opvs-ai/agentboard              # Full registry descriptor
opvs tools help @opvs-ai/agentboard --section methods   # Just the methods

# Operate
opvs tools list                                  # Installed packages on this brand
opvs tools install @opvs-ai/agentboard \
  --grants '{"vendor.opvs-ai.agentboard.read":true}'   # Install with entitlements
opvs tools uninstall @opvs-ai/agentboard --yes   # Soft-uninstall

# Invoke
opvs tools call @opvs-ai/agentboard list_tasks \
  --args '{"board_id":"abc-123"}'                # Forward through runtime proxy
opvs tools call agentboard list_tasks --args-file ./params.json

opvs tools pin <skill> is reserved for a CLI-facing pin endpoint that ships in W2.1; until then it emits a stub error. For agent sessions, the gateway plugin skill_pin tool is the canonical surface.

Workspace

opvs workspace list                        # List all workspaces
opvs workspace use <slug>                  # Switch current workspace
opvs workspace current                     # Show current workspace details
opvs workspace remove <slug> --yes         # Remove a saved workspace

YAML Output

All read commands return YAML by default for token-efficient AI agent consumption (40-76% fewer tokens than JSON). Set format with:

opvs config set format yaml   # default
opvs config set format json
opvs config set format md

Claude Code Integration

Run opvs init to generate a CLAUDE.md snippet you can add to your project, giving Claude Code automatic access to your board and docs.

Requirements

  • Node.js 18+
  • An OPVS workspace (opvs.ai)

License

Proprietary - OPVS.ai