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

run402

v4.121.0

Published

CLI for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.

Readme

run402 CLI

Use the CLI by default for Run402 operations, shell scripts and CI. The typed, opinionated SDK is for programmatic composition; CLI and MCP are thin adapters over its shared workflows and the HTTP API.

Command-line interface for Run402 — provision Postgres databases, deploy static sites, run Node 22 serverless functions, host content-addressed CDN assets, send email, sign on-chain. Paid autonomously with x402 (USDC on Base) or MPP (pathUSD on Tempo, or sats over Bitcoin Lightning). Prototype tier is free on testnet.

The CLI lets an agent act as its own first-class Run402 principal rather than borrowing a human account. Identity records who invoked an action; organization roles, grants, grant keys, freshness, and spend policy determine what that principal may do. People remain first-class owners and members without having to run the CLI themselves.

For the full CLI reference (every flag, every subcommand) start at https://docs.run402.com/llms-cli.txt — the index holds the first-deploy contract and links one fetchable /llms-cli-<slice>.txt per topic (deploy, commands, repos, orgs, functions, assets, ops, errors, frontend, platform); https://docs.run402.com/llms-cli-full.txt is the whole reference as one document.

Deployment summaries share the SDK workflow view. CLI writes redacted detail under .run402/diagnostics/; MCP retains it through expand_result. Typed SDK callers keep the full result. Snapshot collection excludes platform runtime files automatically.

Install

npm install -g run402@latest

Or run without installing:

npx -y run402@latest <command>

30-second start

run402 up --name my-app -y                 # bootstrap wallet/tier/project/link, then deploy
run402 subdomains add my-app             # → https://my-app.run402.com

That's a real Postgres database + a deployed static site, paid for autonomously with testnet USDC.

Output contract

Every command prints JSON to stdout, JSON errors to stderr, and exits 0 on success / 1 on failure. Designed for shells, scripts, and agent loops — pipe everything to jq.

Stale CLI notices are advisory and never pollute success stdout. When a cached npm check says a newer run402 exists, normal commands may emit a structured cli.update_available JSON object on stderr, or an NDJSON event in --json-stream. Run run402 doctor --refresh for the explicit live check; it reports whether this invocation is local, global, npx/npm exec, pnpm/yarn/bun, or custom, and includes an upgrade_client action with both command and argv.

Common commands

One-command app deploy

run402 up --name my-app -y
run402 up --manifest run402.deploy.ts --check
run402 up --manifest run402.deploy.ts --plan
run402 up --manifest run402.deploy.ts --require-plan plan_...
run402 up --manifest run402.deploy.json --project prj_...
run402 up verify --project prj_...
run402 up --nested -y                         # app root inside another repo: its own nested repo + run402 remote

up is a thin CLI shim over the Node SDK action runner. It discovers run402.json, run402.deploy.json, then app.json. A run402.json carrying the app schema/app markers uses the app-install graph; a release-shaped run402.json is normalized through the same ReleaseSpec path as run402 deploy for compatibility. It validates the deploy input before any mutation, resolves the project as --project → .run402/project.json → manifest project_id → approved creation from --name → approved active-project fallback, then applies the manifest. --name is creation/link metadata only; it is not a manifest field and never renames an existing project. When everything is already configured, plain run402 up deploys. Non-interactive recursive prerequisites/local writes require -y/--yes.

For app manifests with verify.http[], up runs HTTP checks after deploy. Fresh Run402 edge sentinel misses (x-run402-edge or sentinel JSON bodies) become propagation_pending with diagnostics instead of hard failure while the host binding is still converging. Use --propagation-budget-s <seconds> to tune the default 120 second wait, --no-propagation-wait to return immediately, and run402 up verify to rerun the same checks without upload, deploy, project creation, or resource mutation.

For typed run402.deploy.ts configs, pass --manifest explicitly because TypeScript/JavaScript configs execute local code. Use --check for local-only import/normalize/file validation, --print-spec to inspect the normalized ReleaseSpec, --plan for a gateway-reviewed non-deploying plan, and --require-plan <plan_id> to apply only that reviewed intent. Warning flags are not used with --require-plan; the reviewed plan binds the exact warning/destructive set. Run402 Core skips Cloud wallet/tier prerequisites and fails closed when no Core project is selected.

Every mode (and run402 deploy) verifies the files the manifest references before any gateway call: migration sql_path/sql_file, function source/files, site { path } entries and dir() targets, assets.put sources. A missing one is MANIFEST_FILE_MISSING (details.missing[] = { field_path, path, kind }, one create_file next action per file). With no manifest in the working directory, UP_MANIFEST_REQUIRED looks one directory down (details.nearby_manifests[], a leading run_in_directory next action such as run402 up --check --dir <dir>); --manifest <path> to a missing file is a typed MANIFEST_NOT_FOUND with a create_manifest next action. An app root that lies inside another repository is never scaffolded into it: the skip carries a create_nested_repo next action, and --nested gives the app its own nested repository (git init -b main, the run402 remote, the first push) plus exactly one line in the enclosing repository's local .git/info/exclude, nothing else touched. up also sets this principal's display name when it has none: RUN402_AGENT_NAME (overrides an existing name), else the detected client (claude-code, codex, cursor, grok, or RUN402_CLIENT=<name> for one with no marker), and result.identity reports detected plus detection: { applied, reason } either way.

repos — host-blind encrypted git repos (zero deploy ceremony)

One noun, seventeen verbs: KyGit is the brand, a vault is the resource, a repo is what you have.

run402 init                                   # once per machine
git remote add origin run402::<org_id>/<project_id>
git push -u origin main                       # allocates the vault on first push, publishes

# or, one call: provision + allocate + scaffold, nothing deployed
run402 repos create my-notes
run402 repos create --nested --project prj_xyz # app inside another repo: its own nested repo + remote
run402 repos view --human
run402 repos list --org org_1a2b3c
run402 repos delete --project prj_xyz --force # refuses without --force while the vault holds generations

A hosted git remote, encrypted before it leaves the machine — no deploy, no manifest, no app. origin is claimed additively — an existing origin is never touched, the run402 remote falls back to run402 instead. A directory inside another repository is never scaffolded into that repository: the skip carries a create_nested_repo next action, --nested makes it its own nested repository (one line appended to the enclosing repository's local .git/info/exclude, nothing else touched), and create prints a git push next action only for a remote it actually added. From MCP, the vault is reached through a run snippet against r.repos; the verbs that mint or redeem a one-time secret (handoff/invite keys, resume/join) refuse there with SECRET_REQUIRES_CLI, naming the run402 repos command to hand the person. See run402 repos --help for the full tiered surface (common: create/view/list; occasional: capture/mirror/recover/handoff/resume/invite/join; lifecycle: rename/delete; maintenance: fsck/gc/access/policy), and the CLI reference's repos section for the terminal-loss statement and the progressive backup warning.

Handoff / resume. run402 repos handoff [--note-file <path>] captures the actual working tree (staged/unstaged/untracked, like git stash push -u) into the vault and mints a single-use bearer key (kgh1_…, printed to stdout exactly once); run402 repos resume <kgh1_…> claims it on another machine, clones fresh, and reapplies the exact dirty state with git stash apply --index. No shared keystore, no shared wallet — the key is the whole handoff. On a wallet with no active tier, resume first folds the same cold-start chain create does (wallet → faucet → one x402 prototype payment); --no-init opts out, and the claim itself never waits on it. Sensitive untracked files (.env, *.pem, SSH/AWS/GPG dirs, …) are excluded from capture by default (--include-sensitive <glob> re-admits one). See the reference run402.com/llms-cli.txt for the full note-schema and flag reference.

Invite / join. The second claim kind beside handoff/resume: a Handoff passes the work on and the sender stops; an Invite grows the team while the sender keeps working. run402 repos invite [--room <key>] [--note-file <path>] captures the checkpoint exactly like handoff — the inviter's own worktree, index, branch, refs, and access are all untouched — registers the inviter's presence in a coordination room (the project's default room, or --room <key> for a named org room), mints a single-use bearer key (kgi1_…, printed to stdout exactly once), and posts ONE room message naming the checkpoint (never the key). run402 repos join <kgi1_…> folds the SAME cold-start chain resume does before the claim, clones fresh, restores the exact dirty state, pins the invite's room locally, registers its own presence, posts ONE arrival message, and reports the inviter (name, labels, liveness), the room's other live presences, and the last few messages. run402 messages wait is the room's blocking read from there — the agent's ear, never an error on silence. Neither invite nor join has an MCP tool, same reasoning as handoff/resume.

Named addressing. run402 orgs slug <slug> (owner-only, small one-time fee) sets an org's globally-unique, address-form slug, after which run402::<slug>/<name> addresses any repo under it — git push to a name that doesn't exist yet push-to-creates it. run402 repos rename <name> [--project <project_id>] claims the per-org-unique <name> half explicitly (no fee); repos create claims one automatically, best-effort, when the org already has a slug. Also CLI/SDK-only — no MCP tool.

Wallet

run402 wallets new default # generate the local wallet without funding it
run402 wallets fund        # request testnet USDC from the faucet
run402 wallets balance     # mainnet + testnet USDC, plus the organization's allowance
run402 wallets current     # the active wallet's address (for funding), rail, and file path

Promo codes

run402 redeem R402-K8F3-Q2W9          # any time, before or after `run402 init`
run402 init --voucher R402-K8F3-Q2W9  # same redemption, folded into setup

A promo code adds to the organization's allowance, which settles tiers and priced calls with no on-chain payment. Case-insensitive, hyphens optional. Retrying is safe — a repeat returns the original result and never adds twice. A bad code never blocks init; it warns and records voucher_error in the JSON summary.

Public Buzz/Nostr identity attribution

Human accounts connect through https://console.run402.com/identity-links/connect: a normal browser, fresh passkey, and Buzz approval, with no terminal/event/passkey credential handling. The CLI commands below are the agent EOA ceremony. identity link list preserves every active/revoked record and its proof protocol; public identity links and organization memberships are independently revocable.

run402 identity link nostr begin --pubkey <npub-or-hex> --visibility public
# Publish the returned proof_content as a standalone Buzz kind-1 event.
run402 identity link nostr complete --event-file raw-event.json
run402 identity link list

This links two separately held public identities through fresh signatures; it never accepts a Nostr private key and never grants authentication, authorization, ownership, deployment, transfer, or payment authority. Buzz users should follow the self-contained run402-buzz getting started guide; these low-level commands remain the debugging boundary, not a competing onboarding flow.

Buzz community control plane

run402 buzz status reports skill installation, human-adoption offers/adoptions, community installation, and this agent's enrollment independently, and safely reports supported: false against an older gateway. The canonical ownership workflow is buzz adopt offer --org … --identity-link …: it capability-checks before mutation and returns a normal durable HTTPS handoff. Poll with buzz adopt offer show <buzzhao_id> and cancel with buzz adopt offer cancel <buzzhao_id>. The raw challenge command is explicitly advanced as buzz adopt direct …; direct completion/cancellation remain buzz adopt complete|cancel. Other goal workflows are buzz install and buzz enroll; decisions are buzz install activate|update|revoke and buzz approve|deny|revoke. buzz install discover --community <buzz:community:host> lists Run402-owned active descriptors without authentication. MCP intentionally has no signing/passkey mutation and only renders exact HTTPS/CLI handoffs. All commands print JSON to stdout, advice to stderr, have zero spend impact, and never accept Nostr/wallet secrets, session material, service keys, grant keys, or payment credentials. Failure JSON preserves the gateway's code-specific next_actions, exact repair field, and retry safety; never replace it with a generic edit-and-retry. See the Fizz/Honey examples.

Buy from an x402 URL

run402 pay https://seller.example/translate --method POST \
  --body '{"text":"hello"}' --max-usd 0.05 \
  --idempotency-key translation:1 --require-receipt

The default maximum is $0.10. --require-receipt requires a verified wallet-rooted offer before payment and a matching merchant receipt afterward. JSON output is the complete x402-commerce-result.v1 envelope, including settlement, movement/replay, delivery, signer relationship, policy, and portable non-secret evidence; an unpriced URL has payment: null. On trusted Run402 PAYMENT_INTENT_PENDING, wait for Retry-After and repeat the identical command with the same payer and --idempotency-key; never replace the key. Custom/arbitrary hosts and other funds_moved: "unknown" outcomes require reconciliation.

Database

run402 projects sql <project_id> "CREATE TABLE items (id serial PRIMARY KEY, …)"
run402 projects validate-expose <project_id> --file manifest.json # check auth manifest, no mutation
run402 projects apply-expose <project_id> --file manifest.json   # declare what's reachable
run402 projects rest <project_id> items "select=*&order=id.desc&limit=10"
run402 projects schema <project_id>                              # introspect tables + RLS

Static sites

run402 sites deploy-dir ./dist                # incremental upload (plan/commit transport)
run402 deploy --manifest app.json             # deploy only (`run402 up` does missing setup first, then this)
run402 deploy status op_... --project prj_...
run402 deploy verify op_... --project prj_... --wait
run402 deploy releases active                 # inspect current-live release inventory
run402 deploy releases diff --from empty --to active
run402 deploy resolve https://example.com/events --project prj_123 --method GET
run402 deploy resolve --url https://example.com/events?utm=x#hero --project prj_123 --method GET
run402 subdomains add my-app                # → my-app.run402.com (auto-reassigns on next deploy)

For pointer-swap recovery, verify the returned operation before declaring the public rollback complete:

run402 deploy promote RELEASE_ID --project PROJECT_ID
run402 deploy verify --operation OPERATION_ID --wait

Promote success means the origin pointer is active; mutable public URLs may still be converging. The result's edge.state reports convergence, and edge.verify_url is the direct operation-scoped HTTP verification endpoint.

deploy-dir hashes each file client-side and only uploads bytes the gateway doesn't already have. Re-deploying an unchanged tree returns immediately with bytes_uploaded: 0. Progress events stream to stderr. Release inspection commands print { release: ... } or { diff: ... } (raw payload, no envelope — see the "Output Contract" section in llms-cli.txt); use them after deploys to compare release inventory without starting another mutation. deploy verify prints the canonical edge-coherence report and exits 2 when the report is valid but not yet coherent. Inventories include release_generation, static_manifest_sha256, and nullable static_manifest_metadata; diffs include static_assets counters such as unchanged/changed/added/removed and CAS byte reuse. deploy resolve <url> (or --url / --host + --path) prints URL diagnostics with would_serve, diagnostic_status, match, warnings, edge_propagation, and next steps; host misses are successful diagnostic calls with would_serve: false. Stable-host resolve fields can include authorization_result, cas_object, response_variant, allow, route_pattern, target_type, target_name, target_file, and edge_propagation (settled, propagating, or sync_pending).

For database-bearing changes, rehearsal happens before commit without a flag: run402 deploy --manifest app.json --json (or run402 up) creates a contained branch, applies the candidate plan there, runs checks, and stops on a failed rehearsal; --no-rehearse skips it and run402 deploy rehearse <plan_id> rehearses a persisted plan by hand. The automatic rehearsal inside up / deploy reports rehearsal: { status: "skipped", reason } when there is nothing to protect: no_live_release on a first deploy, no_migrations, or migrations_unchanged when every migration is already applied with an identical checksum (a page-only redeploy that still carries its migrations ships in seconds). PUBLIC_ROUTED_FUNCTION is informational (requires_confirmation: false) and needs no --allow-warning; only warnings with requires_confirmation: true do. Manual restore points live under run402 snapshots create|list|get|restore|delete; temporary data branches live under run402 branches create|list|renew|delete.

GitHub Actions OIDC deploys

Link once from a local shell that has your Run402 wallet, then commit the generated workflow and manifest:

run402 ci link github --project prj_... --manifest run402.deploy.json
run402 ci link github --project prj_... --manifest run402.deploy.json --route-scope /admin --route-scope /api/*
run402 ci list --project prj_...
run402 ci revoke cib_...

link github infers owner/repo and the current branch, verifies the numeric GitHub repository id, creates a deploy-scoped CI binding, and writes .github/workflows/run402-deploy.yml unless you pass --workflow. The generated workflow is intentionally just the existing deploy command with OIDC enabled:

permissions:
  contents: read
  id-token: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to run402
        run: npx --yes [email protected] deploy --manifest 'run402.deploy.json' --project 'prj_...'

CI deploys can ship site, functions, database, and absent/current base changes. Route declarations are allowed only when the binding was linked with covering --route-scope patterns (/admin exact, /api/* final wildcard); no scopes means no CI route authority. Keep secrets, domains, subdomains, checks, non-current base changes, and out-of-scope routes in a local run402 deploy where the full wallet-backed authority is present.

Storage (paste-and-go CDN assets)

run402 assets put ./logo.png        # → AssetRef with cdn_url, sri, etag
run402 assets put ./asset --key assets/logo --content-type image/svg+xml
run402 assets get <key> --output /tmp/logo.png
run402 assets diagnose <url>        # exit 0 if fresh, 1 if stale

The returned cdn_url is content-addressed (pr-<public_id>.run402.com/_blob/<key>-<8hex>.<ext>) — paste it straight into HTML. SRI is bundled in sri. blob put infers MIME type from the destination key; use --content-type <mime> when the key has no useful extension or needs an explicit override.

Functions

run402 functions deploy <project_id> my-fn --file fn.ts \
  --timeout 30 --memory 256 \
  --schedule "*/15 * * * *" \
  --deps "stripe,zod@^3"
run402 functions logs <project_id> my-fn --tail 100 --request-id req_abc123 --follow
run402 functions logs --request-id req_abc123 --project <project_id>   # <name> optional with --request-id: every function is searched
run402 functions logs my-fn --project <project_id> --all               # include the Lambda INIT_START / REPORT lines
run402 logs --request-id req_abc123 --project <project_id>             # the x-run402-request-id response header, no function name needed
run402 functions invoke my-fn --project <project_id> --body-file request.json
run402 functions invoke paid-fn --project <project_id> --body-file request.json --idempotency-key paid:call:123 --wait
run402 functions rebuild <project_id> my-fn      # refresh ONE function onto the current runtime
run402 functions rebuild <project_id> --all      # refresh every function in the project

Log reads are app-first: every entry carries origin: "app" | "platform", the Lambda runtime lines (INIT_START, START/END/REPORT RequestId, billed duration) are hidden by default (--app), --platform shows only them and --all the raw stream; hidden counts what was dropped and a hint explains an empty result. --request-id accepts req_, fnrun_, and fnatt_ ids, --since takes an ISO timestamp or epoch ms, and run402 logs rejects unknown flags.

Inline --body <json> is validated before any request. Prefer --body-file <path> for agents and Windows cmd.exe; the file path avoids shell quoting entirely. Invalid or empty JSON fails locally instead of invoking the function with corrupted input.

functions rebuild is opt-in and never changes your source: it re-bundles the stored source against the platform's current runtime/entry-wrapper (deps pinned to the exact versions recorded at deploy), so a gateway-side wrapper fix (e.g. an SSR auth.* fix) reaches an already-deployed function — a plain redeploy with unchanged source does not. The source code_hash is unchanged and no new release is created. Functions deployed before dependency locking return CANNOT_REBUILD_UNLOCKED_DEPS; redeploy those from source instead. run402 doctor flags functions on a stale runtime.

Functions run on Node 22 with @run402/functions auto-bundled. Inside the handler:

import { db, adminDb, auth, email, ai } from "@run402/functions";

db(req) is the caller-context client (RLS applies); adminDb() bypasses RLS for platform-authored writes.

Same-origin web routes

run402 deploy accepts site.public_paths for clean static browser URLs and routes.replace for function ingress or exact method-aware static aliases. Release asset paths such as events.html are distinct from public paths such as /events: prefer { "site": { "replace": { "events.html": { "data": "<h1>Events</h1>" } }, "public_paths": { "mode": "explicit", "replace": { "/events": { "asset": "events.html" } } } } } for ordinary clean static URLs. In explicit mode /events.html is not public unless separately declared; mode: "implicit" restores filename-derived reachability and can widen access. site.embedding.frame_ancestors (catalog keys, e.g. ["localhost"], never raw origins) lets the named embedders put the site in an iframe: the gateway sends Content-Security-Policy: frame-ancestors http://localhost:* http://127.0.0.1:* and drops X-Frame-Options on every response of the host; omitted on a later apply carries the previous declaration forward, null returns to deny, unknown keys fail INVALID_SPEC naming the valid ones, and /_run402/config.json discloses the effective policy cross-origin so an embedder can check before framing. site.sign_in_path (e.g. "/join") names the app's own same-origin sign-in page: a signed-out user reaching MCP authorization (/_run402/oauth/authorize) is sent there with returnTo appended instead of the hosted /auth/sign-in; omitted carries forward, null returns to the hosted page, and a value with a query/fragment, //, ://, or a /_run402/ or /auth/ prefix fails INVALID_SPEC on site.sign_in_path. site.noindex: true adds X-Robots-Tag: noindex, nofollow, nosnippet to every response of the host; omitted carries forward, false or null makes the host indexable again, and anything but a boolean or null fails INVALID_SPEC on site.noindex. routes.replace is an array of route entries, not a path-keyed map. Use exact /admin plus final-wildcard /admin/* for a routed section root, narrow /api/* methods such as ["GET","POST","OPTIONS"], POST-only /login function routes, and exact static route targets like { "pattern": "/events", "methods": ["GET","HEAD"], "target": { "type": "static", "file": "events.html" } } only for route-table alias behavior. Static route file is a release asset path, not a public path, URL, CAS hash, rewrite, or redirect. Recipe — static home page + SPA shell: a root alias { "pattern": "/", "target": { "type": "static", "file": "home.html" } } (with home.html at the site root) serves real static bytes at GET / (route_static_alias) while unmatched app routes keep the index.html shell (spa_fallback); expect non-blocking STATIC_ALIAS_SHADOWS_STATIC_PATH (warn) / STATIC_ALIAS_DUPLICATE_CANONICAL_URL (info) plan lints and verify with run402 deploy resolve --url https://<your-site>/ --method GET. Routed functions use Node 22 Fetch Request -> Response; req.url is the full public URL on managed subdomains, deployment hosts, and verified custom domains. Direct /functions/v1/:name remains API-key protected. Known resolve literals include host_missing, manifest_missing, active_release_missing, unsupported_manifest_version, path_error, none, static_exact, static_index, spa_fallback, spa_fallback_missing, route_function, route_static_alias, and route_method_miss; known authorization_result values include authorized, not_public, not_applicable, manifest_missing, target_missing, active_release_missing, unsupported_manifest_version, path_error, missing_cas_object, unfinalized_or_deleting_cas_object, size_mismatch, and unauthorized_cas_object. Known fallback_state values include active_release_missing, unsupported_manifest_version, and negative_cache_hit; preserve unknown future strings. Release inventories may include static_public_paths with public_path, asset_path, reachability_authority, and direct; resolve may return the same reachability fields plus authorization_result, cas_object, response_variant, and route/static fields like allow, route_pattern, target_type, target_name, and target_file. Static route target warnings include STATIC_ALIAS_SHADOWS_STATIC_PATH, STATIC_ALIAS_RELATIVE_ASSET_RISK, STATIC_ALIAS_DUPLICATE_CANONICAL_URL, STATIC_ALIAS_EXTENSIONLESS_NON_HTML, and STATIC_ALIAS_TABLE_NEAR_LIMIT; inspect active routes, static_public_paths, and the backing asset_path. Runtime route failure codes to branch on: ROUTE_MANIFEST_LOAD_FAILED, ROUTED_INVOKE_WORKER_SECRET_MISSING, ROUTED_INVOKE_AUTH_FAILED, ROUTED_ROUTE_STALE, ROUTE_METHOD_NOT_ALLOWED, and ROUTED_RESPONSE_TOO_LARGE.

Secrets

run402 secrets set <project_id> OPENAI_API_KEY --file ./.secrets/openai-key
printf %s "$OPENAI_API_KEY" | run402 secrets set <project_id> OPENAI_API_KEY --stdin
run402 secrets list <project_id>
run402 deploy --manifest run402.deploy.json   # manifest uses secrets.require, not values

Secret values are write-only. list returns keys and timestamps only; deploy manifests should declare dependencies with secrets.require and never contain values.

Jobs

run402 jobs submit --file job.json --project prj_...
run402 jobs get job_abc123 --project prj_...
run402 jobs logs job_abc123 --project prj_... --tail 100
run402 jobs cancel job_abc123 --project prj_...
run402 jobs purge --project prj_...

Jobs are platform-managed runners, not arbitrary Docker execution. Submit the gateway-shaped JSON request (job_type, input.input_json, max_cost_usd_micros) and the CLI handles the required idempotency header through the SDK.

Email

run402 email create my-app
run402 email mailboxes
run402 email defaults --outbound my-app --auth-sender my-app
run402 email update my-app --footer-policy none
run402 email send --to [email protected] --subject "Welcome" --html "<h1>Hi</h1>"
run402 email send --to [email protected] --template notification --var project_name="My App"

For Run402 Core, use the same commands after run402 init --api-base=http://my-core:4020. Whoever runs the Core gateway must configure an outbound provider such as SES first; run402 email mailboxes surfaces provider_readiness, can_send, send_blocked_reason, and next_actions when setup is missing. Core's first email slice supports raw outbound mail with attachments; managed templates, inbound reply handling, sender-domain automation, and delivery operations may remain Cloud-only until the Core gateway adds those capabilities.

Image generation

run402 image generate "a serif logo" --aspect square --output logo.png

$0.03 per image via x402, MPP on Tempo, or Bitcoin Lightning.

On-chain (KMS signers)

run402 contracts provision-signer --chain base-mainnet
run402 contracts call <project_id> <signer_id> --to 0x… --abi @abi.json --fn transfer --args '["0x…","1000000"]'

Private keys never leave AWS KMS. $0.04/day rental + $0.000005/call.

Tier and billing

run402 tier set prototype                                    # free on testnet
run402 tier set hobby                                        # $5 / 30 days
run402 billing checkout <org_id> --product tier --tier hobby  # Stripe alternative

Doctor

run402 doctor                    # { ok, blocking[], warnings[], checks[] }
run402 doctor --refresh          # live npm check for a newer run402

ok is structural: true exactly when blocking[] is empty. Every check carries severity: "blocking" | "advisory" | "info"; advisory findings (an unbound contact passkey, a degraded recovery posture on another org, a stale CLI, vault gaps) land in warnings[] without changing ok or the exit code. The tier check's status is a fixed vocabulary (ok | inactive | frozen | past_due | dormant | purged | missing | unknown | error, never a tier name; see value.tier / value.lifecycle), and a wallet whose own org holds no tier but can reach another org's projects reports missing as advisory (TIER_MISSING_ON_OWN_ORG).

State

Local state lives at:

  • ~/.config/run402/projects.json (0600) — project credentials (anon_key, service_key, tier, lease_expires_at)
  • ~/.config/run402/wallet.json (0600) — wallet for x402 signing
  • ~/.config/run402/config.json (0600) — global default wallet pointer (active_wallet)
  • ~/.config/run402/profiles/<name>/ (0700) — named wallets, each with its own wallet.json + projects.json + non-secret meta.json

Override the base directory with RUN402_CONFIG_DIR or the wallet file with RUN402_WALLET_PATH. Override the API base with RUN402_API_BASE.

Named wallets (profiles)

Hold several wallets on one machine and select between them:

  • run402 wallets list | new <name> | use <name> | rename <old> <new> | bind [<name>] | unbind | import <name> --key <path|-> | rm <name> --yes
  • Select per-command with --wallet <name> (alias --profile), the RUN402_WALLET env var, or a per-directory .run402.json (commit-safe — holds only a name) resolved by walking up the tree. Precedence: flag > env > binding > wallets use default > default. A conflicting env + binding is a hard error.
  • The active wallet name shows in run402 status and run402 wallets current.

The CLI handles all x402 / MPP payment signing automatically — never ask the human for a private key or set up payment libraries by hand.

Sign-in session (a person)

A person signs in; the agent is your wallet (run402 status shows the wallet's own organization state). There is one sign-in session, graded by how it was minted.

  • run402 login — browser passkey sign-in over loopback PKCE (RFC 8252, like aws sso login): the CLI listens on 127.0.0.1, the browser runs the ceremony, and the session (grade loopback: full, step-up-able) is cached at the base config dir (shared across named wallets). Signing in again is the step-up.
  • run402 login --device — RFC 8628 device code for a terminal with no browser; approve it in the console. The session is grade device: read-only.
  • run402 whoami — principal, memberships, session.grade, and the write approvals cached on this machine.
  • run402 approve --action <capability> (--org <org_id> | --project <project_id>) — passkey-signed write approval for one action on one target; a person without a wallet needs it to provision, deploy, or write secrets (an interactive provision/deploy opens it for you).
  • run402 logout — revoke the session server-side and clear it and every write approval locally.
  • run402 orgs list — your orgs joined with the account overview (tier, lifecycle, quotas, allowance, advisories).

Not exposed as MCP tools by design — MCP authenticates as the agent (wallet), and a person's session must not become its ambient authority.

Active project (sticky default)

After provision, the new project becomes the active one. run402 projects use <project_id> switches it. Most commands that take <project_id> default to the active project when omitted.

Help

Every command supports --help / -h:

run402 --help
run402 projects --help
run402 sites --help
run402 assets --help
run402 functions --help

Full reference

The canonical, comprehensive CLI reference — every flag, every subcommand, edge cases, troubleshooting — lives at:

https://docs.run402.com/llms-cli.txt

Same content also at cli/llms-cli.txt (index), cli/llms-cli-<slice>.txt (topic slices) and cli/llms-cli-full.txt (everything) in the repo. Treat those files as authoritative; this README is a quick-orientation landing page.

Other interfaces

run402 is one of the public Run402 surfaces:

  • @run402/sdk — typed TypeScript client (isomorphic + Node entry)
  • run402-mcp — MCP server (Claude Desktop, Cursor, Cline, Claude Code)
  • @run402/functions — in-function helper imported inside deployed functions
  • @run402/astro — Astro SSR, ISR cache, hosted auth, and image integration
  • OpenClaw skill — script-based skill for OpenClaw agents

The in-repo packages run402, run402-mcp, and @run402/sdk release in lockstep. @run402/astro and @run402/functions publish on their own cadences.

License

MIT