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 answer

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 (or --json-stream for newline-delimited events; never both), 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)
hs-x logoutRevoke the active account's session and clear its local token
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, dev status and dev cleanup for override sessions, and dev start|logs|stop|restart for background sessions
hs-x reactReact and HubSpot UI-extension health checks: doctor, review, rules
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 projectHubSpot-compatible native project commands: dev, info, list-builds, upload, deploy, logs, validate
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; --json-stream emits newline-delimited events instead (never together with --json). --no-color strips ANSI styling. --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. Usage telemetry contains the command/subcommand, CLI version, exit code, duration, output mode, OS/architecture/runtime, and CI boolean; it contains no argv, paths, project data, or stable machine identifier. It can also be disabled with HSX_TELEMETRY_OPTOUT=1 or DO_NOT_TRACK=1; a one-time notice on first run says so.

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, mcp-server, or empty), --template picks a starter (deals-tagger, empty, mcp-server, sync-source), --distribution chooses private (default) or marketplace, and --ui-extension adds a starter app card (--no-ui-extension to skip). --object-type picks the CRM object the starter action enrolls (contact, deal (default), company, or ticket), --auth picks oauth (default) or static, and --app-name sets the HubSpot display name. In a terminal without --yes, unanswered choices become a short wizard (Esc goes back, Ctrl+C cancels); --yes accepts every default and installs dependencies without prompting; --no-install and --force do what they say. When you're logged in, init also registers the project with the platform and writes .hs-x/project.json; --no-link skips that. The mcp-server starter registers an external HubSpot Breeze MCP service and requires OAuth; see the Breeze MCP guide.

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, --display-name, 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, or open HubSpot's personal-access-key page for you). Scripted runs must pass all three; a non-TTY run without them exits with HSX_E_INPUT_MISSING_CONNECT_FLAGS. --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 no API token to create or paste. Stored-direct keeps the refresh token in local custody; a logged-in run lets the control plane broker the exchange server-side instead. 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, and --display-name labels the stored credential.

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

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. --profile/-p <name> validates a native HubSpot project under one of its profiles.

hs-x check

hs-x dev

Starts the local dev server. Inside an HS-X project it starts without prompting: the portal comes from the HubSpot account bound by hs-x connect hubspot (or the HubSpot CLI's default account), the dev override on the deployed Worker defaults to observe mode (stream its request and logger.* lines into the terminal) with a two-hour TTL, and every component runs; --pick opens a component picker. From a parent workspace a terminal asks which local project to run. Scripted runs pass --portal, --project-id, --account-id, and --ttl-seconds directly. The server listens on port 8787 unless --port picks another, and the unified log sidecar that card loggers forward to listens on 9099 unless --hsx-log-port moves it. --only <selector> scopes the log stream (a lane such as frontend, backend, request, or hubspot; a level such as errors or warnings; cap:<id>; or free text; repeatable), --capability <id> (repeatable) scopes the override to specific capability ids, --force clears matching overrides before registering, --telemetry-origin <url> replaces the auto-managed cloudflared quick tunnel with your own, --target-origin <url> flips the override to proxy mode (live invocations forwarded to an origin that serves POST /capabilities/<id>/invoke), --no-hubspot skips the HubSpot dev integration, --no-ui-extensions skips UI-extension bridging, and --detach is dev start. Live log streaming needs cloudflared on your PATH.

In a tree with hsproject.json and no hsx.config.ts, hs-x dev runs HubSpot's own dev session for the native project (hs-x project dev is the same command) and follows hs project dev's startup semantics. The project account is the HubSpot CLI's selected account unless --project-account overrides it. The testing account comes from --testing-account; without it, a terminal asks which configured account to test on, listing the project account's developer test accounts first, then its sandboxes, then the project account itself marked as production (a project account that is already a test account or sandbox is used without asking). --yes, --json, and non-TTY runs skip the picker, test on the project account, and warn HSX_W_DEV_TESTING_ON_PRODUCTION_ACCOUNT; hs-x lists only accounts the HubSpot CLI already knows, so create a sandbox with hs sandbox create or a developer test account from your developer account and hs account auth it. For marketplace apps hs-x then counts the portals that have the app installed (test portals excluded); when there are any it prints the count as HSX_W_DEV_PRODUCTION_APP_INSTALLS and a terminal confirms Proceed with local development of this production app? (default No; --yes proceeds with the warning, and the JSON payload carries productionInstallCount). --component <uid> (repeatable) picks components, --profile/-p picks a profile, and if HubSpot's dev port is occupied an interactive run identifies the process and offers to stop it before retrying. --local-proxy <auto|always|never> controls the app's local.json proxy map: auto (default) applies it only while every target is listening and otherwise keeps HubSpot's own proxy for every hubspot.fetch, always applies it regardless and enters proxy mode even without a local.json, and never ignores the file. For apps where HubSpot cannot run app functions locally (anything but private static-auth on 2026.03+), card console and logger output reaches the terminal through that same local proxy mode via an hs-x relay mapping, so the frontend lane needs a live local target or --local-proxy always; in proxy mode, fetches to unmapped origins leave your machine and are signed only when HUBSPOT_CLIENT_SECRET (or CLIENT_SECRET) is set. A register conflict with a session left behind by a crashed run is replaced automatically.

dev status probes the local dev server on --port (its /_hsx/health and manifest) and works unlinked; pass --account-id and --control-plane-url (or HSX_ACCOUNT_ID and HSX_CONTROL_PLANE_URL; there is no stored-account fallback) to additionally list the portal-scoped override sessions recorded on the control plane. dev cleanup --control-plane-url <url> --account-id <id> --session-id <id> removes one; a terminal confirms (default No) and --yes is required for JSON or non-TTY runs. dev status --session <id> reports on a managed background session instead (next entry).

hs-x dev --portal 46993937

hs-x dev start, logs, stop, restart

The agent-managed form of the same server. hs-x dev start (or hs-x dev --detach) launches it in the background and returns a stable session id; --wait-seconds <n> (default 60) bounds how long start waits for the health probe. hs-x dev logs --session <id> reads the session's append-only event stream, with --follow to keep reading, --lane <lane> (frontend, backend, request, hubspot; repeatable) and --level <level> (debug, info, warn, error; repeatable) to filter, --search <text> for a case-insensitive match, --since <time> (an ISO timestamp or a duration such as 30s, 5m, 2h), --limit <n>, --cursor <n> to resume from a byte offset, and --json-stream for NDJSON in follow mode (--follow --json is refused, since JSON is a finite document). hs-x dev status --session <id> reports whether that session is alive. hs-x dev stop --session <id> and hs-x dev restart --session <id> verify the saved PID still identifies the exact session before signalling it; non-TTY and --json mutations require --yes, and --force escalates to SIGKILL only after a graceful shutdown times out.

hs-x dev start --json
hs-x dev logs --session dev_01JYQ4V9K3M8Z2R7T6B5N1PXWA --follow --lane backend
hs-x dev stop --session dev_01JYQ4V9K3M8Z2R7T6B5N1PXWA --yes

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 (each declared input field gets its default, else a typed sample); 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 (which needs CLOUDFLARE_API_TOKEN). --cwd <dir> picks the project root. The exit code is 1 when the dispatch fails or the runtime envelope reports ok: false. Under Bun the worker source is re-imported on every dispatch. The running dev server exposes the same engine over HTTP at POST /_hsx/invoke/<capability-id>; the dev HTTP reference has the envelopes.

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), --pak supplies the HubSpot developer key when the environment doesn't, and --base-url overrides the target's base URL (HSX_CONTROL_PLANE_URL and HSX_HUBSPOT_BASE_URL are the environment equivalents). 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 apps-dev/external/public/v3/full/portal

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. In a terminal, bare hs-x flags chooses an action, create without --file runs a guided boolean-flag wizard, and --key may be omitted to pick from a list; every mutation shows a default-No confirmation, and JSON or non-TTY runs require --yes. Scope defaults come from .hs-x/project.json, .hs-x/hubspot.json, and the active deploy record; override with --project-id, --app-id, --environment, --runtime-origin, or --cloudflare-api-token.

hs-x flags enable --key new-pricing

hs-x react

Inspects HubSpot React UI extensions against the shared HS-UIX rule catalog, with no HS-X login, Cloudflare account, network, or migration required. react doctor runs generic React health checks (hooks, memoization, correctness, performance, code quality) plus HubSpot UI-extension checks with stable rule ids: --scope full|files|changed|lines with --base <ref> narrows to a Git diff, --staged scans staged files, --ci reports only findings introduced against the base, --recursive discovers every nested hsproject.json, --deep adds dead files, exports, dependencies, and cycles, --hubspot-only skips the generic checks, and --strict fails on review-tier findings too. react doctor why <file:line> explains every finding at one location. react review builds an agent-facing review packet (deterministic findings, component evidence, and the versioned rule sources; --deep includes archived trees). react rules shows how each catalog rule is handled, and react rules explain <rule-id> explains one.

hs-x react doctor --scope changed --base main
hs-x react doctor why src/app/cards/Card.tsx:42

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. A bare hs-x deploy keeps the combined HubSpot + Cloudflare workflow.

Plan and consent. --plan (or --dry-run) prints what would change without touching anything. In a terminal the deploy shows its plan and stops at Apply this plan?; --yes skips that confirmation and uses the default account, and a JSON or non-TTY run without --yes is refused with HSX_E_INPUT_INVALID.

Targets. Provider flags make the target set explicit: --cloudflare-deploy deploys only to Cloudflare and never infers a HubSpot upload, --hubspot-upload selects only HubSpot, and passing both selects a combined deploy. Plan and JSON output report deploymentMode plus the requested targets. --build-only stops after generating local artifacts; --cloudflare-dry-run renders the Cloudflare program without pushing it.

HubSpot-direct. In a tree with hsproject.json and no hsx.config.ts, hs-x deploy validates the native project, uploads it, waits for the build, and deploys it using the account the HubSpot CLI selected — no Cloudflare, control plane, or login. Its flags: --account/-a, --config/-c <path>, --use-env, --pak <token>, --message/-m <text>, --hubspot-upload-only (alias --skip-deploy, which uploads and builds with skipAutoDeploy), and --force/-f. Flags that need Cloudflare or the control plane fail clearly in this mode.

Exit codes. 0 on success; 1 on failure; 10 for input and consent errors; 20 when the Worker shipped but the HubSpot upload failed (HSX_W_DEPLOY_PARTIAL).

Environment. --env <value> (also --environment) bakes dev, staging, or production into the generated Worker; the default is production. What that value scopes is the environments reference.

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

Recording and promotion. On a linked deploy the revision is recorded in the control plane by default; --no-record skips that, and --record-local forces it. --promote-when-healthy waits for a healthy attestation and promotes in one run, with --promotion-timeout-ms raising the default 60-second wait. --heartbeat opts unlinked Workers into anonymous heartbeat events; --no-heartbeat disables the generated attestation wiring on linked ones. The deploy lifecycle reference explains what each of these changes.

The advanced flags (HubSpot-only deploys, local mocks, control-plane overrides, CI attribution) stay out of the short help; hs-x deploy --help-all lists them.

hs-x deploy --plan --cloudflare-deploy                   # Cloudflare only
hs-x deploy --plan --cloudflare-deploy --hubspot-upload  # explicit combined deploy
hs-x deploy --env staging --promote-when-healthy         # staging, recorded and promoted

hs-x project

HubSpot-compatible commands for a native HubSpot project (an hsproject.json tree with no hsx.config.ts). They use the account the HubSpot CLI has selected and never contact Cloudflare or the HS-X control plane, so no migration, linking, or HS-X login is needed. project info shows the current project, deployed build, components, app id, auto-deploy setting, selected account, and dashboard URL (--details lists every component). project list-builds lists recent builds (--project <name>, --limit <n>, 1 to 100). project upload uploads the sources and creates a build, the drop-in counterpart of hs project upload: --profile <name> picks an hsprofile.<name>.json, --message <text> sets the build message, --skip-auto-deploy builds without deploying, and --plan shows the account, project, and action without writing. project deploy deploys an existing successful build (--build <id>, or --deploy-latest-build to skip the picker). project logs follows the app's HubSpot execution logs (--function <name>, --tail), and project validate parses and validates the project locally. project dev is hs-x dev for a native project. Upload and deploy also take --force-create (create without accepting skipped metadata), --skip-npm-audit, and --timeout-ms <ms> (build/deploy polling, default 120000); the read commands take --json-schema to print their result schema without a request. All of them accept --account, --config, --use-env, --json, and HubSpot's --format-output-as-json spelling.

hs-x project upload --profile staging
hs-x project deploy --deploy-latest-build --yes --json

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. Bare hs-x migrate in a terminal is a guided journey: it discovers hsproject.json and migration.json sources beneath the workspace, inspects the one you pick, previews its output, and asks for confirmation (default No) before writing a dupe; it never deploys or cuts over. 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 findings (“keep forwarding?”, “confirm this surface”) 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]). 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. Alongside --project-id and --account-id (or the active account): --limit (default 50, clamped to 1–200), --since-minutes (default 15, clamped to 1–10080), --trace / --invocation, --raw, --filter, --sample, --follow (alias --tail) with --interval-seconds (default 3, clamped to 1–60), and --json, plus the HubSpot-side --type <name>, --errors-only, and --app-id <id>. What each leg reads, how they degrade, and how to read a trace is the observability reference.

hs-x logs --project-id deal-tagger
hs-x logs --project-id deal-tagger --trace inv_01JYQ4V9K3M8Z2R7T6B5N1PXWA
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, with --action, --resource <type[/id]>, --actor <user-id>, --outcome (success, failure, or in_progress), --since (30m, 24h, 7d, or an ISO timestamp), and --limit (default 50, clamped to 1–200) as filters. Bare hs-x audit in a terminal opens an interactive account, time-range, filter, and event-detail explorer.

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. Exit codes follow one convention: 10 for input and consent errors (a missing flag, a mutation refused without --yes), 130 for a cancelled prompt, 2 for an unknown dev subcommand or a bad --only selector, 20 for a partial deploy, and 1 for everything else.

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: September 1, 2026. Reflects @hs-x/cli v0.4.11; flags are copied by hand from hs-x <command> --help-all. Refreshed whenever the command surface changes.