@hs-x/cli
v0.4.6
Published
HS-X CLI — init, validate, connect, dev, deploy, promote, rollback, doctor, sync. Installs the `hs-x` command.
Readme
@hs-x/cli
The command-line tool for HS-X, a type-safe HubSpot app framework that deploys
to Cloudflare Workers. Installing this package puts both hs-x and its shorter
hsx alias on your PATH: they run the same CLI for scaffolding projects, running
the local dev loop, and deploying to your own HubSpot developer app and your own
Cloudflare account.
Install
npm i -g @hs-x/cli
hs-x --versionNode 20+ and Bun can both run it. The npm package is @hs-x/cli; the installed
commands are hs-x and hsx, with hs-x used as the canonical spelling in the
docs. If you prefer not to install anything globally, every command also works
through bunx @hs-x/cli <command>.
Thirty seconds
hs-x init deal-tagger # scaffold a project (default template: workflow action)
cd deal-tagger
bun install
hs-x connect # bind a HubSpot developer account and a Cloudflare account
hs-x dev # local dev loop
hs-x deploy # deploy to your HubSpot app and your Cloudflare accountThe CLI works direct-to-HubSpot out of the box. You provide the HubSpot and Cloudflare credentials, the CLI talks to both platforms directly, and nothing requires an HS-X platform account.
Use it with an existing HubSpot project
An existing HubSpot project does not need to migrate to HS-X. Run the same CLI
from a directory containing hsproject.json and no hsx.config.ts:
cd my-existing-hubspot-app
hs-x doctor
hs-x check
hs-x dev
hs-x deploy --plan
hs-x deploy
hs-x logs
hs-x statusIn an interactive terminal, hs-x dev presents the runnable HubSpot app
components and starts only the selected entries. Scripts can select exact
components without a prompt using repeatable --component <uid> flags.
The account selected by the HubSpot CLI is used for both the project and testing
session by default; use --project-account or --testing-account only when an
intentional override is needed.
Frontend console.log/warn/error calls and HubSpot logger.* calls are
mirrored into the hs-x dev terminal without changing the app source. The
original browser and HubSpot logger behavior is preserved, and HMR rebuilds are
instrumented automatically. Console output from locally executed HubSpot app
functions joins the same stream as tagged backend events. Use repeatable
--only frontend, --only backend, --only hubspot, --only errors, or text
selectors to focus the stream. Interactive search is case-insensitive and
matches both raw JSON and the compact key=value tree shown in the terminal.
Press f to cycle lane views, e for errors, / to search, and d to inspect
the latest matching event with its complete raw message and structured
arguments. Identical consecutive events collapse to a repeat count in an
interactive terminal; piped output remains append-only.
If another HubSpot dev server owns the reserved UI-extension port, interactive
mode shows its PID, command, and working directory and offers to stop it and
retry. Scripted and JSON runs never terminate another process automatically.
Agents and CI can own the same loop without keeping a terminal attached:
hs-x dev start --component my_card --json
hs-x dev logs --session <id> --follow --json-stream
hs-x dev logs --session <id> --lane frontend --level error --search "record id" --json
hs-x dev status --session <id> --json
hs-x dev restart --session <id> --yes --json
hs-x dev stop --session <id> --yes --jsondev start (also dev --detach) returns a stable managed-session id. Log
readers use independent byte cursors, so several agents can follow or query the
same frontend, backend, request, and HubSpot stream without consuming each
other's events. Save next_cursor and pass it back as --cursor to resume.
Search is case-insensitive; --lane and --level are repeatable, and --since
accepts an ISO timestamp or a duration such as 5m. SIGINT detaches a log
reader without stopping the server. Stop/restart verify the exact saved process
identity before signaling it; machine and non-TTY mutations require --yes,
while --force only permits escalation after graceful shutdown times out.
This is HubSpot-direct mode. It reads the official HubSpot CLI account
configuration, runs HubSpot's project parser and local dev session, and talks
directly to HubSpot for uploads, deploys, app identity, and logs. It does not
require or contact the HS-X control plane, does not use Cloudflare, does not
create HS-X project bindings, and does not send HS-X telemetry. The original
project remains usable with hs project ... commands.
Account selection follows the HubSpot CLI: the nearest .hsaccount override
wins, then the account selected by hs account use; --account <name-or-id> is
an explicit override for one command. Familiar hs project ... placement works
for the enhanced development loop and read-only project inspection:
hs-x project dev # same enhanced experience as hs-x dev
hs-x project info # concise project/component health
hs-x project info --details # every deployed component
hs-x project list-builds --limit 5 # recent HubSpot builds
hs-x project logs --latest # latest app execution event
hs-x project logs --function fetchData # one serverless function
hs-x project validate # account-scoped component schemas
hs-x project info --json # stable machine-readable envelopeFull component data is always preserved in JSON. Human project info output
summarizes healthy components by type and automatically expands anything that
needs attention. project validate uses the selected account to check
HubSpot's current component schemas rather than deferring schema failures until
upload.
Deploy uses the same account rules. For example:
hs-x deploy --plan # validate and preview; writes nothing
hs-x deploy # upload, wait for the build, then deploy
hs-x deploy -a 4809868 # one-run account override
hs-x deploy --hubspot-upload-only # upload/build; request skipAutoDeployInteractive deploys print the native-project plan and ask for consent before
uploading. JSON and non-interactive mutations require --yes; planning never
does. --hubspot-upload-only (also --skip-deploy) strictly uploads and builds,
requests HubSpot's skipAutoDeploy, and does not run an explicit deploy.
Familiar HubSpot-style aliases are accepted: -a for --account, -m for
--message, and -f for --force; --pak supplies a one-run developer PAK.
Use either --json for one result or --json-stream for newline-delimited
events, never both.
For a native project, these commands are strictly HubSpot-only: deploy never
contacts Cloudflare or the HS-X control plane, never creates an .hs-x project
binding, and never sends HS-X telemetry. Infrastructure flags such as
--cloudflare-deploy, --record-local, --promote-when-healthy,
--apply-schema, and --portal-schema-live fail with a mode-specific error.
The --account-id and --project-id vocabulary shown below belongs to HS-X
projects; native HubSpot projects use --account.
When both hsx.config.ts and hsproject.json are present, the project is an
HS-X project and the full runtime/deploy behavior remains available. Migration
and hs-x link are explicit upgrades, never prerequisites for the direct mode.
There are exactly three onboarding modes (ADR-025); pick by answering two questions — do you want credentials stored locally, and do you want the platform?
- Env-only unlinked — credentials supplied via environment variables; nothing stored, no HS-X account. The CI/scripting and try-it-fast mode.
- Stored-direct — credentials captured by
hs-x connectand kept in the local store; still no HS-X account. The individual-dev steady state for people not using the platform. - Linked platform — an HS-X account with the control plane, dashboard,
teams, hosted billing, and linked deploys. Reached from mode 1 or 2 with
hs-x login(authenticate an HS-X account) andhs-x link(attach an already-deployed project to it).
Modes 1 and 2 need no HS-X account: the platform is opt-in, never a prerequisite for building, deploying, or running an app.
Deployed Workers run in your Cloudflare account, and the generated
.hs-x/alchemy.run.ts (checked into your repo) describes the Cloudflare
resources your app owns — the app keeps running even if you stop using HS-X.
Commands
Grouped the way hs-x help prints them.
Start:
| Command | What it does |
| --- | --- |
| hs-x init [name] | Create a new HS-X project |
| hs-x connect | Link this project to HubSpot and Cloudflare |
| hs-x doctor | Diagnose local setup |
| hs-x check | Validate project source |
Develop:
| Command | What it does |
| --- | --- |
| hs-x dev | Start the local dev server |
| hs-x project | HubSpot-compatible dev and project inspection commands |
| hs-x api <path> | Call HubSpot or the HS-X control plane |
| hs-x flags | Manage feature flags |
| hs-x migrate | Migrate legacy HubSpot apps |
| hs-x react doctor | Audit generic React and HubSpot UIX health |
| hs-x react review | Build contextual evidence for an agent review |
Deploy:
| Command | What it does |
| --- | --- |
| hs-x deploy | Deploy the project |
| hs-x promote | Promote a deploy to an environment |
| hs-x rollback | Roll back an environment |
| hs-x routes | Show active deploy routes |
Observe:
| Command | What it does |
| --- | --- |
| hs-x status | Show project health |
| hs-x logs | Stream runtime and deploy telemetry |
| hs-x drift | Show project drift |
| hs-x audit list | List redacted account audit rows |
| hs-x history | Show recent command runs |
Account:
| Command | What it does |
| --- | --- |
| hs-x login | Authenticate with an HS-X account token |
| hs-x accounts | Manage HS-X accounts |
| hs-x whoami | Show the active HS-X account |
| hs-x logout | Remove the active HS-X account |
| hs-x link | Attach this project to your HS-X account |
| hs-x unlink | Clear the session; keep local project state |
Config:
| Command | What it does |
| --- | --- |
| hs-x secrets | Store app secrets for runtime deploys |
| hs-x completion <shell> | Generate shell completion (bash, zsh, fish) |
| hs-x update | Check for a newer CLI release |
| hs-x help | Show command help |
Run hs-x <command> --help for command-specific flags. Most commands accept
--json for machine-readable output, and prompts can be skipped in scripts
with --yes where a command confirms before changing anything.
React Doctor is read-only and also works in standalone HubSpot projects without an HS-X account or migration. See the React Doctor beta-v1 guide for installation, CI, deep/archive behavior, agent review, and the beta feedback contract.
hs-x deploy without provider flags keeps the combined HubSpot + Cloudflare
workflow. Provider flags are fail-safe and explicit: --cloudflare-deploy
deploys only to Cloudflare, --hubspot-upload uploads only to HubSpot, and
passing both selects a combined deploy. Preview the exact target set with
hs-x deploy --plan --json; the result includes deploymentMode and targets.
Connecting accounts
hs-x connect walks HubSpot and Cloudflare setup back to back; each side is
also available on its own.
hs-x connect hubspot # HubSpot developer account: PAK, or discovered from `hs accounts auth`
hs-x connect cloudflare # Cloudflare: browser OAuth flow, or --auth-method api-tokenFor HubSpot, the CLI discovers credentials from the official HubSpot CLI config
when you have run hs accounts auth, or accepts a developer personal access key
via --pak. For Cloudflare, an interactive run uses a browser
authorization-code flow by default; --auth-method api-token accepts a scoped
API token you create in the Cloudflare dashboard and paste back, which also
suits CI and headless shells.
Migrating an existing app
hs-x migrate run takes a legacy HubSpot app (platform versions 2023.2, 2025.1,
or 2025.2) and generates a 2026.03 HS-X project as a net-new duplicate you can
test with hs-x dev. Your original app keeps running untouched until you cut
over. See hs-x migrate --help for the inspect, report, cards, and swap-cards
subcommands.
Docs
Guides and reference live at hs-x.dev/docs. The getting-started guide goes from an empty directory to a live HubSpot card in about fifteen minutes.
License
Apache-2.0
