The hs-x CLI.
One binary covers the whole lifecycle: scaffold a project, run it locally against a real portal, deploy to HubSpot and your own Cloudflare account, migrate a legacy app, and read what production is doing. Every command works unlinked, straight against HubSpot and Cloudflare; logging into an HS-X account adds the platform surfaces (promote, rollback, logs, drift, audit) on top. This page lists every shipped command with the flags that actually matter.
The 30-second tour
Installing @hs-x/cli provides both hs-x and its shorter hsx alias. They are
identical; this reference uses hs-x as the canonical spelling.
Four commands carry a first session end to end:
hs-x init my-app --yes # scaffold a project
hs-x connect # link HubSpot + Cloudflare credentials
hs-x dev # run it locally against a real portal
hs-x deploy --yes # ship itEverything else is listed below, grouped the way you reach for it. Every command accepts --json for machine-readable output, and hs-x help <command> prints the same curated help as <command> --help.
| Command | What it does |
|---|---|
hs-x init | Scaffold a new HS-X project (alias: create) |
hs-x connect | Connect HubSpot and Cloudflare credentials |
hs-x login | Authenticate an HS-X account with a dashboard token |
hs-x accounts | List and switch HS-X accounts (also whoami, logout) |
hs-x link / unlink | Attach unlinked deploy state to an account / clear the session |
hs-x check | Validate project source (alias: validate) |
hs-x dev | Local dev server, plus dev invoke for one-shot capability runs |
hs-x api | Raw calls to the HS-X control plane or HubSpot developer API |
hs-x flags | List, create, enable, disable, archive feature flags |
hs-x deploy | Build artifacts and deploy to HubSpot and Cloudflare |
hs-x promote | Promote a recorded deploy (alias: deploy promote) |
hs-x rollback | Roll an environment back to an earlier deploy |
hs-x routes | Show active deploy routes |
hs-x secrets | Store runtime secrets, today hubspot-oauth set |
hs-x migrate | Migrate a legacy HubSpot app: run, pull, cutover, inspect, report, cards, swap-cards |
hs-x list | List your HS-X projects and their ids |
hs-x status | Project health and discovered capabilities |
hs-x logs | One timeline: deployed Worker invocations plus HubSpot's app logs |
hs-x checkpoint | Aggregate runtime telemetry from the control plane |
hs-x drift | Project drift state from the control plane |
hs-x audit list | Redacted account audit rows |
hs-x doctor | Diagnose local setup |
hs-x history | Recent local command runs |
hs-x update | Update the CLI to the latest npm release (alias: upgrade) |
hs-x completion | Shell completion for bash, zsh, fish |
Flags that work everywhere
A few flags are global rather than per command. --json switches any command to a machine-readable result envelope on stdout. --cwd <dir> runs a command as if invoked from another directory. --quiet suppresses progress output, --verbose and --debug add detail to errors, and --no-telemetry skips the anonymous usage event for that run.
Help is curated by hand, and it hides escape hatches by default. hs-x <command> --help shows the flags you normally need; --help-all reveals the advanced section (control-plane overrides, local mocks, attribution flags). hs-x --version prints the version; hs-x help <command> [subcommand] works as a spelled-out alternative to --help.
hs-x deploy --help-all # include the advanced flags the short help hidesCommands that read from the HS-X control plane (logs, drift, audit, and friends) talk to the platform endpoint, api.hs-x.dev, by default; the --control-plane-url flag and HSX_CONTROL_PLANE_URL environment variable exist so an internal build can point at a dev control plane, and end users never set them. Identity flags work the way you'd expect: most commands accept --account-id and --project-id (--project is an accepted spelling), with HSX_ACCOUNT_ID and HSX_PROJECT_ID as fallbacks. The project-scoped reads (status, logs, drift, routes) fall back one step further, to the .hs-x/project.json binding that link and deploy maintain — inside a deployed project directory the flag can be omitted entirely.
Project and account setup
hs-x init [name]
Scaffolds a new HS-X project; create is the same command. --type picks the app shape (workflow-action, sync-source, or empty), --template picks a starter (deals-tagger, empty, sync-source), --distribution chooses private (default) or marketplace, and --ui-extension adds a starter app card (--no-ui-extension to skip). --yes accepts every default and installs dependencies without prompting; --no-install and --force do what they say.
hs-x init deal-tagger --type workflow-action --yeshs-x connect
Connects this project to HubSpot and Cloudflare. Run bare in a terminal for the interactive flow, or target one provider with the hubspot and cloudflare subcommands.
For HubSpot, the key flags are --developer-account-id and --pak (the developer personal access key used for project upload and deploy; interactive runs can discover it from HubSpot CLI config after hs accounts auth). --developer-api-key is separate and only serves endpoints that document hapikey auth.
For Cloudflare, the connection is OAuth-only: a browser PKCE flow against Cloudflare's consent screen, with the code exchanged server-side by the control plane — no API token to create or paste. Without a TTY the CLI prints the authorize URL instead of opening a browser. The Cloudflare account id is discovered when --cloudflare-account-id is omitted.
hs-x connect cloudflarehs-x login
Authenticates an HS-X account with an API token you generate in the dashboard. Interactive runs open the token page and prompt for a paste; scripted runs pass --token or set HSX_API_TOKEN. The token binds to one account (pick with --account when the token grants several) and that account becomes the active default.
hs-x login --token "$HSX_API_TOKEN"hs-x accounts
Manages the local account store: list, current, switch <id>, and logout <id> (account, ls, set, and remove are accepted spellings). hs-x whoami is shorthand for accounts current; bare hs-x logout removes the active account.
hs-x accounts switch acct_456hs-x link and hs-x unlink
link attaches a project's unlinked (local_*) deploy state to your HS-X account; it needs a logged-in session and a deployed project. --account-id overrides the active account and --yes skips the confirmation. unlink clears the local session token (with a best-effort server-side revoke) while leaving project state in your Cloudflare account untouched.
hs-x link --yesValidate, run, poke
hs-x check
Validates project source and reports diagnostics; validate is the same command. Exits non-zero on findings, which makes it the natural CI gate.
hs-x checkhs-x dev
Starts the local dev server. In a terminal it prompts for the portal id, public target origin, TTL, and which components to serve; scripted runs pass --portal, --target-origin, --project-id, --account-id, and --ttl-seconds directly. The server listens on port 8787 unless --port picks another. dev status lists active portal-scoped override sessions on the control plane and dev cleanup --session-id <id> removes one.
hs-x dev --portal 46993937hs-x dev invoke <capability-id>
Runs one capability through the production runtime router, in process: payload validation, context construction, handler, and result envelope are exactly what a deployed Worker executes. Fixture defaults fill the dispatch payload; override them with --input, --object, and --install (each takes JSON), or replay the last recorded invocation with --last. --remote dispatches the same invocation at the deployed Worker instead — real install tokens, real portal — with --url <origin> to pin the Worker origin rather than resolving it through the Cloudflare API. The running dev server exposes the same engine over HTTP at POST /_hsx/invoke/<capability-id>.
hs-x dev invoke tag-high-value-deals --object '{"id":"d1","objectType":"deals","properties":{"amount":"99000"}}'hs-x api <path>
Raw HTTP against the HS-X control plane, or against the HubSpot developer-account API with the hubspot target. Request bodies build from arguments httpie-style: field=value for strings, field:=value for typed JSON, field==value for query parameters, Header:Value for headers. -X sets the method (default GET) and --pak supplies the HubSpot developer key when the environment doesn't. Per-portal CRM data is out of reach for both targets; that traffic goes through the control plane after the install account connects.
hs-x api hubspot crm-dev-applications/v3/appshs-x flags
Manages feature flags on the project's tenant runtime: list, create --file <path> (a JSON flag definition; define is an alias), and enable, disable, archive, each taking --key. Scope defaults come from hsx.config.ts and the local Cloudflare pointer; override with --project-id, --app-id, --environment, or --runtime-origin.
hs-x flags enable --key new-pricingDeploy, promote, roll back
hs-x deploy
Builds artifacts and deploys to HubSpot and Cloudflare. Without a linked account it runs unlinked, straight against the providers. --plan (or --dry-run) prints what would change without touching anything; --yes skips the confirmation and uses the default account. --portal-schema-live diffs each sync's declared schema against the live portal and prints a PLAN line per difference; --apply-schema applies that plan (creating or altering the portal properties) — the pair belongs to a first deploy, and applying needs the crm.schemas.<object>.write scope on your personal access key. --hubspot-upload and --cloudflare-deploy select sides explicitly, --build-only stops after generating local artifacts, and --promote-when-healthy waits for a healthy deploy and promotes it in one run. --heartbeat opts unlinked Workers into anonymous heartbeat events.
hs-x deploy --plan # see the plan first, then run with --yeshs-x promote
Promotes a recorded deploy to an environment; deploy promote is the same command. Takes --deploy-id plus --project-id and --account-id for context.
hs-x promote --deploy-id dep_0042 --project-id deal-taggerhs-x rollback
Rolls an environment back to an earlier deploy. Linked (after hs-x login), it is traffic-first: a membership-gated control-plane plan resolves the target's verified Cloudflare Worker version, the CLI creates a 100% deployment of it and health-probes it (restoring the prior version if the probe fails), and only then records the move and advances the active pointer; pass --account-id, --project-id, --deploy-id, and --force to skip prompts, and provide a Cloudflare API token (HSX_CLOUDFLARE_API_TOKEN / CLOUDFLARE_API_TOKEN). Unlinked, it updates the pointer in tenant Cloudflare KV with --project-id, --deploy-id, and optionally --environment. Unlinked rollback is a bookkeeping change: without revisioned routing, redeploy or re-route Cloudflare traffic yourself for it to affect live requests.
hs-x rollback --project-id deal-tagger --deploy-id dep_0041hs-x routes
Shows the active deploy routes for a project (route and routing are accepted spellings). Takes --project-id.
hs-x routes --project-id deal-taggerhs-x secrets
Stores deployment secrets HS-X passes into the tenant Cloudflare runtime. The one shipped scope is HubSpot OAuth app credentials: secrets hubspot-oauth set with --account-id, --project-id, --hubspot-app-id, --client-id, --client-secret, and optionally --env (production, staging, or dev). In a terminal, missing fields are prompted and the scope is confirmed before writing; each flag also has an HSX_* environment fallback.
hs-x secrets hubspot-oauth set --env stagingBring a legacy app over
The migrate family moves a legacy HubSpot app (platform 2023.2, 2025.1, or 2025.2) to a 2026.03 HS-X project. The generated project is a net-new dupe for testing in hs-x dev; the original app keeps running untouched until cutover. The migration guide walks the whole journey; this is the command surface.
hs-x migrate run [path]
The one-command migration: detects the legacy source (a project tree with hsproject.json, or a migration.json input), classifies every component, and generates the dupe from everything portable, including app cards, serverless functions, webhook subscriptions, and workflow actions. Pieces needing a human decision are listed with doc links; they gate cutover, not the dupe. --out names the output directory (default migrated-app), and re-running after resolving findings is safe.
hs-x migrate run ./legacy-app --out migrated-apphs-x migrate pull
Pulls a live, UI-configured legacy app's definition from HubSpot — cards, webhook subscriptions, workflow actions — and writes the migration.json input that migrate run consumes. In a terminal, omit --app-id to pick the app from a list of your developer account's migratable apps; --app-name overrides the recorded name and --out names the output file (default migration.json). Needs the HubSpot credentials hs-x connect hubspot stores.
hs-x migrate pull --app-id 123456hs-x migrate cutover [path]
Plans or performs the in-place cutover of the original app to 2026.03, keeping its app id, installs, OAuth grants, and listing. Bare, it prints the dry-run plan: the ordered steps, the one-way door (no downgrade from 2026.03), and every open decision. With --execute it performs the cutover once no blocking decision remains — a blocker is a source that's missing something cutover needs (a URL, entrypoint, or label) or carries an unsupported component; advisory "keep forwarding?" / "confirm this surface" findings don't block, since an in-place cutover keeps the source as-is. Because it's one-way, --execute asks you to type the project name to confirm (--yes skips that in automation; a non-TTY run without --yes is refused). A 2025.2 source takes the config-only path (platformVersion bump + in-place re-upload, rolled back if the build fails); 2023.2/2025.1 sources run HubSpot's own interactive hs project migrate, which needs a terminal to answer its feature prompts.
hs-x migrate cutover ./legacy-app # dry-run plan
hs-x migrate cutover ./legacy-app --execute # perform it (type the project name to confirm)hs-x migrate inspect <path> and hs-x migrate report <path>
inspect classifies a migration input: what migrates automatically, what needs human review, and whether the replacement needs the Cloudflare runtime. It exits 1 while human-review findings remain, so CI can gate on it. report summarizes the same analysis as readiness counts and suggested next steps.
hs-x migrate inspect ./legacy-app --jsonhs-x migrate cards <path>
Generates a replacement App Card project from a legacy CRM card migration input, then validates it. --project names the output directory. Fails while the input still has human-review findings; resolve those via inspect first.
hs-x migrate cards ./migration.json --project migrated-apphs-x migrate swap-cards
Swaps a live legacy CRM card for its replacement App Card through the HubSpot developer API. Requires --app-id, --legacy-card-id, and --replacement-card-id; --helpdesk-card-id covers the help-desk variant when there is one.
hs-x migrate swap-cards --app-id 123456 --legacy-card-id 1001 --replacement-card-id 2001Watch, diagnose, maintain
hs-x list
Lists your HS-X projects and their ids — the ids every project-scoped command on this page takes (status --project, logs, drift, routes). A linked-platform surface: it reads from the control plane and defaults to the active account, with --account-id to pick another.
hs-x lisths-x status
Bare hs-x status validates the local project tree: diagnostics plus the worker capabilities discovered in source. Inside a deployed project it also appends the deployed project's health — active routes, drift, and runtime telemetry — best-effort, so a dead network never breaks the local check. --project <id> shows that remote view for any project.
hs-x statushs-x doctor
Diagnoses local setup: accounts, HubSpot CLI auth, control-plane reachability, and recent HS-X activity. The first command to run when something feels off.
hs-x doctorhs-x logs
One timeline for everything your app does: Workers Logs rows from your deployed runtime ([cf]) merged with HubSpot's own app logs ([hs] — card and extension renders, production frontend logger output, webhook deliveries, API calls, OAuth authorizations). Run bare in a terminal for a guided project, source, log-type, and time-range picker; a project bound in the current directory is selected by default. --source chooses all (default), workers, or hubspot, and the two legs degrade independently — Workers Logs need a linked HS-X account, HubSpot logs need only a deployed app and HubSpot CLI credentials. Alongside --project-id and --account-id (or the active account): --limit, --since-minutes, --trace / --invocation, --raw, --filter, --sample, --follow, --interval-seconds, and --json, plus the HubSpot-side --type <name> (log type, repeatable or comma-separated), --errors-only, and --app-id <id> (defaults to the project's .hs-x/hubspot.json binding). Every row carries origin=workers|hubspot.
hs-x logs --project-id deal-tagger
hs-x logs --project-id deal-tagger --trace inv_01JY...
hs-x logs --project-id deal-tagger --follow --filter source=action,status>=500
hs-x logs --source hubspot --errors-onlyhs-x checkpoint
Reads the project's aggregate runtime telemetry checkpoint from the control plane: recent failures grouped by fingerprint (occurrences, affected portals, last seen), sampled successes, totals, and latency percentiles. Takes --project-id; the same aggregate also appears inside hs-x status --project <id>.
hs-x checkpoint --project-id deal-taggerhs-x drift and hs-x audit list
drift reports the project's drift state as recorded by the control plane and requires a linked account; it takes --project-id. audit list prints redacted audit rows for an account and takes --account-id.
hs-x drift --project-id deal-taggerhs-x history
Shows recent command runs recorded by the local CLI; --limit caps the count (default 20).
hs-x history --limit 5hs-x update and hs-x completion <shell>
update checks npm for a newer CLI release and installs it, using the package manager that owns the running binary (npm, bun, pnpm, or yarn); --check reports without installing, and --json is check-only by design (upgrade is an alias). completion prints a completion script for bash, zsh, or fish and registers both the hs-x and hsx command names.
hs-x completion zsh >> ~/.zshrcErrors carry a stable HSX_E_* code, a hint, and a docs link. Re-run with --verbose for the inferred cause, --debug for wire-level request and response detail, or --json to capture the full error envelope for a bug report.
Where the commands lead
- Getting started — the first session, narrated instead of listed.
- Local dev — what
hs-x devactually wires up against a real portal. - Migrate an app — the journey around
migrate run, the dupe, and cutover. - Environments — how deploy, promote, and rollback fit together.
- Secrets — why the runtime needs
hubspot-oauth setand what it unlocks. - Feature flags — authoring the flag definitions
hs-x flags createconsumes.
Last updated: July 24, 2026. Reflects @hs-x/cli v0.3.0; flags and subcommands mirror the CLI's own curated help. Refreshed whenever the command surface changes.