@andrewgolovanov/pulse
v0.3.0
Published
Developer-first CLI for synchronizing, validating, running, and deploying SiteOS Pulse Playwright suites.
Readme
SiteOS Pulse CLI
SiteOS Pulse CLI synchronizes, validates, and runs Playwright smoke suites locally, then creates an immutable bundle for the SiteOS Pulse monitoring service.
Last reviewed: 2026-07-27.
Requirements
- Node.js 20.12 or newer.
- A JavaScript or TypeScript project using npm, pnpm, Yarn, or Bun.
- Chromium installed through Playwright before the mandatory local monitoring run.
During guided first-run setup, the CLI can install @playwright/test as a development dependency
after showing the exact package-manager command and receiving confirmation. It does not install
Chromium or any other project dependency automatically.
Install
Run without a permanent installation:
npx @andrewgolovanov/pulse --helpOr install the pulse command globally:
npm install --global @andrewgolovanov/pulse
pulse --helpQuick start
From the root of an existing project:
NPM_PULSE="npx @andrewgolovanov/pulse"
$NPM_PULSE login
npm install --save-dev @playwright/test
npx playwright install chromium
$NPM_PULSE init --project storefront --base-url https://storefront.example.com
$NPM_PULSE sync
$NPM_PULSE validate
PLAYWRIGHT_BASE_URL=http://localhost:3000 $NPM_PULSE test
$NPM_PULSE deploy --dry-runAlternatively, run pulse without a command for guided onboarding. If Playwright is missing,
SiteOS Pulse detects the package manager and offers to install only
@playwright/test before creating configuration files. If Chromium is missing during the local
test, the CLI prints the matching install command; it never downloads the browser without the
user running that command.
pulse init creates:
siteos.config.json;siteos.playwright.config.tsas an isolated production-monitoring configuration;tests/siteos/homepage.spec.tsas a replaceable starter check;- a
.siteos/pulse/entry in.gitignore.
Existing SiteOS Pulse configuration and the project's own Playwright configuration are not
overwritten. Pulse always points siteos.config.json at siteos.playwright.config.ts, so project
settings such as webServer, local-only URLs, custom reporters, or a multi-browser matrix cannot
leak into the isolated production runner.
Commands
pulse init
Create the minimal SiteOS Pulse project files. This explicit command does not install dependencies.
pulse init --project storefront --suite smoke --tests-dir tests/siteos --base-url https://storefront.example.compulse login
Authorize the CLI in your browser and choose the organization that should issue the deploy-only
token. Choosing it for the CLI does not change the active organization in the browser. Sessions for
multiple organizations can coexist for each API origin and are stored in
~/.config/siteos/pulse/credentials.json with user-only permissions.
pulse login
pulse login --api-url https://siteos-pulse.xui.seExisting version 1 credentials are migrated atomically to the multi-organization format when first read. An older CLI cannot read the new format, so rolling back may require signing in again.
pulse organizations, pulse use, and pulse status
List the organizations authorized for the current API origin, then bind the current project to one of them:
pulse organizations
pulse use acme
pulse statuspulse organizations marks the current project's binding with *. pulse status shows the API
origin, project binding, organization, session state, and expiry without printing the token. The
binding is keyed by the project's resolved filesystem path and stored outside Git in
~/.config/siteos/pulse/project-bindings.json. After a successful deployment, the private binding
also records the confirmed remote project ID and slug. The tracked slug in siteos.config.json
remains the portable identity used by teammates and CI.
Existing organization-only project bindings are read automatically and upgraded to version 2 on the next binding write. The file and its parent directory retain user-only permissions. Changing the bound organization clears project fields so a remote project ID cannot cross tenant context.
Remove one organization session or all sessions for the API origin:
pulse logout --organization acme
pulse logout --all
pulse logout --all --yesRemoving a session also removes local project bindings that point to that organization.
pulse validate
Validate configuration, test discovery, dependency declaration, bundle size, and secret exclusions.
pulse validate
pulse validate --jsonpulse sync
Compare the Playwright specs currently found under testsDir with the Checks in
siteos.config.json:
pulse sync
pulse sync --check
pulse sync --jsonInteractive synchronization reports four groups before changing anything:
- Added specs can be selected explicitly; each selected spec becomes one active manual Check.
- Removed exact selectors are removed automatically; a Check is removed when no selector remains.
- Unchanged exact selectors stay as they are.
- Pattern-managed Checks are reported with their current matches but are not rewritten.
A renamed spec therefore appears as one removal and one addition. Required local helper and fixture
imports are merged into bundle.include; existing entries are not pruned automatically. The CLI
shows the final change set and writes siteos.config.json only after confirmation. It also refuses
to apply a stale plan if the configuration changed during review.
--check and --json are read-only and exit with status 1 when drift or a blocker exists. Plain
pulse sync requires an interactive terminal.
pulse test
Run the project's own @playwright/test installation. Arguments after -- are passed to Playwright.
Pulse passes --config siteos.playwright.config.ts explicitly.
pulse test --base-url http://localhost:3000
pulse test --headed --project chromium -- --workers=1pulse deploy
Validate the project and build an immutable .tgz bundle with a SHA-256 checksum:
pulse deploy --dry-run
pulse deploy --dry-run --output .siteos/pulse/release.tgz --jsonRemote upload uses the versioned SiteOS Pulse API and the scoped session created by pulse login:
pulse deploy
pulse deploy --organization acme
pulse deploy --create-projectBefore building or uploading the bundle, the CLI validates the token and asks the Pulse API to resolve the project inside the selected organization. Resolution uses a confirmed local project ID first, then an exact slug. A normalized matching base URL with a different slug is treated as a possible duplicate, not as permission to create another dashboard project.
For a possible duplicate, an interactive deployment requires one explicit choice:
- update an existing project;
- create a separate project;
- cancel without changing the config, binding, bundle, or remote service.
Updating an existing project previews and confirms the tracked slug change, writes it atomically to
siteos.config.json, rebuilds from the final config, and stores the opaque project ID locally only
after a successful upload. Deliberate same-URL creation requires --create-project. --yes skips
the ordinary final deployment confirmation but never implies duplicate creation.
The final preview shows project, slug, organization, API origin, update/create mode, Check count,
and file count. If multiple organizations are authorized, select one interactively, pass
--organization <slug>, or persist the choice with pulse use <slug>.
pulse deploy --dry-run remains fully local: it validates and builds the bundle without signing in
or contacting the API. JSON output includes the resolved deployment target and does not print human
prompts.
For non-interactive CI, SITEOS_PULSE_API_TOKEN can override saved local sessions. The server-side
token principal is authoritative for the deployment organization; environment tokens are never
written to credentials or project bindings. A non-interactive deploy must resolve its organization
without a prompt. An unresolved same-URL collision exits with PROJECT_COLLISION; normally it is
resolved once interactively and the corrected slug is committed. Use --create-project in CI only
when a distinct same-URL project is intentional.
CLI 0.3.0 requires the project-resolution API. An older server produces
PULSE_API_VERSION_UNSUPPORTED before upload; the CLI does not fall back to the former unsafe
create behavior.
The CLI has no direct access to PostgreSQL, artifact storage, the scheduler, or the runner.
Configuration
siteos.config.json is data-only JSON and is never executed as JavaScript:
{
"version": 2,
"project": {
"slug": "storefront",
"name": "Storefront",
"baseUrl": "https://storefront.example.com",
"monitoringEnabled": true
},
"testsDir": "tests/siteos",
"playwrightConfig": "siteos.playwright.config.ts",
"checks": [
{
"slug": "smoke",
"name": "Smoke",
"include": ["tests/siteos/**/*.spec.ts"],
"active": true,
"schedule": { "mode": "scheduled", "cadenceSeconds": 300 }
}
],
"apiUrl": "https://siteos-pulse.xui.se"
}Use bundle.include for helpers and fixtures that are required at runtime but are not Playwright
test selectors. Paths must stay inside the project root.
Bundle safety
Deployment bundles are limited to 5,000 files, 50 MiB total, and 10 MiB per file. The CLI rejects sensitive or control-plane paths including:
.envand.env.*;.npmrc;- filenames containing
secretorcredential; .git,.siteos,.checks, andnode_modules.
SITEOS_PULSE_API_TOKEN is read from the process environment only when provided and must never
be placed in siteos.config.json or committed to the project.
