view .md
Reference · CLI

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.

Time
≈ 8 min read
Outcome
You know which command does what, the handful of flags each one really needs, and where the linked-account commands start.

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 it

Everything 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.

CommandWhat it does
hs-x initScaffold a new HS-X project (alias: create)
hs-x connectConnect HubSpot and Cloudflare credentials
hs-x loginAuthenticate an HS-X account with a dashboard token
hs-x accountsList and switch HS-X accounts (also whoami, logout)
hs-x link / unlinkAttach unlinked deploy state to an account / clear the session
hs-x checkValidate project source (alias: validate)
hs-x devLocal dev server, plus dev invoke for one-shot capability runs
hs-x apiRaw calls to the HS-X control plane or HubSpot developer API
hs-x flagsList, create, enable, disable, archive feature flags
hs-x deployBuild artifacts and deploy to HubSpot and Cloudflare
hs-x promotePromote a recorded deploy (alias: deploy promote)
hs-x rollbackRoll an environment back to an earlier deploy
hs-x routesShow active deploy routes
hs-x secretsStore runtime secrets, today hubspot-oauth set
hs-x migrateMigrate a legacy HubSpot app: run, pull, cutover, inspect, report, cards, swap-cards
hs-x listList your HS-X projects and their ids
hs-x statusProject health and discovered capabilities
hs-x logsOne timeline: deployed Worker invocations plus HubSpot's app logs
hs-x checkpointAggregate runtime telemetry from the control plane
hs-x driftProject drift state from the control plane
hs-x audit listRedacted account audit rows
hs-x doctorDiagnose local setup
hs-x historyRecent local command runs
hs-x updateUpdate the CLI to the latest npm release (alias: upgrade)
hs-x completionShell 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 hides

Commands 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 --yes

hs-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 cloudflare

hs-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_456

hs-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 --yes

Validate, 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 check

hs-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 46993937

hs-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/apps

hs-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-pricing

Deploy, 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 --yes

hs-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-tagger

hs-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_0041

hs-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-tagger

hs-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 staging

Bring 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-app

hs-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 123456

hs-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 --json

hs-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-app

hs-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 2001

Watch, 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 list

hs-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 status

hs-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 doctor

hs-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-only

hs-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-tagger

hs-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-tagger

hs-x history

Shows recent command runs recorded by the local CLI; --limit caps the count (default 20).

hs-x history --limit 5

hs-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 >> ~/.zshrc
When a command misbehaves

Errors 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 dev actually 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 set and what it unlocks.
  • Feature flags — authoring the flag definitions hs-x flags create consumes.

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.