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

@melten-ai/mltn

v26.9.5

Published

Melten CLI

Readme

@melten-ai/mltn

mltn is the command-line way to get a Melten access token for a Melten service, so you can call that service's API without copying tokens by hand. It follows the same split as the GitHub CLI: sign in once with auth login, then read a token with auth token. A machine that acts as a service identity uses workload token instead.

Sign in to a service

Sign in for the service you want to call, named by its audience:

npx @melten-ai/mltn auth login --audience https://mvp.melten.ai

This opens Melten OAuth in your browser once and stores a session for that service. By default the session carries every permission your account is granted for it. Add --scope to sign in with a smaller, least-privilege set:

npx @melten-ai/mltn auth login --audience https://mvp.melten.ai --scope "repo read:org"

--scope can only narrow, never widen: your permissions come from Melten's policy, so asking for a permission you do not have is refused. To change scopes later, sign in again.

Get a token

Once signed in, print a token for the service. This never opens a browser, so it is safe in scripts:

npx @melten-ai/mltn auth token --audience https://mvp.melten.ai

It prints only the token, refreshing it automatically when it has expired, so you can pass it straight to another command:

curl -H "Authorization: Bearer $(npx @melten-ai/mltn auth token \
  --audience https://mvp.melten.ai)" \
  https://mvp.melten.ai/api/...

If you are not signed in for that service, auth token fails and tells you to run auth login first.

Get a persistent credential

An access token stops working after an hour, which is a problem for a tool that runs longer than that and cannot open a browser to sign in again. For those, print a Melten Review credential instead. It does not expire; the server stops accepting it only once you revoke it, or after a year without use:

MELTEN_TOKEN="$(npx @melten-ai/mltn auth credential --audience https://mvp.melten.ai)"

It carries the permissions your session already holds for that service, and is printed once and never stored — mltn keeps no copy, so if you lose it, issue another one. Treat it as you would a password: keep it in an environment variable or a secret store, never in a file, a repository, or your shell history.

To revoke one, pipe it in on stdin — it is never read from the command line, so it does not reach your shell history. This prints nothing on success:

printf '%s' "$MELTEN_TOKEN" | npx @melten-ai/mltn auth credential --revoke \
  --audience https://mvp.melten.ai

auth logout does not revoke these credentials. It only removes the sessions mltn stores, and knows nothing about credentials you have already printed — revoke each one explicitly.

Get tokens for a machine

A machine that acts as a Melten service identity has no person to sign in. Examples are a Factory Machine that writes shared history or publishes to Store. An administrator issues such a machine a workload credential (mwc_...) instead, bound to one client, service and scope. mltn workload keeps that credential in an owner-only file and exchanges it for 15-minute access tokens.

Describe the machine's client in a private config file:

{
  "schema": "melten-auth/workload-client/v1",
  "token_url": "https://auth.melten-ai.workers.dev/token",
  "client_id": "factory-001-history",
  "resource": "https://melten-observability-prod-001.tail55ec96.ts.net:8446",
  "scope": "events:write",
  "expected_token_lifetime_seconds": 900,
  "credential_file": "/home/me/.config/melten/workload/history.credential"
}

These are the fields of Messageboard's private workload-auth document, so the same format serves both. Each consumer still needs its own credential. Messageboard's client serializes exchanges only within its own process, so never point it and mltn at the same credential file.

  • token_url is the issuer's /token endpoint, and resource is the service's exact audience.
  • scope is the credential's scope as Auth stores it: each name once, sorted, separated by single spaces, for example store:read store:write.
  • expected_token_lifetime_seconds is the longest lifetime mltn accepts, from 120 to 3600. Auth issues 900.
  • Paths are absolute.
  • The config and the credential file must each be a regular file you own, not a symlink or hard link, with no group or other permissions. Each must sit in a directory you own with no group or other permissions.
  • The credential's directory must also be writable by you, because the lock lives there.

Receive the credential at issuance. The administrator issues it with the issuance helper's --secret-result-fd, which writes it once to an anonymous pipe. Drain that pipe straight into mltn workload receive on the machine, so the secret is never displayed, copied or stored anywhere else.

First check the destination, before anything is issued. --check runs every check receive makes and reads nothing:

ssh <machine> '/usr/local/bin/mltn workload receive --check --config /home/me/.config/melten/workload/history.json'

Then issue into it. File descriptor 3 carries only the framed secret, through the pipe, and the helper's metadata goes to stderr. With pipefail, the command fails if either the helper or receive fails:

set -o pipefail
bun skills/melten-auth/scripts/melten-auth.ts identity-workload-credential-issue \
  --env prod --login <service-login> --client-id factory-001-history \
  --resource https://melten-observability-prod-001.tail55ec96.ts.net:8446 \
  --scope events:write --secret-result-fd 3 3>&1 1>&2 \
  | ssh <machine> '/usr/local/bin/mltn workload receive --config /home/me/.config/melten/workload/history.json'

receive accepts exactly one framed mwc_ credential on stdin. It stores it as the config's credential_file, creating a missing directory with mode 0700, and prints only the path.

  • Confirm the exchange. The pipeline's status covers delivery. To confirm that the stored credential also exchanges at Auth, bypass the token cache, which may still hold a token from a previous credential. Use a fresh state directory, and the token stays on the machine: ssh <machine> 'd=$(mktemp -d) && XDG_STATE_HOME="$d" /usr/local/bin/mltn workload token --config … >/dev/null; s=$?; rm -rf "$d"; exit $s' && echo exchanged.
  • Rotation. receive refuses to overwrite a stored credential unless --replace is given. Pair --replace-credential-id <current-id> on the helper with receive --replace, and run receive --check --replace first. --replace also drops any token cached from the old credential.
  • Expiry. A workload credential expires 365 days after issuance, or after 90 days without an exchange. List its metadata (expires_at, inactivity_expires_at) and rotate before then. Revoke it when the machine retires.
  • Failed delivery. If delivery fails after issuance, list the credential metadata and replace that credential again. Auth never reveals a lost secret.

Print a token:

mltn workload token --config /home/me/.config/melten/workload/history.json

It prints only the token. Every call checks the credential file, and a replaced credential or a changed config never reuses a cached token. The token's issue time must be within 5 minutes of this machine's clock, so keep the machine's time synchronized. The token is cached in a 0600 file under your XDG state directory (~/.local/state/mltn by default) and renewed about two minutes before it expires.

If proactive renewal hits a transport interruption, HTTP 429 or HTTP 5xx, the helper can still return that same cached token while more than five seconds of its original lifetime remain. It rechecks the credential, configuration and private cache after the failed exchange; successful exchanges also recheck the credential and configuration before returning. It never extends expiry, changes identity or opens a browser. Proactive renewal waits at most five seconds when a usable cache exists; a cold exchange retains its 30-second ceiling. Each invocation attempts renewal at most once. If another process holds the credential lock, a caller with a usable cache rechecks and returns it without waiting or starting another exchange. Without a usable cache, callers retain the existing bounded lock wait. After a transport interruption, the same private cache also delays proactive retries for 30 seconds while its token remains usable. This avoids an immediate retry colliding with an exchange that may still be running at Auth. It is best-effort pacing, not proof that the server stopped: separate state directories do not share this delay, and a failed cache write is reported. The next invocation after the delay tries renewal again; HTTP 429/5xx responses do not set this transport delay. A cold exchange is still allowed when the cached token is no longer usable. After expiry, or without a usable cache, an outage remains an error; these bounds do not extend the calling tool's own deadline.

Explicit refusals, redirects and invalid token responses fail and discard this state directory's cached token. Unrecognized transport failures, including TLS certificate errors, also fail and discard that cache. A failure to discard it is reported alongside the original refusal. Cache invalidation is not global revocation: other state directories may retain independently issued tokens until expiry. Resource servers still enforce their current grants and token validity; the helper never substitutes another identity for a refused request. Use one shared state directory per machine consumer to share its cache and avoid duplicate exchanges.

This renews access tokens, not the underlying workload credential. Keep an owner and rotation date for that credential, using the expiry metadata above. Replacement is supported; automatic credential rotation is not provided.

Auth refuses concurrent use of one workload credential. So every mltn process that uses the same credential file takes turns, whatever its HOME or XDG_STATE_HOME: the lock is <credential_file>.lock, beside the credential. One process exchanges while the others wait, and callers that share a state directory then reuse its token.

Wrap it for tools. Tools that take a token command expect an executable with no arguments, such as Factory's manifest machine_token_command and SWB's Store token selector. Give each one a one-line private script:

#!/bin/sh
exec /usr/local/bin/mltn workload token --config /home/me/.config/melten/workload/history.json

Install mltn on the machine at a pinned version (npm install -g @melten-ai/mltn@<version>), and use its absolute path. mltn runs on Node through #!/usr/bin/env node, so the calling service's PATH must include node.

What the file protects. An owner-only file keeps the credential from other users. It does not keep it from other processes that run as the same user, including agents with full access. Melten's same-user trust model accepts that. Keep one credential per machine, service and consumer (client_id), and rotate it through Auth's atomic replacement.

Commands

  • auth login --audience <url> [--scope "<scopes>"] — sign in to a service in the browser and store its session; --scope optionally limits the session to a subset of your permissions.
  • auth token --audience <url> — print an access token for a service you are signed in to, refreshing as needed. No browser.
  • auth credential --audience <url> — print a persistent Melten Review credential for a service you are signed in to. Printed once, never stored.
  • auth credential --revoke --audience <url> — revoke a credential read from stdin.
  • auth status — list the services you are signed in to, each session's scope, and its token expiry.
  • auth logout — sign out of every service and remove the stored credentials. Does not revoke credentials from auth credential.
  • workload receive --config <file> [--replace] [--check] — store a machine's workload credential piped from the issuance helper's --secret-result-fd. Never prints it. --check only runs the destination checks, before issuance.
  • workload token --config <file> — print an access token for a machine's service identity from its workload credential, renewing and caching it. No browser.

Development server

By default mltn talks to production. Add --dev to use the Melten development server; development and production sign-ins are kept separate and never overwrite each other.

npx @melten-ai/mltn --dev auth login --audience https://mvp-dev.melten.ai
npx @melten-ai/mltn --dev auth token --audience https://mvp-dev.melten.ai

MLTN_ISSUER can point mltn at another trusted HTTPS Melten deployment for local testing.

Where credentials are stored

mltn keeps one session per service under your XDG state directory (~/.local/state/mltn by default), with file permissions restricted to your user. It never prints your credentials. auth logout revokes and deletes them.

Machine mode keeps its credential at the config's credential_file, with its lock beside it. It caches access tokens in the same state directory as workload-*.json. auth logout touches none of these.

Development

The CLI is written in TypeScript. Common commands:

bun install
bun run check   # Biome, typecheck, and tests
bun run build   # compile src/ to dist/index.mjs

Source lives in src/; bun run build compiles it to dist/index.mjs, and bin/mltn.mjs is the thin Node entrypoint the package exposes as mltn.

Publishing

The package is public on npm and is released through GitHub Actions using npm Trusted Publishing (OIDC), so no long-lived npm token is stored in the repository. A manual publish-cli.yml run uses circlesac/oneup to compute the next CalVer version from the npm registry inside the workflow; it does not commit that version back. Register this repository and the publish-cli.yml workflow as the package's npm trusted publisher before the first publish.

Melten observability

Connect to Melten Tailscale and run:

npx --yes @melten-ai/mltn observability login

This selects the production writer audience and telemetry:write queries:write scopes. DK and SCC read/renew this production session through noninteractive auth token; they never prompt from a tool call. --dev selects a development writer session for operator tests; automatic DK/SCC clients always target production and do not consume that development session. Refresh/logout operations share a cross-process lock so concurrent tools cannot race rotating refresh credentials. auth token renews within two minutes of expiry and can retain an already-valid token during a temporary renewal outage.

Grafana uses the same Melten Google identity through its own browser session. Signing into Grafana alone does not create a local CLI credential. New DK releases automatically collect and upload private retrieval observations only on Melten's tailnet. Set DK_QUERY_COLLECTION=off to disable capture and uploads, and DK_TELEMETRY=0 / SCC_TELEMETRY=0 to disable operational traces.