walkerOS CLI
The walkerOS CLI (@walkeros/cli) is a command-line tool for building, testing, and running event collection flows. It handles the complete workflow from configuration to deployment. It bundles flows into optimized JavaScript, testing with simulated events, and running collection servers locally or in Docker.
Installation
Global Installation (Recommended)
Install globally to use the walkeros command anywhere:
npm install -g @walkeros/cli
# Verify installation
walkeros --versionLocal Installation
Install in your project for team consistency:
npm install --save-dev @walkeros/cli
# Use with npx
npx walkeros --versionCommands overview
| Command | Purpose | Use Case |
|---|---|---|
bundle | Build production-ready bundle from flow config | Create deployable JavaScript from configuration |
push | Execute event with real API calls (or --simulate for mocked) | Testing and production validation |
setup | Run the optional setup() lifecycle on one component | Provision external resources (BigQuery datasets, Pub/Sub topics, SQLite tables, webhook registrations) |
validate | Validate events, flows, mappings, contracts, or entries | Check configuration before bundling |
run | Start HTTP event collection server | Accept incoming events via HTTP POST |
cache | Manage CLI package and build caches | Clear stale caches, view cache statistics |
auth | Authentication and identity | Log in, log out, check identity |
projects | Manage walkerOS projects | Create, list, update, delete projects |
flows | Manage walkerOS flows | Create, list, update, delete, duplicate flows |
deploy | Create and manage deployments | Deploy flows to walkerOS cloud or self-hosted |
previews | Manage preview bundles | Test flow changes on live sites before deploying |
The push command accepts either a config JSON or a pre-built bundle as input.
Configuration types
The CLI uses types from @walkeros/core:
Flow.Json- Root config file format (version,flows)Flow- Single flow (hasconfig,sources,destinations,transformers,collector)Flow.Config- Per-flow config block (platform,url,settings,bundle)Collector.InitConfig- Runtime type passed tostartFlow()
The CLI transforms Flow.Json → Flow (per flow) → bundled code that uses Collector.InitConfig at runtime.
Packages and overrides
Build-time concerns live under each flow's config.bundle block. Three fields are supported:
packages: the list of npm packages (or local paths) the bundler should install for this flow. Pacote downloads them based on this list. You do not need to runnpm installyourself for step packages; the CLI handles it transparently.overrides: pin transitive dependency versions, matching npm'soverridessemantics. Useful when an upstream package declares an overly narrow version range that conflicts with a newer transitive version in the same tree.traceInclude(server flows only): an escape hatch for the file tracer. See below.
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/collector": {}
},
"overrides": {
"@amplitude/analytics-types": "2.11.1"
}
}
}
}
}Server bundles use nft tracing
Server flows (platform: "server") are traced automatically with @vercel/nft. The bundler externalizes every step package, then nft walks the entry to figure out which files are actually reachable at runtime, and copies only those files into dist/node_modules/. Native add-ons, .proto files, and __dirname-loaded assets are picked up.
There is no walkerOS.bundle.external annotation: nft figures out the externalization automatically.
Escape hatch: traceInclude
If nft cannot statically reach a file (rare: dynamic require(somePath) constructed from a runtime variable, dynamically loaded data files), declare it explicitly with flow.<name>.config.bundle.traceInclude. Paths and globs are both supported (matched via picomatch). Paths resolve against the install root, not your project directory.
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": { "@walkeros/server-destination-gcp": {} },
"traceInclude": [
"node_modules/some-pkg/data/*.json",
"node_modules/another-pkg/lib/runtime-loaded.js"
]
}
}
}
}Range conflict resolution
When two transitive consumers declare incompatible ranges for the same dependency (e.g., arrify@^3.0.0 from one package, arrify@^2.0.0 from another), the bundler now resolves the chosen range to a concrete version via the npm registry and nests any non-satisfying spec under its consumer's node_modules/. This kills classes of upstream chaos (like arrify is not a function from @google-cloud/common) before they can reach runtime. After install, a defense-in-depth check warns when any installed package's declared deps don't match what's reachable on its resolution path; if you see those warnings, add an overrides entry to your flow's config.bundle.overrides to pin the offending dep. If the npm registry is unreachable during validation, set BUNDLER_STRICT_RANGES=0 to bypass strict validation with a warning instead of failing the build.
Schema version
The flow.json schema stays at version: 4. Build-time fields live under flow.<name>.config.bundle.{packages, overrides, traceInclude}. The flow.<name>.config.bundle.external sub-field is no longer supported in @walkeros/cli@4.x.
Package imports
Implicit collector
The collector is added automatically. To pin a specific version (recommended for production), add the collector explicitly:
"packages": {
"@walkeros/collector": { "version": "1.0.0" },
"@walkeros/web-source-browser": {},
"@walkeros/destination-demo": {}
}Default exports (sources & destinations)
Sources and destinations automatically use their default export - no imports needed:
"packages": {
"@walkeros/web-source-browser": {}, // Uses default export
"@walkeros/destination-demo": {} // Uses default export
}Utility imports
Use imports when you need specific utility functions from a package:
"packages": {
"@walkeros/core": { "imports": ["getId", "clone"] }, // Optional utilities
"@walkeros/web-source-browser": {
"imports": ["createTagger"] // Additional utility
}
}Named-export selection with import
For packages without a default export, or to pick a specific named export, set import on the step alongside package. The bundler adds the name to the imports list automatically.
"sources": {
"custom": {
"package": "@my/custom-package",
"import": "namedExport"
}
}The legacy code: "namedExport" form is no longer accepted. Validation raises OBSOLETE_CODE_STRING with a rename hint pointing to import.
Local packages
By default, the CLI downloads packages from npm. For development or testing unpublished packages, you can use local packages instead by specifying a path property.
Configuration
Add a path property to any package to use a local directory instead of npm:
{
"packages": {
"@my/custom-destination": {
"path": "./my-custom-destination"
}
}
}Resolution Rules
pathtakes precedence - When bothpathandversionare specified,pathis used- Relative paths - Resolved relative to the config file's directory
- Absolute paths - Used as-is
- dist folder - If a
dist/folder exists, it's used; otherwise the package root is used
Dependency Resolution
When a local package has dependencies on other packages that are also specified with local paths, the CLI will use the local versions for those dependencies too. This prevents npm versions from overwriting your local packages.
{
"packages": {
"@walkeros/core": {
"path": "../packages/core"
},
"@walkeros/collector": {
"path": "../packages/collector"
}
}
}In this example, even though @walkeros/collector depends on @walkeros/core, the local version of core will be used (not downloaded from npm). This is essential when testing changes across multiple interdependent packages.
Use Cases
Development of custom packages:
{
"packages": {
"@my-org/destination-custom": {
"path": "../my-destination"
}
}
}Testing local changes to walkerOS packages:
{
"packages": {
"@walkeros/collector": {
"path": "../../packages/collector"
}
}
}When ready for production, simply remove the path property to use the published npm version.
Getting started
Before using the CLI, you need a flow configuration file. Here's a minimal example:
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/server-source-express": {},
"@walkeros/destination-demo": {}
}
}
},
"sources": {
"http": {
"package": "@walkeros/server-source-express",
"config": {
"settings": { "path": "/collect", "port": 8080 }
}
}
},
"destinations": {
"console": {
"package": "@walkeros/destination-demo",
"config": {
"settings": { "name": "Console Logger" }
}
}
},
"collector": { "run": true }
}
}
}The @walkeros/collector package is automatically added when your flow has sources or destinations.
Save this as flow.json.
Bundle command
The bundle command builds production-ready JavaScript bundles from flow configurations.
Use Case
You've defined your sources, destinations, and transformations in a flow configuration file. Now you need to:
- Download the required npm packages
- Bundle everything into a single optimized JavaScript file
- Deploy it to production (Docker, Cloud Run, serverless functions)
The bundle command handles all of this.
Basic Usage
walkeros bundle flow.jsonThis writes the optimized bundle to stdout (web flows only). Use -o to write to a file or directory (e.g., -o ./dist/walker.js for web, -o ./dist/ for server, which produces dist/{flow.mjs, package.json, node_modules/}). For server flows you can also write a .tar.gz/.tgz archive (e.g., -o ./flow.tar.gz), which packs the server bundle directory (flow.mjs, package.json, node_modules/) into a single gzip file. Web single-file bundles do not support archive output.
Step-by-Step Guide
1. Create a flow configuration
Create server-collect.json:
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/server-source-express": {},
"@walkeros/destination-demo": {}
}
}
},
"sources": {
"http": {
"package": "@walkeros/server-source-express",
"config": {
"settings": {
"path": "/collect",
"port": 8080,
"cors": true
}
}
}
},
"destinations": {
"console": {
"package": "@walkeros/destination-demo",
"config": {
"settings": {
"name": "Event Logger",
"values": ["name", "data.title", "timestamp"]
}
}
}
},
"collector": { "run": true }
}
}
}2. Bundle the flow
walkeros bundle server-collect.json --statsOutput:
📦 Downloading packages from npm...
✓ @walkeros/collector@latest
✓ @walkeros/server-source-express@latest
✓ @walkeros/destination-demo@latest
🔨 Bundling...
✓ Bundle created: ./dist/flow.mjs
📊 Bundle Statistics:
Size: 45.2 KB (minified)
Packages: 3
Format: ESM
3. Review the bundle
ls -lh dist/
# -rw-r--r-- 1 user staff 45K flow.mjs
# -rw-r--r-- 1 user staff 152B package.json
# drwxr-xr-x 12 user staff 384B node_modules
file dist/flow.mjs
# dist/flow.mjs: JavaScript source, UTF-8 Unicode textThe bundle is now ready to deploy!
Options
walkeros bundle <config-file> [options]| Option | Description |
|---|---|
-o, --output <path> | Write bundle to file, directory, or presigned URL |
-f, --flow <name> | Build specific flow (for multi-flow configs) |
--all | Build all flows |
-s, --stats | Show bundle statistics |
--json | Output statistics as JSON (for CI/CD) |
--no-cache | Skip package cache, download fresh |
-v, --verbose | Detailed logging |
When --output is a URL (e.g., a presigned S3 URL), the CLI bundles to a temp file and uploads via HTTP PUT. This is used by the walkerOS cloud service for remote builds.
For server flows, -o resolves to a directory: dist/{flow.mjs, package.json, node_modules/}. When -o ends in .tar.gz or .tgz, that same directory is packed into a single gzip archive instead (server flows only). For multi-flow --all, each flow gets its own subdirectory: dist/<flowName>/....
Multi-Flow Example
# Bundle development flow
walkeros bundle config.json --flow development
# Bundle production with stats
walkeros bundle config.json --flow production --stats
# Bundle all flows
walkeros bundle config.json --allPush command
The push command executes your flow with a real event. By default it makes actual API calls to your configured destinations. Use --simulate to mock specific steps for safe testing. It accepts either a config JSON (which gets bundled) or a pre-built bundle.
Use Case
You want to:
- Test event processing with mocked destinations (
--simulate) - Test with real third-party APIs (GA4, Meta, BigQuery, etc.)
- Verify production credentials and endpoints work
- Debug actual API responses and errors
- Perform integration testing before deployment
- Execute a pre-built bundle without rebuilding
Push handles both safe local testing (with --simulate) and real integration testing.
Basic Usage
# With config JSON (auto-bundled)
walkeros push flow.json --event '{"name":"page view","data":{"title":"Home"}}'
# With pre-built bundle
walkeros push dist/flow.mjs --event '{"name":"page view"}'Step-by-Step Guide
1. Create a flow configuration
Create api-flow.json with a destination that makes real HTTP calls:
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/web-destination-api": {}
}
}
},
"destinations": {
"api": {
"package": "@walkeros/web-destination-api",
"config": {
"settings": {
"url": "https://your-endpoint.com/events",
"method": "POST"
}
}
}
},
"collector": { "run": true }
}
}
}2. Create an event file
Create event.json:
{
"name": "order complete",
"data": {
"id": "ORD-12345",
"total": 299.99,
"currency": "USD"
},
"user": {
"id": "user_abc123"
}
}3. Push the event
walkeros push api-flow.json --event event.json --verbose4. Review the output
📥 Loading event...
📦 Loading flow configuration...
🔨 Bundling flow configuration...
🖥️ Executing in server environment (Node.js)...
Pushing event: order complete
✅ Event pushed successfully
Event ID: 1701234567890-abc12-1
Entity: order
Action: complete
Duration: 1234ms
The event was sent to your real API endpoint!
Options
walkeros push <input> [options]| Option | Description |
|---|---|
-e, --event <source> | Required. Event to push (JSON string, file path, or URL) |
-f, --flow <name> | Flow name (for multi-flow configs) |
-p, --platform <platform> | Platform override (web or server) |
--simulate <step> | Simulate a step (repeatable). Mocks the step's push, captures result. Use destination.NAME or source.NAME. |
--mock <step=value> | Mock a step with a specific return value (repeatable). Use destination.NAME=VALUE. |
--snapshot <source> | JS file to eval before execution. Sets global state (window.dataLayer, process.env, etc.). |
-o, --output <path> | Write result to file |
--json | Output results as JSON |
-v, --verbose | Verbose output with debug information |
-s, --silent | Suppress output (for CI/CD) |
Input Types
The CLI auto-detects the input type by attempting to parse as JSON:
- Config JSON - Bundled and executed
- Pre-built bundle (
.js/.mjs) - Executed directly
When using pre-built bundles, platform is detected from file extension:
.mjs→ server (ESM, Node.js).js→ web (IIFE, JSDOM)
Use --platform to override if extension doesn't match intended runtime.
Event Input Formats
The --event parameter accepts three formats:
Inline JSON string:
walkeros push flow.json --event '{"name":"page view","data":{"title":"Home"}}'File path:
walkeros push flow.json --event ./events/order.jsonURL:
walkeros push flow.json --event https://example.com/sample-event.jsonPush modes
| Mode | Flag | API Calls | Use Case |
|---|---|---|---|
| Real | (none) | Real HTTP requests | Integration testing, production validation |
| Simulate | --simulate | Mocked (captured) | Safe local testing |
| Mock | --mock | Returns mock value | Controlled testing |
Recommended workflow:
- Use
push --simulatefirst to validate configuration without side effects - Use
push(without flags) to verify real integrations work before deployment
JSON Output
For CI/CD pipelines, use --json for machine-readable output:
walkeros push flow.json --event '{"name":"page view"}' --json --silentOutput:
{
"success": true,
"event": {
"id": "1701234567890-abc12-1",
"name": "page view",
"entity": "page",
"action": "view"
},
"duration": 1234
}
On error:
{
"success": false,
"error": "Connection refused: https://your-endpoint.com/events",
"duration": 5023
}
Multi-Flow
Push to specific flows:
# Push to staging
walkeros push flow.json --event event.json --flow staging
# Push to production
walkeros push flow.json --event event.json --flow productionSetup command
The setup command runs the optional setup() lifecycle on a single component to provision external resources before traffic flows. Use it for one-time provisioning steps like creating a BigQuery dataset and table, declaring a Pub/Sub topic and subscription, creating SQLite tables, or registering a webhook with a third-party API.
For the conceptual overview of the lifecycle (when to implement setup() in a component, how it relates to the runtime hot path, and the operator separation rationale), see Setup lifecycle.
Use case
Setup is for the operator-time, "do this once before traffic" step that sits between writing config and accepting events:
- A BigQuery destination needs its dataset and table to exist with the right schema before rows can be streamed in.
- A Pub/Sub source needs a subscription against a topic before it can pull messages.
- A SQLite store needs its tables created before reads and writes work.
- A webhook integration needs to register its callback URL with the upstream service.
Setup is explicit only. It is never triggered by push, simulate, deploy, or the long-running runtime. You run it once when provisioning, then again only when external resources need to be re-provisioned (for example, after changing the table schema in config). The runtime never tries to "fix" missing resources on its own.
Basic usage
# Provision the BigQuery dataset and table for the destination named "bigquery"
walkeros setup destination.bigqueryTarget syntax
The target uses the same <kind>.<name> syntax as walkeros push --simulate. Valid kinds are source, destination, and store. Transformers are pure functions and have no setup.
| Target | Resolves to |
|---|---|
destination.bigquery | The destination named bigquery in the resolved flow |
source.events-in | The source named events-in |
store.session | The store named session |
Options
walkeros setup <target> [options]| Option | Description |
|---|---|
-c, --config <path> | Flow config file (default: ./flow.json) |
-f, --flow <name> | Flow name for multi-flow configs |
--json | Output as JSON (passed to the package's setup logger) |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
What "skip" means
The framework narrates one of three reasons when nothing runs and exits successfully:
| Reason | Trigger |
|---|---|
no setup function | The package does not export a setup function on its default export |
config.setup is false | The flow config explicitly opts out with "setup": false |
config.setup is unset | The flow config does not declare setup at all |
In all three cases the exit code is 0. Setup is a single-purpose command, not a tiered status check.
Result output
When the package's setup() returns a non-undefined value, the CLI emits it as JSON on stdout for jq-style scripting. This lets you script around what was provisioned:
walkeros setup destination.bigquery --json | jq .datasetCreatedIf the package returns nothing, no JSON is emitted; you only see the framework narration.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success or skip (any of the three skip reasons above) |
| non-zero | Failure (resolution error, missing default export, package threw) |
IAM note
Setup typically needs higher permissions than runtime push: "create dataset" or "create subscription" vs "write rows" or "pull messages". Operators commonly run setup with a separate service account, or different credentials, than the runtime uses. Plan your IAM accordingly: grant the runtime only what it needs to push, and grant setup the broader provisioning scope.
Examples
# Provision the BigQuery dataset and table for the destination named "bigquery"
# in the default flow file.
walkeros setup destination.bigquery
# Same but pointing to a specific flow in a multi-flow config.
walkeros setup destination.bigquery --flow analytics
# Custom config path.
walkeros setup destination.bigquery --config ./flows/prod.json
# Pipe the structured result to jq.
walkeros setup destination.bigquery --json | jq .datasetCreated
# Provision a Pub/Sub source's subscription.
walkeros setup source.events-inValidate command
The validate command checks the structure and correctness of events, flow configurations, mapping configurations, contracts, or individual flow entries before bundling or deployment.
Use case
Before bundling or deploying your flow, you want to:
- Catch configuration errors early
- Verify event structure follows walkerOS conventions
- Check mapping patterns are valid
- Validate contracts define proper entity-action schemas
- Validate a specific destination, source, or transformer entry against its package's published JSON Schema
- Integrate validation into CI/CD pipelines
Validate gives you fast feedback without the overhead of bundling.
Basic usage
# Validate a flow configuration (schema, references, cross-step examples)
walkeros validate flow.json
# Validate an event structure
walkeros validate event.json --type event
# Validate a mapping configuration
walkeros validate mapping.json --type mapping
# Validate a contract
walkeros validate contract.json --type contract
# Validate a specific entry against its package schema
walkeros validate flow.json --path destinations.snowplowValidation types
The --type option accepts four validation types. Default is flow:
| Type | What it validates |
|---|---|
event | Event structure: name field exists, follows "entity action" format with space, valid data types |
flow (default) | Flow.Json config: schema, references, packages, and cross-step example compatibility |
mapping | Mapping rules: event patterns use "entity action" or wildcard format, rule structures are valid |
contract | Contract structure: entity-action entries map to JSON Schema objects, optional $tagging metadata |
Use --path for entry validation against package schemas (e.g., --path destinations.snowplow).
Step-by-step guide
1. Validate a flow configuration
walkeros validate flow.jsonOutput (valid):
Validating flow...
Validation Results:
✓ All checks passed
Summary: 0 error(s), 0 warning(s)
2. Validate with errors
# Create an invalid event
echo '{"name":"pageview"}' > bad-event.json
walkeros validate bad-event.json --type eventOutput:
Validating event...
Validation Results:
✗ name: Event name must be "entity action" format with space (e.g., "page view")
Summary: 1 error(s), 0 warning(s)
3. Validate with warnings
# Event without consent object
echo '{"name":"page view","data":{"title":"Home"}}' > event.json
walkeros validate event.json --type eventOutput:
Validating event...
Validation Results:
✓ All checks passed
⚠ consent: No consent object provided
→ Consider adding a consent object for GDPR/privacy compliance
Summary: 0 error(s), 1 warning(s)
Options
walkeros validate [input] [options]| Option | Description |
|---|---|
-t, --type <type> | Validation type (default: flow). Also: event, mapping, contract |
--path <path> | Validate a specific entry against its package schema (e.g., destinations.snowplow) |
-f, --flow <name> | Flow name to validate (for multi-flow configs) |
-o, --output <path> | Write result to file |
--strict | Treat warnings as errors (exit code 2) |
--json | Output results as JSON |
-v, --verbose | Show detailed validation information |
-s, --silent | Suppress banner output |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Valid (no errors) |
| 1 | Validation errors found |
| 2 | Warnings found (with --strict) |
| 3 | Input error (file not found, invalid JSON, etc.) |
CI/CD integration
Use --json and exit codes for automated pipelines:
# Fail on any error
walkeros validate flow.json --json || exit 1
# Fail on warnings too (strict mode)
walkeros validate flow.json --strict --json || exit 1JSON output format:
{
"valid": true,
"type": "flow",
"errors": [],
"warnings": [
{
"path": "packages.@walkeros/destination-demo",
"message": "Package \"@walkeros/destination-demo\" has no version specified",
"suggestion": "Consider specifying a version for reproducible builds"
}
],
"details": {
"flowNames": ["default"],
"flowCount": 1,
"packageCount": 2
}
}
Multi-flow validation
Validate a specific flow in a multi-flow configuration:
# Validate only the "production" flow
walkeros validate flow.json --flow productionIf the flow doesn't exist:
Validation Results:
✗ flows: Flow "production" not found. Available: default, staging
Summary: 1 error(s), 0 warning(s)
Event validation details
Event validation checks (see event.ts):
- Name field exists - Required field
- Name is non-empty - Cannot be empty string
- Entity-action format - Must contain space (e.g.,
"page view"not"pageview") - Schema validation - Data types match expected structure
- Best practices - Warns if consent object is missing
# Valid event
walkeros validate '{"name":"product view","data":{"id":"P123"}}' --type event
# Invalid: missing space in name
walkeros validate '{"name":"productview"}' --type eventMapping validation details
Mapping validation checks (see mapping.ts):
- Object structure - Must be an object with event patterns as keys
- Event patterns - Must be
"entity action"format or contain wildcard (*) - Rule structure - Each rule must be an object or array of objects
- Catch-all position - Warns if
*is not the last pattern
# Valid mapping
walkeros validate '{
"page view": {"name": "pageview"},
"*": {"name": "generic_event"}
}' --type mappingContract validation details
Contract validation checks (see contract.ts):
- Root structure - Must be an object (not array or primitive)
$taggingmetadata - If present, must be a non-negative integer- Entity keys - Cannot be empty strings
- Action entries - Each entity must contain an object of action entries
- Schema entries - Each action value must be a JSON Schema object
# Valid contract
walkeros validate '{
"page": {
"view": {
"type": "object",
"properties": {
"title": { "type": "string" }
}
}
}
}' --type contractEntry validation (--path)
Entry validation checks a specific destination, source, or transformer in your flow config against the package's published JSON Schema. The CLI fetches the schema from the package on the CDN and validates the config.settings object using AJV.
# Validate a specific destination entry
walkeros validate flow.json --path destinations.snowplow
# Validate a specific source entry
walkeros validate flow.json --path sources.browser
# Short form (works if the key is unique across sections)
walkeros validate flow.json --path snowplowThe entry validator:
- Resolves the entry from the flow config (first flow is used)
- Reads the
packagefield to identify the npm package - Fetches the package's JSON Schema from the CDN
- Validates the entry's
config.settingsagainst the schema
Auth commands
The auth command group manages authentication with the walkerOS cloud service. Authentication is required for cloud commands (projects, flows, deploy).
Login
Log in to walkerOS via an OAuth browser flow. The CLI requests a device code, opens your browser for authorization, and polls for the resulting token.
walkeros auth loginOutput:
! Your one-time code: ABCD-1234
Authorize here: https://app.walkeros.io/auth/device?code=ABCD-1234
Opening browser...
Waiting for authorization... (press Ctrl+C to cancel)
✓ Logged in as user@example.com
Token stored in ~/.config/walkeros/config.json
The token is stored in ~/.config/walkeros/config.json with 0600 permissions. You can also set the WALKEROS_TOKEN environment variable instead of using auth login.
| Option | Description |
|---|---|
--url <url> | Custom app URL (default: https://app.walkeros.io) |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
Logout
Remove stored credentials from disk.
walkeros auth logout| Option | Description |
|---|---|
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
Whoami
Show the current authenticated user's identity, including email, user ID, and project ID (if the token is project-scoped).
walkeros auth whoamiOutput:
user@example.com
User: usr_abc123
Project: proj_def456
| Option | Description |
|---|---|
-o, --output <path> | Write result to file |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
Token resolution
The CLI resolves authentication tokens in this order:
WALKEROS_TOKENenvironment variable- Config file (
~/.config/walkeros/config.json, written byauth login) - Not authenticated (cloud commands will fail)
Projects commands
The projects command group manages walkerOS cloud projects. All commands require authentication (see Auth commands).
List projects
walkeros projects list| Option | Description |
|---|---|
--cursor <c> | Resume from a pagination cursor returned by a previous list call |
--limit <n> | Maximum number of projects to return |
Get project details
# Get by explicit ID
walkeros projects get proj_abc123
# Uses WALKEROS_PROJECT_ID if omitted
walkeros projects getCreate a project
walkeros projects create "My Analytics Project"Update a project
walkeros projects update proj_abc123 --name "New Name"Delete a project
walkeros projects delete proj_abc123Common options
All projects subcommands support:
| Option | Description |
|---|---|
-o, --output <path> | Write result to file |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
Flows commands
The flows command group manages flow configurations within a project. All commands require authentication and a project context (either --project or WALKEROS_PROJECT_ID).
List flows
walkeros flows list| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
--cursor <c> | Resume from a pagination cursor returned by a previous list call |
--limit <n> | Maximum number of flows to return |
--sort <field> | Sort by: name, updated_at, created_at |
--order <dir> | Sort order: asc, desc |
--include-deleted | Include soft-deleted flows |
Get a flow
Retrieves a flow with its full Flow.Json content.
walkeros flows get cfg_abc123| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
Create a flow
# With inline JSON
walkeros flows create "My Flow" --content '{"version":4,"flows":{"default":{"config":{"platform":"server"}}}}'
# From a file via stdin
cat flow.json | walkeros flows create "My Flow"| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
-c, --content <json> | Flow.Json string or file path |
Update a flow
# Update name only
walkeros flows update cfg_abc123 --name "Updated Flow"
# Update content
walkeros flows update cfg_abc123 --content '{"version":4,"flows":{"default":{"config":{"platform":"server"}}}}'| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
--name <name> | New flow name |
-c, --content <json> | New Flow.Config JSON string or file path |
Delete a flow
Soft-deletes a flow configuration.
walkeros flows delete cfg_abc123Duplicate a flow
Creates a copy of an existing flow configuration.
walkeros flows duplicate cfg_abc123 --name "Flow Copy"| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
--name <name> | Name for the copy (defaults to "Copy of ...") |
Common options
All flows subcommands support:
| Option | Description |
|---|---|
-o, --output <path> | Write result to file |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
Deploy commands
The deploy command group handles deploying flows to the walkerOS cloud or managing self-hosted deployments with heartbeat registration. All commands require authentication.
deploy create
Create a new deployment. The CLI infers the deployment type (web or server) from the flow configuration.
# From a local config file
walkeros deploy create flow.json
# From a remote flow ID
walkeros deploy create cfg_abc123
# With a specific flow name (multi-config flows)
walkeros deploy create flow.json --flow productionOn success, the CLI displays the deployment ID, slug, and type. It also shows example commands for running the deployment locally or via Docker. The create response does not include a deploy token: deploy tokens are minted separately, so the Docker instructions tell you to create one in the app (Settings, Self-hosted deploy token) and set it as WALKEROS_DEPLOY_TOKEN.
| Option | Description |
|---|---|
--label <string> | Human-readable label for the deployment |
-f, --flow <name> | Flow name for multi-flow configs |
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
-o, --output <path> | Write result to file |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
deploy start
Deploy a remote flow to walkerOS cloud infrastructure. Auto-detects whether to use web (script hosting) or server (container) deployment based on the flow content. Streams deployment progress via SSE.
# Deploy a flow
walkeros deploy start cfg_abc123
# Deploy a specific config in a multi-config flow
walkeros deploy start cfg_abc123 --flow production
# Deploy without waiting for completion
walkeros deploy start cfg_abc123 --no-waitOutput (web deployment):
Building bundle...
Publishing to web...
✓ Published: https://cdn.walkeros.io/proj_xxx/walker.js
Output (server deployment):
Building bundle...
Deploying container...
Starting container...
✓ Active: https://collect-abc123.walkeros.io
| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
-f, --flow <name> | Flow name for multi-config flows |
--no-wait | Return immediately after triggering (do not stream progress) |
--timeout <seconds> | Override the client-side wait budget (defaults to 12 minutes, which covers the server's full deploy budget) |
-o, --output <path> | Write result to file |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
By default deploy start streams progress until the deploy completes. The
client-side wait budget defaults to 12 minutes so a slow but healthy long
deploy is never aborted early and misread as a failure in CI; --timeout
overrides it. Each invocation sends a fresh idempotency key, so retrying after
a failed attempt starts a new deploy instead of replaying the previous result.
When a deploy fails, the CLI prints a stable, machine-readable error.code
alongside the message so CI can branch on the code without matching prose. A
rate-limited trigger (429) is reported as retryable with the Retry-After
hint; under --wait the CLI honors one bounded retry automatically.
deploy list
List all deployments in a project.
walkeros deploy list
# Filter by type
walkeros deploy list --type server
# Filter by status
walkeros deploy list --status active| Option | Description |
|---|---|
--project <id> | Project ID (defaults to WALKEROS_PROJECT_ID) |
--cursor <c> | Resume from a pagination cursor returned by a previous list call |
--limit <n> | Maximum number of deployments to return |
--type <type> | Filter by type: web, server |
--status <status> | Filter by status |
deploy status
Get deployment details by ID or slug.
walkeros deploy status dep_abc123
# Or by slug
walkeros deploy status my-collector| Option | Description |
|---|---|
--project <id> | Project ID |
deploy delete
Delete a deployment by ID or slug.
walkeros deploy delete dep_abc123| Option | Description |
|---|---|
--project <id> | Project ID |
--json | Output as JSON |
Common options
All deploy subcommands support:
| Option | Description |
|---|---|
-o, --output <path> | Write result to file |
--json | Output as JSON |
-v, --verbose | Verbose output |
-s, --silent | Suppress output |
Previews command
The previews command group manages preview bundles — short-lived flow bundles
used to test configuration changes on a real production site before deploying.
Each preview gets a short token; visiting any page of your site with
?elbPreview={token} activates preview mode for that browser (7-day cookie).
All commands require authentication and a project (set via WALKEROS_PROJECT_ID
or --project).
previews list
List all previews for a flow.
walkeros previews list <flowId> [--project <projectId>]| Option | Description |
|---|---|
--project <id> | Project ID (overrides default) |
previews get
Get details for a single preview.
walkeros previews get <flowId> <previewId> [--project <projectId>]| Option | Description |
|---|---|
--project <id> | Project ID (overrides default) |
previews create
Create a preview bundle for a specific flow settings entry.
walkeros previews create <flowId> [options]| Option | Description |
|---|---|
-f, --flow <name> | Flow settings name (resolved to an ID) |
-s, --settings-id <id> | Flow settings ID (alternative to --flow) |
-u, --url <siteUrl> | Your site URL; prints a ready-to-open activation URL on stdout |
--project <id> | Project ID (overrides default) |
Without --url, the CLI prints the activation fragment (?elbPreview=...) to
stdout — append it to any URL on your site to activate preview mode. With
--url, it prints the full {siteUrl}?elbPreview={token} URL, plus a
deactivation URL on stderr. Most modern terminals make the URL clickable.
You must provide either --flow or --settings-id to pick which flow settings
the preview should bundle.
previews delete
Delete a preview. Removes both the DB row and the S3 bundle immediately; the
production walker on visitors' browsers self-heals on the next page load by
clearing the elbPreview cookie and loading the production flow.
walkeros previews delete <flowId> <previewId> [options]| Option | Description |
|---|---|
-y, --yes | Skip confirmation (required to run non-interactively) |
--project <id> | Project ID (overrides default) |
Example
# Create a preview for the `demo` flow settings with a ready-to-open URL
walkeros previews create flow_abc123 \
--flow demo \
--url https://example.com
# List previews for a flow
walkeros previews list flow_abc123
# Delete when you're done
walkeros previews delete flow_abc123 prv_xyz456 --yesRun command
The run command starts an HTTP server that accepts events and processes them through your flow.
Use Case
You need an HTTP endpoint to:
- Receive events from browser clients, mobile apps, or server-side sources
- Process events through your collector and destinations
- Test the full event pipeline locally before deploying to production
This is similar to running a Segment or Jitsu collection endpoint.
Basic Usage
walkeros run flow.json --port 8080Step-by-Step Guide
1. Create a collection flow
Create collect.json:
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/server-source-express": {},
"@walkeros/destination-demo": {}
}
}
},
"sources": {
"http": {
"package": "@walkeros/server-source-express",
"config": {
"settings": {
"path": "/collect",
"port": 8080,
"cors": true
}
}
}
},
"destinations": {
"console": {
"package": "@walkeros/destination-demo",
"config": {
"settings": {
"name": "Event Collector",
"values": ["name", "data", "user.id", "timestamp"]
}
}
}
},
"collector": {
"run": true,
"globals": {
"environment": "development"
}
}
}
}
}2. Start the collector
walkeros run flow.jsonOutput:
📦 Bundling flow...
✓ Bundle ready
🚀 Starting collection server...
✓ Server running on http://localhost:8080
✓ Endpoint: POST http://localhost:8080/collect
✓ Health check: GET http://localhost:8080/health
3. Send test events
Open a new terminal and send events:
# Page view event
curl -X POST http://localhost:8080/collect \
-H "Content-Type: application/json" \
-d '{
"name": "page view",
"data": {
"title": "Home Page",
"path": "/"
},
"user": {
"id": "user123"
}
}'
# Product view event
curl -X POST http://localhost:8080/collect \
-H "Content-Type: application/json" \
-d '{
"name": "product view",
"data": {
"id": "P123",
"name": "Laptop",
"price": 999
}
}'4. See events in console
The collector terminal shows:
[Event Collector] page view
data: {"title":"Home Page","path":"/"}
user.id: user123
timestamp: 1701234567890
[Event Collector] product view
data: {"id":"P123","name":"Laptop","price":999}
timestamp: 1701234567891
Options
walkeros run <config|bundle|archive> [options]The input can be a flow config, a pre-built bundle, or a .tar.gz/.tgz flow archive (local file or URL).
| Option | Description |
|---|---|
-p, --port <number> | Server port (default: 8080) |
-h, --host <address> | Host address (default: 0.0.0.0) |
--deploy <id-or-slug> | Deployment ID or slug (enables heartbeat to walkerOS cloud) |
--project <id> | Project ID (used with --deploy) |
--url <url> | Public URL of this server (used with --deploy) |
--health-endpoint <path> | Health check path (default: /health) |
--heartbeat-interval <seconds> | Heartbeat interval in seconds (default: 60) |
--json | Output as JSON |
-v, --verbose | Detailed logging |
-s, --silent | Suppress output |
Heartbeat registration
When --deploy is provided, the collector registers itself with the walkerOS cloud via periodic heartbeats. This makes the running instance visible in the project dashboard and enables remote management.
walkeros run flow.json \
--deploy dep_abc123 \
--project proj_def456 \
--url https://collect.example.com \
--heartbeat-interval 30The heartbeat sends instance ID, uptime, CLI version, and mode. The server can respond with update (triggering a bundle refresh) or stop (graceful shutdown).
Running Pre-Built Bundles
You can also run pre-built bundles directly:
# First, bundle
walkeros bundle collect.json
# Then run the bundle
walkeros run dist/flow.mjs --port 8080Running flow archives
run also accepts a .tar.gz/.tgz flow archive, either a local file or a URL. The CLI fetches or reads the gzip, extracts the bundle and its sibling node_modules/, and runs the entry. This lets server flows whose step packages are external resolve those packages at runtime from the extracted node_modules/.
# Bundle to an archive
walkeros bundle collect.json -o flow.tar.gz
# Run a local archive
walkeros run flow.tar.gz --port 8080
# Run an archive from a URL
walkeros run https://example.com/flow.tar.gzComplete example: Web → Server flow
This example demonstrates a complete analytics pipeline:
- Browser events captured by web flow
- Sent to server collection endpoint
- Logged to console (swap for BigQuery in production)
1. Create Server Collection Flow
Create server-collect.json:
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/server-source-express": {},
"@walkeros/destination-demo": {}
}
}
},
"sources": {
"http": {
"package": "@walkeros/server-source-express",
"config": {
"settings": { "path": "/collect", "port": 8080, "cors": true }
}
}
},
"destinations": {
"console": {
"package": "@walkeros/destination-demo",
"config": {
"settings": { "name": "Server Logger" }
}
}
},
"collector": { "run": true }
}
}
}2. Create Web Tracking Flow
Create web-track.json:
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "web",
"bundle": {
"packages": {
"@walkeros/web-source-browser": {},
"@walkeros/web-destination-api": {}
}
}
},
"sources": {
"browser": {
"package": "@walkeros/web-source-browser",
"config": {
"settings": { "pageview": true, "elb": "track" }
}
}
},
"destinations": {
"api": {
"package": "@walkeros/web-destination-api",
"config": {
"settings": {
"url": "http://localhost:8080/collect",
"method": "POST"
}
}
}
},
"collector": { "run": true }
}
}
}3. Start Collection Server
Terminal 1:
walkeros run server-collect.json4. Start Web Server
Terminal 2:
walkeros run web-track.json --port 30005. Test in Browser
Create demo.html:
<!DOCTYPE html>
<html>
<head>
<script src="http://localhost:3000/walker.js"></script>
</head>
<body>
<h1 data-elb="promotion" data-elb-promotion="name:Get Started">
Welcome to walkerOS
</h1>
<button data-elbaction="click:cta">Start Tracking</button>
<script>
// Manual tracking
track('custom event', { action: 'demo', value: 42 });
</script>
</body>
</html>Open in browser. Terminal 1 shows:
[Server Logger] page view
[Server Logger] promotion view
[Server Logger] promotion cta
[Server Logger] custom event
Cache command
The cache command manages the CLI's package and build caches.
Use Case
The CLI caches downloaded npm packages and compiled builds to speed up repeated operations. You may need to:
- Clear stale cached packages when debugging version issues
- Free up disk space by removing old cached builds
- View cache statistics to understand cache usage
How Caching Works
Package Cache (.tmp/cache/packages/):
- Mutable versions (
latest,^,~) are re-checked daily - Exact versions (
0.4.1) are cached indefinitely - Saves network time on repeated builds
Build Cache (.tmp/cache/builds/):
- Caches compiled bundles based on flow.json content + date
- Identical configs reuse cached builds within the same day
- Dramatically speeds up repeated builds (~100x faster)
Basic Usage
# View cache statistics
walkeros cache info
# Clear all caches
walkeros cache clearCommands
View cache info:
walkeros cache infoOutput:
Cache directory: .tmp/cache
Cached packages: 12
Cached builds: 5
Clear all caches:
walkeros cache clearClear only package cache:
walkeros cache clear --packagesClear only build cache:
walkeros cache clear --buildsBypassing Cache
To skip the cache for a single build operation:
walkeros bundle flow.json --no-cacheThis downloads fresh packages and rebuilds without using or updating the cache.
Options
| Option | Description |
|---|---|
--packages | Clear only the package cache |
--builds | Clear only the build cache |
Global options
These options work with all commands:
walkeros [command] [options]| Option | Description |
|---|---|
--verbose | Show detailed logs |
--silent | Suppress output |
--json | Output as JSON (for CI/CD) |
--help | Show help for command |
--version | Show CLI version |
Environment variables
| Variable | Purpose |
|---|---|
WALKEROS_TOKEN | API token for cloud commands (overrides auth login config) |
WALKEROS_PROJECT_ID | Default project ID for projects, flows, and deploy commands |
WALKEROS_APP_URL | Base URL override (default: https://app.walkeros.io) |
WALKEROS_DEPLOY_TOKEN | Deploy token for container heartbeat authentication |
WALKEROS_CLIENT_TYPE | Override client identity sent to the app. Defaults to cli; set to runner for long-lived flow runners. Used by the runtime image. |
WALKEROS_OBSERVE_LEVEL | Baseline telemetry level for walkeros run (off, standard, or trace). Invalid values are warned about and ignored. |
WALKEROS_CONFIG_FROZEN | Set to 1 or true to make walkeros run serve the bundle as an immutable snapshot: secrets are still injected at boot, but config hot-swap and heartbeat are disabled. |
API version compatibility
Official clients (CLI, MCP, runner image) send three headers on every request to the walkerOS app so the server can tell them apart and enforce minimum versions per endpoint:
User-Agent: e.g.walkeros-cli/1.4.0 (node/18.19.0; linux)X-WalkerOS-Client:cli,mcp, orrunnerX-WalkerOS-Client-Version: the installed package version
If you call an endpoint that has been updated in a way that requires a newer
client, the app responds with 426 Upgrade Required. The CLI prints the
required minimum version and the upgrade command, then exits with code 2:
Error: This walkerOS app endpoint requires @walkeros/cli >= 1.5.0
(you have 1.4.0). Upgrade with: npm install -g @walkeros/cli@latest
See https://walkeros.io/docs/upgrading for details.
The MCP server surfaces the same information in tool error responses so AI assistants can tell the user to upgrade. See Upgrading for the full version-negotiation rules.
Set WALKEROS_CLIENT_TYPE=runner to identify the CLI binary as a long-lived
flow runner instead of an interactive CLI session. The official runner Docker
image sets this automatically.
CI/CD integration
GitHub Actions
name: Build Flows
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install CLI
run: npm install -g @walkeros/cli
- name: Bundle flows
run: walkeros bundle flow.json --all --stats --json > stats.json
- name: Upload bundles
uses: actions/upload-artifact@v3
with:
name: flows
path: dist/Docker Build
The canonical multi-stage Dockerfile installs the CLI in the build stage, bundles the flow into a dist/ directory, then copies the directory into the runtime image. You do not need to declare step packages in package.json; pacote installs them transparently from flow.json.
FROM node:22.23.0-alpine AS builder
WORKDIR /build
RUN npm init -y && npm install --save-dev @walkeros/cli
COPY flow.json ./
RUN npx walkeros bundle flow.json -o dist/
FROM walkeros/flow:4
WORKDIR /app/flow
COPY --from=builder /build/dist/ ./
ENV PORT=8080
EXPOSE 8080Troubleshooting
Package Download Issues
If packages fail to download:
# Clear cache and retry
walkeros bundle flow.json --no-cache
# Check npm registry access
npm pingBuild Issues
If you encounter build issues:
# Clear cache and retry
walkeros cache clear
# Retry with verbose output
walkeros bundle flow.json --verbosePort Already in Use
If the port is already in use:
# Use a different port
walkeros run flow.json --port 8081
# Or kill the process using the port
lsof -ti:8080 | xargs killAuthentication Issues
If cloud commands fail with authentication errors:
# Check current identity
walkeros auth whoami
# Re-authenticate
walkeros auth login
# Or set token directly
export WALKEROS_TOKEN=sk-walkeros-xxxnft cannot trace a runtime asset
If a runtime asset is missing in dist/node_modules/ (typically because the dep loads it via a dynamically constructed path), declare it explicitly under the flow's config.bundle.traceInclude. Paths and globs both work, resolved against the install root:
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": { "@walkeros/server-destination-gcp": {} },
"traceInclude": [
"node_modules/some-pkg/data/*.json"
]
}
}
}
}Caching pacote downloads in CI
The bundler caches downloads under process.env.NPM_CACHE_DIR (default
<tmpDir>/cache/npm). On CI, persist that path with actions/cache:
- uses: actions/cache@v4
with:
path: .walkeros-cache/npm
key: walkeros-${{ hashFiles('**/flow.json') }}
- run: WALKEROS_TMP_DIR=.walkeros-cache npx walkeros bundle flow.json -o dist/Bundle output is large
dist/node_modules/ for a server flow with the GCP destination typically holds 30-50MB across 10k+ files (grpc, protobufjs, etc.). Recommendations:
- Use
.dockerignoreto exclude irrelevant build output from non-bundle contexts. - Prefer
COPY --from=builder /build/dist/ /app/flow/over file-by-file in your Dockerfile. - Expect ~30s artifact upload time on slow CI.
Next steps
- Flow Configuration - Learn about flow config structure
- Docker Deployment - Deploy flows to production
- Runner - Self-hosted runner with config polling and hot-swap
- MCP Server - Use CLI tools from AI assistants
- Sources - Explore event sources
- Destinations - Configure analytics tools
- Mapping - Transform events for destinations
See Also
Using Integrated mode instead? The CLI uses JSON configuration (Bundled mode). If you prefer TypeScript and want the collector built into your application, see Integrated Mode and the Collector documentation.
Both approaches use the same underlying architecture. The difference is how you configure and deploy.