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

@skhema/cli

v0.17.0

Published

Skhema CLI - Authentication and AI skills management for agent platforms

Readme

[!IMPORTANT] Generated mirror of a private source repo — do not open PRs here. This repository is an automatically generated, read-only mirror of a package built from Skhema's private monorepo. Pull requests are disabled and any change pushed here is overwritten on the next release. Questions and bug reports: [email protected]. Security: see SECURITY.md.

@skhema/cli

The Skhema command-line interface (skhema). Authenticate as a human or an agent, then drive the Skhema Public API from your terminal, CI, or an autonomous agent — projects, elements, components, strategies, exports, resources, and webhooks, plus one-command agent onboarding.

Install

npm i -g @skhema/cli
skhema --help

Requires Node ≥ 18.

Agent quickstart

Point an agent (OpenClaw / Hermes / any CI job) at Skhema in one line — install skills, register the MCP server, and verify an API connection:

SKHEMA_API_KEY=sk_live_… npx @skhema/cli init --yes --json

skhema init:

  • Verifies a credential — resolves --api-key / SKHEMA_API_KEY / a stored key / an OAuth session (same precedence as every command), exchanges + probes it, and reports the org and permission. An explicit --api-key is stored for future commands (never overwriting a different stored key without --force).
  • Installs skills into every detected agent platform (idempotent — reruns report unchanged).
  • Registers the MCP server (https://mcp.skhema.com/mcp, Streamable HTTP) in detected clients by safely merging a dedicated config file and writing a .bak backup — or printing copy-paste instructions when a client's config isn't cleanly writable. --yes registers non-interactively; without it, init reports what it would do and prompts only on a TTY. MCP auth is per-client browser OAuth on first use — the CLI only wires the URL, never a credential.

--yes never prompts and does everything resolvable, reporting what it skipped. Re-running is safe: every step reports already-done work as such.

Raw API passthrough

Reach any current or future gateway route without waiting for a dedicated verb — with the CLI's credential resolution, error mapping, and exit codes:

skhema api GET /projects                       # leading /v1 is optional
skhema api POST /projects/ws_1/elements --data @element.json
skhema api GET /projects --query limit=10 --query type=strategy
echo '{"name":"Q3"}' | skhema api POST /projects --data -
skhema api routes                                # every live route from the OpenAPI spec

--data takes a JSON literal, @file, or - (stdin). --query k=v repeats. The passthrough refuses any host other than the Skhema gateway.

Reading the public element repository

Beyond your own project, Skhema publishes a public repository of elements anyone can read and fork. Both element read commands can include it:

skhema element list --include-public
skhema element search "grassroots sport" --include-public --limit 10
skhema element list --collection sport-in-australia   # one curated public set

Public results come back as their own table, because the two lanes are different: only your organization's elements are yours to edit. Each row shows Author — who added the element to Skhema — and Source, who originated the content when it was mapped from an external document. skhema element get prints the full citation:

Source: Example Sports Commission — National Sport Strategy, 2024–2027
https://example.com/strategy

An element original to its author shows no Source line at all. A forked element whose content has since drifted reads Derived from: instead.

A bare skhema element get reads your organization's elements. To get an id you copied out of a Public results table, pass the same flag:

skhema element get el_... --include-public

--collection <slug> is public-only: organization elements are omitted and --include-public is implied. An unknown or empty slug returns an empty result rather than an error — the Public results table then reads (0), so a mistyped slug never looks like an empty project.

Strategy document imports

Import a local strategy document or public URL through the same reviewable proposal used by the web and MCP surfaces:

skhema import start --file ./strategy.pdf --wait
skhema import get imp_...                       # inspect the mapped proposal
skhema import decide imp_... --file decisions.json
skhema import apply imp_... --project-name "Imported strategy" --yes

Use --json for a stable machine envelope. Applying or discarding requires an interactive confirmation, or an explicit --yes in scripts and CI.

Agent login (no API key yet)

The quickstart above assumes you already have an SKHEMA_API_KEY. A brand-new agent — a personal assistant a user just pointed at Skhema for the first time — has no key. API keys can't bootstrap themselves (auth key create needs a logged-in session), so device login is the front door, and it's built to survive an agent harness that kills long-running commands.

The classic skhema auth login --headless blocks one process polling until the human approves — agents get interrupted and the login is lost. Instead, split it into two short commands that persist state between them:

# 1. Request a code and EXIT IMMEDIATELY (no blocking). Relay the URL to the human.
skhema auth login --headless --no-wait --json
# → { "ok": true, "command": "auth login", "data": {
#     "pending": true, "user_code": "WDJB-MJHT",
#     "verification_uri": "https://auth.skhema.com/device",
#     "verification_uri_complete": "https://auth.skhema.com/device?code=WDJB-MJHT",
#     "expires_at": "2026-07-23T12:15:00.000Z", "interval": 5 } }

# 2. After the human taps the URL and approves, poll once to finish. Repeat until done.
skhema auth login --complete --json
# pending → exit 6, error.code "authorization_pending"  → wait a few seconds, run it again
# success → exit 0, data { "authenticated": true, "user": {…}, "organization": {…} }

The poll loop an agent runs:

  1. skhema auth login --headless --no-wait --json → relay verification_uri_complete to the human.
  2. skhema auth login --complete --json on a timer. Poll no faster than the interval seconds from step 1 (default 5s): the CLI self-throttles across processes, so a --complete fired inside that window just returns authorization_pending again without contacting the server.
    • exit 6 (authorization_pending) → not approved yet; wait ≥ interval and retry.
    • exit 0 (authenticated: true) → done.
    • exit 1 (expired_token / access_denied / invalid_grant) → the code died; start over from step 1.
  3. Re-running step 1 while a code is still live returns the same code (idempotent — it never invalidates a code the human is mid-approving). Pass --force to discard it and mint a fresh one.
  4. For harnesses that tolerate a slightly longer command, --complete --wait <seconds> polls for up to N seconds (honouring the server interval) instead of a single round.

Once logged in, move to the durable API-key lane so later sessions skip the browser entirely:

skhema auth key create --name my-agent --use   # creates a key AND stores it as the credential

From then on the agent authenticates with the stored key (or SKHEMA_API_KEY) — no device flow, no browser.

Credential lanes

The CLI accepts two kinds of credential and resolves them in a fixed precedence order (highest first):

  1. --api-key <sk_live_…> global flag (this invocation only)
  2. SKHEMA_API_KEY environment variable
  3. A stored API key (skhema auth key use <key>)
  4. A stored OAuth session (skhema auth login)

API keys (lanes 1–3) are for CI and agents — no browser, no device flow. The OAuth session (lane 4) is for interactive human use. The organization is baked into an API key, so you never pass an org id when using one.

skhema auth status reports exactly which lane is active and for which org:

skhema auth status
# Credential:   SKHEMA_API_KEY environment variable
# Key:          sk_live_...a1b2
# Verified:     Yes
# Permission:   read-write
# Organization: org_…

Managing API keys

skhema auth login                       # interactive OAuth (needed to manage keys)
skhema auth key create --name ci --permission read   # prints the key ONCE
skhema auth key create --name ci --use  # …and store it as the CLI credential
skhema auth key list                    # masked, with usage + status
skhema auth key revoke <key-id>
skhema auth key use  <sk_live_…>        # store a key you already have
skhema auth key remove                  # forget the stored key

create / list / revoke call the same server-side api-key-manage function the web dashboard uses, authenticated with your OAuth session — issuance authorization (org owner/admin, plan limits, one-time key display, security emails) is enforced there, unchanged. Raw keys are printed only at creation and are otherwise always masked.

Headless / CI

export SKHEMA_API_KEY=sk_live_…
skhema --json project use <project-id>   # every command now just works

Command conventions

Every command supports the global flags --json, --quiet, --verbose, and --api-key <key>.

--json envelope

Under --json, commands emit one stable envelope on stdout:

// success
{ "ok": true,  "command": "project use", "data": { "defaultProjectId": "ws_1" } }
// failure
{ "ok": false, "command": "auth key create", "error": { "code": "forbidden", "message": "…", "requestId": "req_…" } }

Exit codes

Deterministic, so agents can branch on them:

| Code | Meaning | | ---- | ------------------------------------------------------------------------------- | | 0 | Success | | 1 | Generic / API error | | 2 | Usage error (bad or missing arguments) | | 3 | Auth required (no usable credential) | | 4 | Permission or plan denied (HTTP 403 / 402) | | 5 | Rate limited (HTTP 429) | | 6 | Device authorization still pending (auth login --complete — not approved yet) |

Default project

skhema project use <project-id>   # stored in ~/.skhema/config.json (0600)
skhema project use --clear

Later project-scoped commands read this default when --project is omitted.

Contributor commands

Approved contributors get a contribute command group for generating embeds and shareable links, and for inspecting their account, analytics, and payouts. Every command is gated on approved-contributor status and honours --json.

skhema contribute generate embed --element-type key_challenge \
  --content "..." --contributor-id contrib_…      # HTML <skhema-element> snippet
skhema contribute generate link  --element-type key_challenge \
  --content "..." --contributor-id contrib_…      # save + share links

skhema contribute status                          # approval status, ID, display name
skhema contribute profile                         # public profile (edit at contribute.skhema.com/account)
skhema contribute analytics --time-range 30d      # embeds, loads, clicks, CTR + top content
skhema contribute analytics --content-hash <hash> # per-content detail with top pages
skhema contribute payouts                         # payout history (20% commission, 60-day hold)

Source provenance

When the content is largely unedited from someone else's published document, add the source alongside your own author attribution. You stay the author (who added it to Skhema); the source records who originated it.

| Flag | Meaning | | ------------------------------ | ------------------------------------------------------------------------------------------ | | --provenance-org <name> | Source organization. Activates the group — the other flags are an error without it. | | --provenance-document <name> | Source document name | | --provenance-url <url> | Absolute http(s) URL of the source document | | --provenance-date <date> | YYYY, YYYY-MM, YYYY-MM-DD, or a range like 2024..2027 (both ends same granularity) |

skhema contribute generate link --element-type key_challenge \
  --content "Participation in community sport is declining" \
  --contributor-id contrib_… \
  --provenance-org "Australian Sports Commission" \
  --provenance-document "Sport Strategy" \
  --provenance-url https://www.example.org/strategy.pdf \
  --provenance-date 2024..2027

Note --source-url is a different thing: it records the page hosting the embed, for analytics attribution, not where the content came from.

Generated snippets carry the source as flat provenance-* attributes, so an embedded card shows the Source line alongside your byline. A <skhema-component> snippet has one outer tag and therefore one source, so it carries only what is true of every element: elements from two papers by the same organization still show Source: {organization}, with the differing document, URL and date dropped. Elements from different organizations share nothing, and the CLI says so rather than citing the component to one of them.

Provenance rides on the publish call, so --save-only (which never publishes) rejects the flags rather than dropping them. The server records provenance without ever failing a publish over it — when it declines to (a re-publish of identical content that already carries a different source, say), the CLI prints the reason as a warning rather than reporting a clean success.

In a --from-file batch, an element may carry its own provenance object ({ organization, documentName?, url?, documentDate? | dateRange? }), which overrides the batch-level flags for that element:

[
  { "elementType": "key_challenge", "content": "…" },
  {
    "elementType": "guiding_policy",
    "content": "…",
    "provenance": { "organization": "Sport Australia", "documentDate": "2019" }
  }
]

Generated embed snippets pin the CDN to a specific @skhema/embed version (https://unpkg.com/@skhema/embed@<version>/dist/embed.min.js), so a published snippet renders identically forever rather than tracking latest.

Configuration & storage

| What | Where | | ----------------------------- | -------------------------------------------------------------------- | | OAuth session | macOS Keychain (com.skhema.cli) → ~/.skhema/credentials.json | | Stored API key | macOS Keychain (com.skhema.cli/api-key) → ~/.skhema/api-key.json | | Preferences (default project) | ~/.skhema/config.json |

Environment overrides for non-production environments: SKHEMA_API_URL, SKHEMA_AUTH_URL. The underlying API client is @skhema/sdk — use it directly when you want Skhema in your own code rather than your terminal.

License

MIT