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

@candledottv/cli

v0.9.0

Published

The Candle CLI: authorize a device from your browser, then manage API keys, wallets, and setup health from the terminal

Readme

@candledottv/cli

The Candle CLI: authorize a device from your browser, then manage API keys, wallets, and setup health from the terminal. Zero runtime dependencies; the whole thing is one self-contained dist/index.js that runs under plain Node.

Quick start

Install the Candle CLI (macOS or Linux):

    curl -fsSL https://candle.tv/install.sh | bash

or with Homebrew:

    brew install candledottv/tap/candle

Then: candle setup

candle setup authorizes this device from your browser, shows the agent wallets as funding destinations, prints the skill and MCP install lines, and runs a full health check. candle auth login on its own does just the authorization step.

The npm package @candledottv/cli stays published for CI, programmatic use, and Windows until install.ps1 ships; npx -y @candledottv/cli@latest <command> runs it once without installing.

No-npm fallback

The same CLI can run straight from the public repo:

bunx github:candledottv/agentic candle auth login

That fetches the agentic repo, resolves the candle bin at its root (packages/cli/dist/index.js, a committed build), and runs it. If bun's git-dependency handling fails on your machine, clone and build directly:

git clone https://github.com/candledottv/agentic.git
cd agentic
bun install
bun run --cwd packages/cli build
node packages/cli/dist/index.js auth login

Commands

| Command | What it does | | --- | --- | | candle setup [--no-browser] | The onboarding wizard: authorizes this device (skipped when already authorized), prints the agent wallets as funding destinations plus the paste-into-your-agent brief, shows the skill/MCP install lines, runs the full doctor check (setup's exit code is doctor's), and links the web console. Safe to re-run. | | candle auth login [--profile <name>] [--scopes <a,b,c>] [--label <name>] [--no-browser] | Authorizes this device: prints a code, opens (or prints) an approval URL, polls until approved, then stores the resulting device token and API key. | | candle auth status | Shows which storage backend is in use, both credential prefixes, the config file path, and a live validity check for each credential. | | candle auth logout [--keep-key] | Revokes the stored API key (skipped with --keep-key), clears local credentials and config, and prints the portal URL for revoking the device itself. | | candle keys list | Lists this account's API keys: prefix, scopes, environment, timestamps, and which device minted each one. | | candle keys create [--scopes <a,b,c>] [--label <name>] [--expires-in <days>] [--tx-limit <usd> [--reset daily\|weekly\|monthly\|never]] | Creates a new API key and prints the plaintext exactly once, with the same optional name, expiration, and USD transaction limit the portal's create form takes. Stored locally only if the CLI does not already hold a working key. | | candle keys revoke <prefix> | Revokes an API key by prefix. Revoking the CLI's own stored key also clears it locally. | | candle wallets | Shows the account's embedded (launch) wallets and any linked wallets, using the API key, with a Signer column saying whether this machine holds each linked wallet's signing key. | | candle profile list | Lists profiles on this machine, with cached accounts. | | candle profile add <name> --api-url <url> | Creates a profile before authenticating it. | | candle profile use <name> | Makes a profile the active one. | | candle profile rename <old> <new> | Renames a profile. | | candle profile remove <name> --yes | Deletes a profile and its stored credentials. | | candle mcp [--tools <a,b,c>] [--read-only] [--print-config] | Runs the Candle MCP server (built into this binary) with this CLI's stored API key and API URL in its environment, so an MCP client config is just {"mcpServers": {"candle": {"command": "/Users/you/.local/bin/candle", "args": ["mcp"]}}} -- the absolute path, because GUI hosts launch servers with the app's environment and never see your PATH. Run --print-config to print that block filled in for this install. --read-only starts it with no key and only the four keyless read tools; --tools pins an explicit allowlist. The server is bundled into the binary, so the host needs nothing else installed. | | candle doctor | Runs a full health check (runtime, backend, credentials, API reachability, credential validity, wallet delegation) as a PASS/FAIL/SKIP table. Exits nonzero on any FAIL. | | candle verify <file> --bundle <path> [--identity <uri>] [--issuer <url>] | Verifies a release asset's Sigstore bundle against the trusted root compiled into this binary. No network, no credentials, and nothing else installed: the bundle carries the certificate and the transparency-log entry. --identity defaults to the release identity for the version in a latest.json sitting beside the bundle; --issuer defaults to GitHub Actions'. Prints verified: <identity> and exits 0, or the reason on stderr and exits 1. | | candle update [--check] [--to <tag>] | Replaces this binary with the latest signed release. The download is renamed over the running binary only after its SHA-256 matches both SHA256SUMS and latest.json AND its Sigstore bundle verifies in process against that exact version's release workflow. --check reports what is available and installs nothing; --to <tag> pins a release (an older one installs, with a warning). A Homebrew or npm install is left alone, with the command that owns it printed instead. |

Every command accepts these global options:

| Flag | Effect | | --- | --- | | --api-url <url> | Overrides the API base URL for this invocation, beating CANDLE_API_URL and the stored config value. | | --profile <name> | Act as a named profile; see Profiles below. | | --no-verify-account | Skips the check that the stored key belongs to the profile's account. | | --json | Machine-readable output instead of a formatted table or summary, generally the underlying API response. One exception: auth login's JSON output still omits the plaintext device token and API key, matching its human-readable summary, since login never displays either value in any mode. | | --help, -h | Prints usage. | | --version, -v | Prints the CLI version. |

Verify a release

Every release on https://github.com/candledottv/agentic/releases is built and signed by that repository's release.yaml workflow, and install.sh and candle update already check this for you. To check a download by hand, three commands, in increasing strength:

curl -fsSLO https://github.com/candledottv/agentic/releases/download/cli-v0.6.1/SHA256SUMS
curl -fsSLO https://github.com/candledottv/agentic/releases/download/cli-v0.6.1/candle-darwin-arm64
grep candle-darwin-arm64 SHA256SUMS | shasum -a 256 -c
gh attestation verify candle-darwin-arm64 --repo candledottv/agentic \
  --signer-workflow candledottv/agentic/.github/workflows/release.yaml
curl -fsSLO https://github.com/candledottv/agentic/releases/download/cli-v0.6.1/candle-darwin-arm64.sigstore.json
cosign verify-blob --new-bundle-format --bundle candle-darwin-arm64.sigstore.json \
  --certificate-identity-regexp '^https://github.com/candledottv/agentic/\.github/workflows/release\.yaml@refs/tags/cli-v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  candle-darwin-arm64

--new-bundle-format (cosign 2.2 or newer) says "expect a Sigstore bundle", which is what releases from 0.6.1 onward are signed as; without it cosign also accepts an older bundle format of its own, which candle verify cannot read.

No cosign or gh installed? candle verify <file> --bundle <path> (this CLI's own command, see the table above) runs the same check against the trusted root compiled into the binary, no network call required. Full walkthrough, including the installer script's own signature and the transparency log: Verify a Candle release.

The --json contract

For agents and scripts, --json guarantees: stdout carries exactly one JSON value -- the result on success, or a failure envelope -- and stderr carries diagnostics only. Exit codes: 0 success, 1 failure (the envelope says why), 2 usage error (the arguments themselves were wrong; nothing ran).

The failure envelope is stable:

{
  "ok": false,
  "code": "TIER_REQUIRED",
  "status": 403,
  "message": "Pro tier required",
  "suggestion": "Stake CNDL to reach Pro.",
  "docsUrl": "https://docs.candle.tv/developers/agent-access"
}

code is always present (the API's error code, an RFC 6749 error for the device flow, NETWORK_UNREACHABLE when the server was never reached, USAGE for argument errors, or a local precondition code like NO_DEVICE_TOKEN). suggestion is the fix as a command or setting when one is known; docsUrl appears when the API names a docs page for this error. Parse stdout, switch on code, run the suggestion.

Credential storage

Two credentials are stored: a device token (cndl_dvc_..., scoped to key management) and an API key (cndl_live_... or cndl_test_..., scoped to whatever your device authorized). Neither is ever written to the config file, logged, or printed, with one exception: keys create shows the plaintext API key exactly once, at the moment it's issued. auth login never prints either plaintext value, in any mode (including --json) -- both credentials go straight into storage, since the whole point of the CLI managing them is that you never have to see or copy them.

The CLI picks the best available backend for your machine, in this order:

  1. macOS Keychain, via the security CLI, when available.
  2. Linux Secret Service, via secret-tool, when the binary is present and a real store/lookup round trip succeeds (a headless box can have the binary installed with no Secret Service actually running; the CLI checks for that rather than trusting the binary's presence alone).
  3. An encrypted file (~/.config/candle/credentials.enc, AES-256-GCM, PBKDF2-derived key), everywhere else, Windows included. This is a first-class fallback, not an error: headless Linux agents are exactly where this matters most.

candle auth status and candle doctor both report which backend is active.

Profiles

One machine can hold credentials for several accounts and hosts. auth login creates a profile implicitly when none is already selected, named from --profile <name> or derived from the API host (staging, production, or the hostname, de-duplicated with a numeric suffix). Which profile a command acts as, highest wins: --profile, CANDLE_PROFILE, the activeProfile in config.json, the sole profile. With several profiles and none selected the CLI refuses and lists them; guessing is how a wallet import once landed on the wrong account.

Re-running auth login refreshes the profile you are already on, in place: the same name, the same refs, a new device token and key. Use --profile <new name> to add another instead. auth logout removes the acting profile's entry and its stored credentials, and clears activeProfile when it pointed there. candle profile list shows every profile with its cached account and how old that cache is (no network call); profile use <name> makes one active and refreshes its account from the API; profile add <name> --api-url <url> creates one before authenticating it; profile rename and profile remove <name> --yes do what they say. Removing a profile deletes its two stored credentials and nothing else; imported wallet signers belong to the wallet, not the profile. candle wallets marks, per linked wallet, whether this machine holds its signer (stored, none, or stale for a revoked wallet whose signer is still here).

Every authenticated command prints Profile: <name> Account: <account> at <api url> before its own output (--json output is unchanged except auth status, auth login and doctor, which carry profile and account; auth status and doctor also carry cachedAccount, the account the profile recorded, whenever a profile is resolved; scripts get identity from auth status --json). The account is cached at login from the API. Where the line is printed from that cache and CANDLE_API_KEY or CANDLE_DEVICE_TOKEN is overriding the stored credential, it reads Account: unknown (CANDLE_API_KEY override) rather than naming an account that credential was never checked against; auth status and setup look the account up live and print what they get, and auth status and doctor name the account the profile recorded beside it when the two differ (not under an env credential override, where the live answer is not the profile's key's). Before an authenticated command acts, the CLI asks the profile's stored key which account it belongs to and refuses if the answer differs from the account the profile recorded, naming both and the repairs in order of cost. A key that was legitimately re-issued is repaired with candle profile use <name>, which re-caches the account; candle auth login --profile <name> re-authenticates instead; --no-verify-account skips the check for one invocation without repairing anything. An unreachable API turns the check into a warning, never a failure. The check is skipped when CANDLE_API_KEY or CANDLE_DEVICE_TOKEN is overriding the stored credential, when a profile has no cached account or no stored key, and for the commands that only read the identity or repair it: auth login, auth status, auth logout, doctor, verify (which acts as no identity at all: two files and a signature) and the profile commands. setup is guarded, because it skips its login step whenever credentials are already stored.

A pre-profile install is migrated on first run: profile default is created from the existing settings and the two credentials are copied to profile:default:* refs. The old refs and fields are left in place so an older CLI keeps working, until an auth logout clears them along with the profile they were migrated into.

Environment variables

| Variable | Effect | | --- | --- | | CANDLE_DEVICE_TOKEN | Overrides the stored device token for this process. Every command that needs the device token checks this first, before the store. | | CANDLE_API_KEY | Overrides the stored API key for this process, same precedence as above. | | CANDLE_API_URL | Overrides the API base URL, beating the stored config value (but not an explicit --api-url flag). | | CANDLE_PROFILE | Selects the profile when --profile is not given. | | CANDLE_KEYRING_PASSPHRASE | The passphrase for the encrypted-file backend. Without it, a non-interactive process (no TTY) fails with a clear error rather than falling back to writing plaintext; an interactive session is prompted instead. | | CANDLE_CONFIG_DIR | Overrides where the CLI keeps its config and encrypted-file credentials (default ~/.config/candle). Mainly a testing seam. | | CANDLE_ALLOW_INSECURE_HTTP | Allows an http:// API URL pointing at a non-loopback host. The CLI attaches a device token or API key to nearly every request, so it refuses cleartext by default. Loopback (localhost, 127.0.0.0/8, ::1) is always allowed and needs no opt-in; set this only for a trusted local endpoint that is not loopback, such as a devcontainer reaching its host. |

CANDLE_DEVICE_TOKEN and CANDLE_API_KEY together mean CI needs no storage backend at all: set both and every command works without ever touching a keychain or the encrypted file.

What this CLI deliberately does not do

Launch, trade, and order commands. Executing trades and launches belongs to the SDK and MCP server, not this CLI. This CLI's whole job is credential management plus a handful of read-only or administrative operations; anything that moves an agent's actual workload stays with the packages built to run one.

keys limits. There is no command for setting per-key spend limits, because the API route that sets them (PUT /keys/:prefix/limits) structurally rejects a device token. It only accepts an agent key or a live session, since a spend limit is fund-movement authority, and this CLI's device token is scoped narrowly to key management. Manage limits from the portal.

devices list / devices revoke. The device-token endpoints (GET/DELETE /device/tokens) are session-only by design: this is the self-renewal guard that keeps a stolen device token from reading your device metadata (labels, timestamps, revocation state) or revoking a sibling device. A device token cannot list or revoke devices, including itself, which is why auth logout can revoke the API key it manages but has to send you to the portal to revoke the device token. Sibling device prefixes are not themselves secret: they appear in keys list's "minted by" column, which is attribution and grants no capability. Device management is the portal's job, not this CLI's.