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

railcode

v0.2.6

Published

Developer CLI for the multi-tenant Railcode platform: log in, scaffold, and deploy static apps.

Downloads

1,577

Readme

railcode CLI

Developer CLI for the multi-tenant Railcode platform: log in, scaffold, and deploy static apps from the terminal. It authenticates with a personal API token (long-lived, revocable) and uses the existing multipart deploy API.

Install

pnpm install
pnpm build            # → dist/index.js (the `railcode` bin)

Then run node dist/index.js <command>, or pnpm link --global to put railcode on your PATH.

Commands

railcode login [--api-url <url>]   Sign in and mint a personal API token
railcode login --setup-token <token>  Sign in with a one-time onboarding setup token
railcode init <app> [dir] [--template react|static] [--force]
                                   Scaffold an app. dir defaults to ./<app>;
                                   pass "." to scaffold into the current dir
railcode deploy [--private] [--no-source] [--force]
                                   Build (if configured) and deploy the app here
railcode pull [<deploy>] [--app <slug>] [--dir <path>] [--force]
                                   Download a deploy's source (default: the live one)
railcode db <list|query> ...       List data connectors / run read-only SQL
railcode connections <list|create|delete> ...   Manage org data connectors (admin)
railcode connector <list|docs|fetch|native|enable|create|delete> ...
                                   Call service connectors / manage them (admin)
railcode agent <list|show|create|update|delete|run|schedule> ...
                                   Manage org-scoped managed agents
railcode members <list|set-role|remove|add> ...  Members + system roles (admin)
railcode roles <list|create|update|delete|add-member|remove-member|grants|grant|revoke|materialize|effective|catalog> ...
                                   Org roles + the granular grants table (admin)
railcode apps <list|show|access|set-access|add-editor|remove-editor|add-viewer|remove-viewer|transfer|archive|unarchive|delete> ...
                                   Apps + access policy (owner/admin; editors for
                                   access/add-viewer/remove-viewer)
railcode app kv <collections|list|get|set|delete|drop> ...
                                   Manage an app's KV store (owner)
railcode app files <list|download|upload|delete> ...
                                   Manage an app's files (owner)
railcode llm <providers|models>    The org's callable models, as apps see them
railcode llm connect chatgpt       Bill LLM calls to a ChatGPT plan (admin)
                                   Signs in with a login of its own; --from-codex
                                   reuses ~/.codex/auth.json (shared token, see help)
railcode analytics <app> [--range 1d|7d|30d|90d]    Per-app pageview analytics
railcode logs <connector|service-connector|llm|email|agent> [filters]
                                   Org observability logs (admin)

The members, roles, apps, analytics, logs, connections, and the connector admin subcommands mirror the web console's admin surfaces — everything an owner/admin can do in the dashboard is available from the CLI. They all target your saved org and are gated server-side by the same capabilities as the console (a plain member gets 403; app list/show/access follow the per-app access policy).

  • login opens your browser against the server URL (default https://api.railcode.app) to authorize the CLI, then mints a personal API token, resolves your organization, and saves everything to ~/.railcode/config.json (dir 0700, file 0600). A short-lived localhost callback catches the code automatically: the authorize page probes it and only navigates there once the CLI answers. When it can't be reached — browser on another machine, or one that won't follow a link to 127.0.0.1the Railcode page shows the code instead (with a copy button); paste it into the waiting prompt. Pasting the .../railcode-cli/callback?state=...&code=... address works too, if a browser does end up on an unreachable page: the CLI reads the code out of it, checking the state matches this login run. --paste / --no-browser skips the callback entirely and goes straight to the code page — the right default for SSH/headless boxes.
  • login --setup-token <token> is the non-interactive onboarding path (no TTY or browser — used by the dashboard's copied setup prompt). A setup token (rc_setup_...) is a short-lived (~10 min), ONE-TIME bootstrap credential, not a personal API token: the CLI exchanges it once for a personal API token and writes the same config as a browser login. If it's expired or already used, generate a fresh prompt from the dashboard.
  • init <app> [dir] scaffolds a directory. dir is optional and defaults to ./<app>; pass . to scaffold into the current directory, or any path to scaffold into it. The target need not be empty (same-named files are overwritten), but an existing railcode.json is preserved unless you pass --force. By default it creates a React + Vite + Zustand starter — a personalized "Welcome to Railcode, <name>" home wired to every SDK capability: identity/team, a live to-dos list and file uploads (work with zero setup), and SQL, saved queries, service connectors, and LLM cards that call the real thing when configured and fall back to a labeled sample otherwise. Hovering a name or card title reveals the exact SDK call behind it; every write fires a toast with the call that just ran. Use --template static for a no-build index.html (loads /_api/sdk.js and demos await me() + db.collection().put/get) plus railcode.json with "dist": ".".
  • deploy reads railcode.json ({ app, build?, dist? }), runs the resolved build command when needed, then uploads the output dir by app slug. On the first successful deploy for a slug, the server creates the app as part of that deploy; a failed first deploy does not leave a visible not-deployed app behind. The live URL is printed after success. It also uploads the project source alongside the built files, and sends the deploy number this folder is based on — see Source, pull, and the version marker. --no-source skips the source tree; --force deploys over a base someone else has moved past; --private sets access to private for this deploy only.
  • pull [<deploy>] downloads the source stored with a deploy — the live one by default, or the number the dashboard's deploy history shows (#3 — numbers count from 1 per app). --app <slug> picks the app when there's no railcode.json here, --dir <path> writes somewhere other than the current folder, and --force overwrites local files that differ. Files the deploy doesn't contain are never deleted. This requires a server with deploy source history endpoints; older servers keep accepting deploys, but pull reports that source pull is not supported yet.
  • apps manages apps and their access policy. Grants come in three tiers: owner, editor, and member (viewer). An editor can deploy, read/revert deploy history, pull source, read analytics, read the access policy, and add/remove individual viewers — but not delete, archive, transfer, change the access mode or the editor list, or use app kv/app files (those stay owner/admin). Editors can open the app in every access mode and keep the grant across mode changes, so the editor list is not an audience list; railcode apps access groups grants by tier to keep that clear. Use the atomic add-editor/remove-editor (and add-viewer/remove-viewer, restricted mode only) to change one person without rewriting the whole policy; on set-access, omitting --editors leaves the editor list alone while --editors "" clears it. transfer demotes the previous owner to editor rather than cutting them off.
  • ci github wires the app up to deploy from GitHub Actions, in one command. It resolves the app from railcode.json and the repository from the origin remote, mints a deploy token, hands it to GitHub as the repository secret RAILCODE_API_TOKEN via the gh CLI (over stdin — the plaintext never reaches your screen, your shell history, or an argv), and writes .github/workflows/railcode-deploy.yml. Without gh, or with --no-secret, it prints the token once plus the exact gh secret set command. --repo owner/name and --branch <name> override what it detects; --force overwrites an existing workflow file. Nothing is added to railcode.json.
  • token manages those deploy tokens directly: create (plaintext shown once; --name <label>, --expires-in-days <n>), list, revoke <prefix>. The app comes from --app or railcode.json. A deploy token can deploy that one app and nothing else — it cannot read data, list apps, revert a deploy, or mint another token. It is EDIT-tier to create, every owner/editor/admin of the app can revoke any of them, and it stops working if whoever created it loses edit rights on the app. Long-lived by default: an expiring CI credential breaks a pipeline with no warning, so a lifetime is opt-in.
  • db inspects the org's data connectors (per-org Postgres) and runs ad-hoc read-only SQL. It works straight after railcode loginno app and no railcode.json required — since connectors are org-scoped; it hits the app-less /api/organizations/{org}/data/* plane with your login token. railcode db list (aliases ls, connections) prints each connector's name + engine (--json for the raw array). railcode db query "<sql>" (alias sql) runs SQL against --connection (default default) and prints a table + row count; --engine <postgres|bigquery|turso> is inferred from the connector list when omitted, --params '<json-array>' binds $1, $2, … placeholders (SQL is never interpolated), --file <path> reads SQL from a file, and --json prints the raw { columns, rows, rowcount, truncated } envelope.
  • agent manages org-scoped managed agents when your permissions allow it. Manifests are JSON or YAML files in the same shape the API stores under agent.manifest.
    • railcode agent list lists agents; --json prints raw AgentOut[].
    • railcode agent show <name|uuid> prints one agent; --manifest prints only its manifest JSON.
    • railcode agent pull <name|uuid> --output agent.json writes the existing manifest for editing.
    • railcode agent create --file agent.yaml creates an agent; update <agent> --file agent.yaml replaces an existing agent manifest; delete <agent> --yes archives it. --visibility <org|personal> on create/update/test sets or changes who the agent belongs to (default org on create; omitted on update leaves it alone). A personal agent is invokable and manageable by its creator alone — no grant makes it shared — and personal -> org is blocked once created. Requires agent:create (personal) or agent:create_org (org). agent show/list print visibility, and show prints Owner: for a personal agent.
    • railcode agent test --file agent.yaml --input '{"k":"v"}' runs a draft manifest without saving; railcode agent run <agent> --input '{"k":"v"}' invokes a saved agent and prints the result. Use --trace for the step trace and --json for the raw run detail.
    • railcode agent schedule set <agent> --cron "0 9 * * *" --timezone UTC creates or updates the agent's one schedule. schedule show, pause, resume, delete --yes, and run-now operate on that single schedule.
  • personal-connectors (aliases personal-connector, pc) manages your own connected third-party accounts (Gmail, Slack, …), brokered by railcode (in-house) — distinct from org-admin service connectors and from an agent's tools.personal_connectors. list shows toolkits this deployment brokers and your connection status; tools <toolkit> prints that toolkit's callable tools and input schemas; connect <toolkit> prints an OAuth URL to open in a browser; call <toolkit> <tool> [--args '<json>'] runs one tool on your own connected account. Hits the non-org-scoped /api/personal-connections/* plane — a personal connection belongs to the human, not the org.

Configuration

~/.railcode/config.json:

{ "apiUrl": "...", "email": "...", "apiToken": "rc_...", "tokenPrefix": "rc_...", "orgUuid": "...", "orgSlug": "..." }

API URL resolution: --api-url > RAILCODE_API_URL > saved config > prompt. Set RAILCODE_API_TOKEN to override the saved token in CI. On a 401, the saved token is cleared and you're prompted to railcode login again.

In CI there is no saved config at all, so the org uuid has to come from the environment too: set RAILCODE_API_TOKEN, RAILCODE_API_URL and RAILCODE_ORG_UUID. Only the first is a secret; the other two are identifiers. railcode ci github writes all three for you.

Staying up to date

The CLI keeps itself current. When you run a command in an interactive terminal it checks the npm registry — at most once every 6 hours — for a newer railcode release within your current major and, if there is one, installs it globally (with whichever package manager it detects: npm/pnpm/yarn/bun) and tells you:

railcode: a new version is available — 0.1.26 → 0.1.27. Updating…
railcode: updated to 0.1.27. It takes effect on your next command.

It never jumps across a major version (a breaking 2.0.0 is left for you to install deliberately), the check is best-effort (a registry/network hiccup is silently ignored — it never blocks your command), and it's skipped in non-interactive/CI runs so automation never self-mutates a global install. The last_checked_for_updates timestamp lives in ~/.railcode/update-check.json, and all of the above is printed to stderr so --json output stays clean.

Environment overrides:

  • RAILCODE_NO_UPDATE=1 — turn auto-update off entirely.
  • RAILCODE_UPDATE_DRY_RUN=1 — check and print the command it would run, without installing (also forces the check even off-TTY; handy for scripts and testing).
  • RAILCODE_REGISTRY_URL (falls back to npm_config_registry) — point the check at a different npm-compatible registry.

railcode.json

{
  "app": "dashboard",
  "build": "npm run build",
  "dist": "dist"
}

build and dist are optional. Set "dist": "." for no-build static apps.

Deploy output resolution:

  1. railcode.json dist wins.
  2. Otherwise railcode.json build runs and uploads dist/.
  3. Otherwise a package.json with a build script runs <pm> run build and uploads dist/, where <pm> is the project's package manager — detected from a packageManager field or lockfile (pnpm/yarn/bun), defaulting to npm when there's no lockfile.
  4. Otherwise a root index.html can be deployed interactively; for CI set "dist": ".".

Source, pull, and the version marker

A deploy uploads two things: the built files that get served, and the project source so it can be pulled back later. The source tree is the project folder minus anything its .gitignore excludes, minus a built-in exclude list, minus the resolved build-output directory. The built-in list (matched by exact name at any depth) covers vendored deps and build output (node_modules, .venv, venv, dist, build), VCS internals (.git, .hg, .svn), framework/tool caches (.vite, .next, .nuxt, .svelte-kit, .astro, .turbo, .parcel-cache, .cache, .output, .wrangler, .vercel, .netlify, __pycache__, .pytest_cache, .mypy_cache, .ruff_cache, .tox, .eggs, .ipynb_checkpoints, coverage, .nyc_output), agent/local tooling state (.gstack, .playwright-mcp), editor and OS debris (.vscode, .idea, .DS_Store, Thumbs.db, desktop.ini), env files (.env, .env.local, .env.development.local, .env.production.local.env.example still ships), package-manager debug logs, and the .railcode marker. If that tree is over the upload limit the deploy stops with a message naming the limit — add what doesn't belong to .gitignore, or pass --no-source.

On servers without deploy source history support, the extra deploy fields are ignored for compatibility: deploy still works, but no marker is written and railcode pull reports that the server does not support source pull yet.

railcode pull brings a deploy's source back down. With no argument it pulls whatever is live; railcode pull 412 pulls that deploy. It writes into the current folder (or --dir <path>), never deletes files the deploy doesn't contain, and stops rather than overwriting local files that differ unless you pass --force.

Both commands leave a version marker behind — .railcode, one small JSON file recording the instance, org, app and deploy number this folder now matches:

{ "api_url": "https://api.railcode.app", "org_uuid": "…", "app": "demo",
  "app_uuid": "…", "deploy": 412 }

The next deploy from that folder sends the number as its base version, and the server rejects the deploy (409) if the app has moved past it — so two people working from the same pull can't silently erase each other. The rejection says who moved it; resolve it with railcode pull && railcode deploy, or go over it on purpose with railcode deploy --force.

Because the marker is written after every successful deploy — including the first deploy of a brand-new app — plain edit-deploy iteration stays protected without pulling. It is scoped to one app: a copied project folder, or one re-pointed at another app or instance, sends no base version rather than the wrong one. Keep it out of git (railcode init gitignores it for you): it is sync state about your folder, so a colleague's git clone must not inherit it.