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

@azx-pbc/helix-cli

v0.3.0

Published

Deploy CLI for Helix, the AZX App Platform

Readme

helix — Helix deploy CLI

helix is a per-app CLI, like git or vercel: you run it from inside an app's directory. It reads that app's helix.json, zips the build output, uploads it to the portal as a new version, and manages the live pointer.

The mental model

my-app/
  helix.json        ← helix reads this from the current working directory
  dist/           ← the folder helix zips and uploads (configurable)

Everything keys off the current working directory. cd into your app, then run helix <command>. There is no "select an app" flag you normally need — the app is wherever you're standing.

Configuration

Each setting is resolved flags → environment → helix.json → built-in default (first match wins):

| Setting | Flag | Env | helix.json key | Default | | ---------- | -------------- | ------------------ | ---------------- | -------------------------- | | App slug | --slug | — | slug | (required) | | Portal URL | --portal-url | HELIX_PORTAL_URL | portalUrl | http://localhost:3001 | | Build dir | --dir | — | dir | dist | | Auth token | --token | HELIX_TOKEN | — | (helix login if unset) |

A helix.json looks like:

{ "slug": "my-app", "dir": "dist", "portalUrl": "https://portal.example.com" }

portalUrl is the one you cannot leave to the default. http://localhost:3001 is right only for a portal running on your own machine; against a deployed one, set portalUrl (or HELIX_PORTAL_URL, or --portal-url) or every command — starting with helix login — fails to connect to a portal that was never there. Your portal prints the exact file to copy under How to develop → On your machine. The file is the form worth checking in: login, create, deploy and promote all resolve it the same way, so it is set once.

The repo's examples/*/helix.json deliberately omit it — a checked-in portal URL would be wrong for every deployment but one — so to deploy an example, add portalUrl to its file or export HELIX_PORTAL_URL first.

--dir is resolved relative to the current working directory, and so is helix.json — another reason to run helix from the app directory.

Commands

helix login                                                   # browser sign-in (OIDC device flow)
helix logout                                                  # forget the cached tokens
helix whoami                                                  # who the portal thinks you are
helix create   [--display-name <name>] [--visibility <v>]   # register the app
helix deploy   [--dir <dir>] [--bundle <zip>] [--promote]    # upload a version
helix versions                                               # list versions
helix promote  <number>                                      # make a version live
helix rollback [number]                                      # revert the live pointer
helix skill    [--path <file>]                               # write this deployment's agent skill to disk

deploy uploads the bundle as a preview; --promote flips it live in the same step (architecture §5.1). visibility is internal | group:<id>[,<id>…] | password | public.

helix skill fetches this deployment's rendered agent skill (GET /api/v1/skill, ADR-0036) — the same document the portal's How to develop modal hands out, with this deployment's hosts, servable models, and approval baselines already substituted in. It needs no app slug or helix.json, only a portal URL and a token. Defaults to ./SKILL.md; --path .claude/skills/helix/SKILL.md drops it where a Claude Code agent reads it off disk.

Breaking in 0.2.0: the private visibility mode was renamed to internal. It never checked which user signed in, only that someone had. Passing the old value now errors rather than mapping to the new one, deliberately: the name is reserved for a future owner-only mode, so a silent alias would come to mean the opposite of what it says. Update scripts to use internal.

Authentication (M3)

Two paths, in precedence order:

  1. Static tokenHELIX_TOKEN / --token. Sends the value as a bearer token verbatim. This is the CI/scripts path, and also how the portal's dev-token stub keeps working (HELIX_TOKEN=$PORTAL_DEV_TOKEN). It is never accepted by a production portal.
  2. helix login — the OIDC device flow. The CLI asks the portal (GET /api/v1/auth/config) which issuer to use (the local dev IdP on :3002 in dev; Entra later), prints a verification URL + code, and polls while you approve in a browser. Tokens land in ~/.config/helix/tokens.json (mode 0600, keyed by issuer) and are silently renewed with the refresh token. On 401, nothing is auto-launched — agents run headless; the error says to run helix login.

Running it

Installed from npm

npm i -g @azx-pbc/helix-cli
cd my-app
export HELIX_TOKEN="…"
helix deploy --promote

Needs Node 22.12+ (or 24+). The engines range and the bundle's esbuild target move together (see scripts/build.mjs), so the declared floor is real: older runtimes may not merely warn, they may fail to parse it.

0.0.0 is a deprecated placeholder that exists only because npm requires a package to exist before a trusted publisher can be attached to it. Every real version is 0.1.0 or later and carries a provenance attestation. npm filters registry versions by engines against the running runtime, so before 0.3.0 declared 22.12+ an install on Node 22 fell all the way back to that placeholder — the reason a supported-looking Node could yield a non-functional package.

From this monorepo today

Build the real binary once and link it; from then on helix behaves exactly as it will when installed from npm:

pnpm --filter @azx-pbc/helix-cli build
npm link ./packages/cli          # puts `helix` on your PATH

cd examples/hello-world
export HELIX_TOKEN="$PORTAL_DEV_TOKEN"          # the portal's dev-token stub
helix create --display-name "Hello World"
helix deploy --promote
helix versions

Run it from your app directory so helix.json and a relative --dir resolve against the app, not the repo.

Without linking, node packages/cli/dist/helix.js <cmd> works the same way. To skip the build during CLI development, node --import tsx packages/cli/src/bin.ts <cmd> runs straight from source.

About pnpm --filter @azx-pbc/helix-cli helix -- <cmd>

This form runs the CLI's dev script through pnpm. It works for flags now (the CLI strips the -- that pnpm forwards — see src/args.ts), but pnpm runs the script in packages/cli, not your app. So it will not find your app's helix.json, and a relative --dir resolves against packages/cli. Use it only for --help or with explicit --slug + an absolute --dir:

pnpm --filter @azx-pbc/helix-cli helix -- deploy --slug my-app \
  --dir /abs/path/to/my-app/dist --promote

For real deploys, prefer running from the app directory (npm link, above).

Packaging

This is the only package in the repo that emits JS. Everything else runs from TypeScript source via tsx and is private: true; a published CLI can't.

pnpm build runs scripts/build.mjs, which esbuild-bundles src/bin.ts into a single dist/helix.js with a #!/usr/bin/env node banner. Two things make that the right shape rather than a tsc --outDir:

  • @azx-pbc/shared gets inlined. It's a private workspace:* package whose exports point straight at ./src/index.ts, and the edge/portal/egress all consume it as raw TS deliberately. Publishing must not force a build+dist+d.ts onto shared for one consumer, and must not ship a manifest depending on @azx-pbc/[email protected] — a version no registry has. Bundling solves both, so shared is a devDependency here, not a dependency.
  • No tsx at runtime. The bin used to point at src/bin.ts behind a #!/usr/bin/env -S tsx shebang while tsx was only a devDependency, so a real global install would have been broken on arrival.

archiver, openid-client, and zod stay external and install from the registry — bundling archiver's transitive tree buys nothing.

CI's package job builds, runs pnpm pack, asserts the tarball ships dist/ and no src/, then globally installs the tarball in a clean prefix with tsx off PATH and runs helix --help. That last step is what actually proves publishability; the unit tests never touch the bundle. It runs on every PR, so a broken artifact fails before a release is ever cut.

Releasing

Releases are cut by tag and published by .github/workflows/release-cli.yml:

cd packages/cli
npm version patch                       # or minor — edits package.json only
cd ../.. && git commit -am "release(cli): v0.1.1"
git tag cli-v0.1.1 && git push && git push --tags

The workflow re-runs the whole build → pack → assert → global-install sequence against the tag, refuses to publish if the tag and package.json disagree, and then publishes with provenance.

Three things to know before touching it:

  • The tag prefix is cli-v, not v. v* is the platform's version and already drives the container-image builds in ci.yml. The CLI versions independently.
  • There is no NPM_TOKEN. Auth is npm trusted publishing (OIDC): npmjs.com has a registered trust relationship with AZX-PBC-OSS/helix + release-cli.yml. Renaming or moving that workflow file breaks publishing until the registration is updated — that narrowness is the point.
  • It packs with pnpm and publishes with npm. Only pnpm rewrites catalog: and workspace:* into real ranges; npm is the client whose OIDC support is documented and reliable. Each does the half it's good at.

See ADR-0032 for why public npm rather than GitHub Packages.