walkerOS v4.0.0
Changes
Remove dead bundleRemote() and add OpenAPI drift detection.
Breaking changes:
- Removed
bundleRemote()export from@walkeros/cli. The corresponding
/api/bundleendpoint was removed from the walkerOS app on 2026-04-08, so
this function had been silently broken in production for ~3 weeks. Local
bundling viabundle()is unaffected. - Removed
remoteandcontentoptions from the MCPflow_bundletool. The
tool now bundles locally only.
New: - Added
npm run -w @walkeros/cli validate:openapi-specscript that diffs the
checked-inpackages/cli/openapi/spec.jsonagainst the live app's OpenAPI
document. Detects drift between the walkerOS-side type contract and the actual
API. Wired into PR-time CI, daily cron, and a pre-commit lint-staged hook. All
layers are gated on aWALKEROS_APP_URLsecret and skip silently when unset,
so the change ships safely without configuration. To activate: set
WALKEROS_APP_URLin repo secrets pointing to a deployed app instance.
Fix walkeros push deadlock for web flows whose destinations await real timers
during init.
Previously, async-drain timer interception captured every setTimeout into a
pending map and only fired them via a post-fn flush. If a destination's init
awaited one of those captured timers (e.g.,
@walkeros/web-destination-amplitude's engagement plugin awaits a 10s
setTimeout to give up on a CDN script load), init never resolved,
await collector.push deadlocked, and Node exited with
Detected unsettled top-level await (exit 13).
A drain pump now runs alongside fn(flowModule) for non---simulate runs: each
tick fires every captured non-cleared timer using a real setImmediate
reference. Timers fire in delay-ascending order, intervals re-register, callback
errors are reported via console.warn. Bounded by max-iterations (1000) and
wall-clock (30s) caps.
--simulate <step> continues to use the post-fn flush path so snapshot
ordering remains stable.
Behavior change (edge case): a destination using setTimeout for retry backoff
under walkeros push (real, non-simulate) now sees its timer fire instantly.
This was already the documented contract for --simulate <step> snapshots; it
now extends to real push for consistency.
Validate device-code and token responses from the auth server with Zod schemas
at the trust boundary in login/index.ts. Malformed responses now surface as
structured errors instead of being trusted into config writes or browser
launches. Replaces the hand-rolled type guards for Items 1 and 3 of the cli-auth
feedback review. No public API change.
Explicit opt-in anonymous usage telemetry for CLI and MCP. Telemetry is off by
default; users opt in with walkeros telemetry enable and out with
walkeros telemetry disable. No persistent identifier is written before opt-in.
No ingest endpoint ships in this release: opting in records consent locally;
emission begins when a managed endpoint is released. The data contract lives at
packages/cli/src/telemetry/flow.json.
Add flowId filter to CLI listDeployments and redesign the MCP
deploy_manage tool around it.
CLI (@walkeros/cli):
listDeployments({ projectId?, type?, status?, flowId? })now forwards
flowIdas a query parameter toGET /api/projects/{id}/deployments.- New helper
deleteDeploymentByFlowId({ projectId?, flowId, slug? })deletes
the active deployment for a flow, surfacing aDeploymentAmbiguityError(code
MULTIPLE_DEPLOYMENTS, with adetails[]list) when a flow has more than one
active deployment and no slug was supplied.
MCP (@walkeros/mcp) breaking: deploy_manage'sget,delete, andlistactions now take
{ projectId?, flowId, slug? }. The oldidparameter has been removed.
flowIdis required forget/deleteand optional forlist. Soft-deleted
deployments are always excluded.- When a flow has multiple active deployments and
slugis not provided,
get/deletereturn aMULTIPLE_DEPLOYMENTSerror with adetails[]list
of{ slug, type, status, updatedAt }entries so the caller can pick one.
deployaction is unchanged.
Event model v4: breaking changes to the Event, Source, and Entity shapes.
event.idis now a W3C span_id (16 lowercase hex chars), generated by the
collector. Reference: W3C Trace Context (W3C Recommendation, January 2020).event.version,event.group,event.countare removed.source.typeis now the source kind (e.g.browser,gtag,mcp,cli).
Newsource.platformholds the runtime (web|server|app| ...).source.idandsource.previous_idare removed.- Browser source now sets
source.urlandsource.referrer. - MCP source sets
source.toolper emission. CLI source setssource.command. Entity.nestedandEntity.contextare now optional. Rootevent.nestedand
event.contextremain required.- Each source self-registers via TypeScript module augmentation of
SourceMap
in@walkeros/core. - App-side coordination (
/workspaces/developer/app) is a follow-up plan, not
part of this release. Telemetry from v4 CLI/MCP will not validate against the
existing app schema until that follow-up ships. Mapping.Rule.skipis renamed toMapping.Rule.silent. Customer flow.json
configs usingskip: truein mapping rules must rename tosilent: true.
Hard cut: no legacy alias, the field is gone.
Add CodeDiff atom and CodeDiffBox molecule — read-only, theme-aware Monaco
DiffEditor wrappers for side-by-side / inline code diff viewing. CodeDiffBox
mirrors CodeBox's API (header, actions, traffic lights, footer) and adds an
opt-in summary strip, split/inline toggle, and copy button. Supports any Monaco
language; walkerOS $var: / $secret: decorations are applied to both sides
automatically.
IntelliSense improvements for flow.json editors:
- Chain references (
next/before) now autocomplete in all forms: scalar,
inline array, multi-line array, and Route[] innernext. Previously only the
scalar form triggered. $store.completions, hover, and validation added. Fed by a new optional
storesfield onIntelliSenseContext; the flow extractor collects store IDs
from the active flow.$env.completions and hover added. OptionalenvNamesinventory on
IntelliSenseContextenables validation; when absent,$env.still gets a
generic hover.$contract.completion now only triggers when the cursor starts a new string
value, matching runtime semantics (whole-string refs only).packagecompletion detection is JSON-path aware — multi-line"package":
values now surface completions.- Variables and definitions are collected at config / flow / step levels with
correct cascade priority (step > flow > config). - Markers validate chain references in all forms via a JSON walk instead of a
scalar-only regex. - Internals now import the shared
REF_*regex constants from@walkeros/core
— single source of truth, no inline duplicates.
PropertyTable — responsive card-view fallback via CSS container queries
(triggered below 420px), graceful empty-state rendering with an optional
emptyMessage prop (default: "No specific properties available."), and improved
column-width handling so the Description column no longer forces horizontal
overflow in narrow containers.
Add Monaco IntelliSense for $flow.X cross-flow references in Code/CodeBox.
Completion offers known sibling flow names from the parsed flow document, hover
describes the resolved target, decorations style matches the other reference
prefixes, and unknown flow names emit a warning marker. Re-export REF_FLOW
from @walkeros/core so consumers can build inline regex tooling without
reaching into the subpath.
Flow v4: type redesign and cross-flow references.
Breaking changes:
- Renamed
Flow.Settings(single-flow shape) toFlow. The newFlow.Settings
is the arbitrary kv-bag insideFlow.Config(matchesDestination.Settings
semantics). - Renamed
Flow.Config(root file shape) toFlow.Json. - Removed
Flow.WebandFlow.Server. Replaced by
config.platform: 'web' | 'server'(a string discriminator). - Renamed
Flow.InlineCodetoFlow.Code. - Renamed
Flow.SourceReference/DestinationReference/
TransformerReference/StoreReferencetoFlow.Source/Destination/
Transformer/Store(Reference suffix dropped). - Renamed
Flow.ContractEntrytoFlow.ContractRule. - Lifted
bundleand platform fields into the per-flowconfigblock. flow.jsonversionbumped from 3 to 4. v3 input is rejected (no compat
shim).
New:$flow.X.Yreference resolves toflows.X.config.Yin the same file. Useful
for linking a web flow's API destination to a server flow's deployed URL
without duplicating values.- Per-flow
Flow.Configblock:{ platform, url, settings, bundle }. walkeros validatewarns on unresolved$flow.X.Y(use--strictto error).
walkeros bundleandwalkeros deployalways error on unresolved refs.- See
docs/migrating/v3-to-v4.mdxon the website for the manual migration
steps. No automated codemod is shipped.
Add flowCanvasResult helper + FlowCanvasToolResult / FlowCanvasPayload /
SuggestionTile types for UI-renderable tool outputs. flow_manage actions
get / create / update now return a kind: 'flow-canvas' payload with
optional suggestion tiles so chat clients can render the flow graph inline.
Split @walkeros/mcp into a library entry (server factory plus ToolClient
abstraction) and a thin stdio binary. The package now exports
createWalkerOSMcpServer, HttpToolClient, createStreamableHttpHandler,
TOOL_DEFINITIONS, and the ToolClient interface so host applications can
mount walkerOS MCP tools over HTTP (e.g. from a Next.js Route Handler) or
consume them directly from non-MCP runtimes (e.g. Vercel AI SDK adapters). The
walkeros-mcp stdio binary is unchanged for end users; importing
@walkeros/mcp programmatically no longer auto-starts stdio.
Tool handlers now wrap user-writable strings (flow/project names, config fields,
validation messages) in <user_data>…</user_data> delimiters so chat consumers
can keep prompt-injection defence-in-depth. Two new utilities are exported:
wrapUserData(s) and redactNestedStrings(obj).
Breaking — @walkeros/core: fetchPackage(name, { baseUrl }) now expects
the host app to expose the v2 /api/packages/[name] endpoint that returns the
merged WalkerOSPackage shape directly (single round-trip, ?expand=all). The
previous two-fetch pattern (?path=package.json + ?path=dist/walkerOS.json)
is removed. Hosts must serve the v2 shape; the offline jsdelivr fallback is
unchanged.
Feature — CLI/MCP/explorer: Outbound walkerOS-aware HTTP clients now
identify themselves to the configured app origin via
X-Walkeros-Client: walkeros-{cli|mcp}/{version}. @walkeros/explorer exports
setPackageTypesBaseUrl(url?) so host apps can proxy .d.ts through their own
origin (used by the walkerOS Tag Manager app to drop the jsdelivr CDN allowance
entirely).
BREAKING: Unified reference syntax: $store:id and $secret:NAME now use
the dot separator: $store.id and $secret.NAME.
The coherent rule across every walkerOS reference is:
.key or path (resolver looks up or walks what follows):literal value or raw-code payload (resolver uses what follows
verbatim)
$var.,$def.,$env.NAME[:default],$contract., and$code:(…)are
unchanged, they already fit the rule.
Every shipped example, publishedwalkerOS.jsonmetadata, doc page, and skill
has been updated. A new canonical reference-syntax guide lives at
/docs/guides/reference-syntax. Regex constants (REF_VAR,REF_DEF,
REF_ENV,REF_CONTRACT,REF_STORE,REF_SECRET,REF_CODE_PREFIX) are
exported from@walkeros/coreimport these instead of hand-rolling regexes.
Upgrade
Search-and-replace across your flow configs:
$store:<id> → $store.<id>
$secret:<NAME> → $secret.<NAME>
Everything else stays the same. Your $var.*, $def.*, $env.*,
$contract.*, and $code:* references need no changes.
JSON Schema exports now include canonical id + title (e.g.
Destination.Config, Logger.Config) — replaces anonymous __schema0 /
object / any labels. Extracts shared LoggerConfigSchema (was inlined 5×).
Removes deprecated schemas/value-config.ts. No TypeScript surface changes.
BREAKING: Unified callback signatures across mapping and on.*
subscriptions.
Every callback in walkerOS now reads (data, context) => result. Sources,
transformers, destinations, and stores already conformed; mapping and on.* join
the family in v4.1.
Mapping callbacks
fn, condition, and validate now share a single shape:
(value, context: Mapping.Context) => result
Mapping.Options is removed. Replaced by Mapping.Context:
interface Context {
event: WalkerOS.DeepPartialEvent;
mapping: Value | Rule;
collector: Collector.Instance; // required
logger: Logger.Instance; // required
consent?: WalkerOS.Consent; // resolved consent
}Rule-level condition is now (event, context) => boolean.
Mapping.Options.props is removed (no production callers).
Mapping upgrade
// before
const fn: Mapping.Fn = (value, mapping, options) => /* … */;
const cond: Mapping.Condition = (value, mapping, collector) => /* … */;
const val: Mapping.Validate = (value) => /* … */;
// after
const fn: Mapping.Fn = (value, context) => /* … */;
const cond: Mapping.Condition = (value, context) => /* … */;
const val: Mapping.Validate = (value, context) => /* … */;In $code: strings (flow.json):
// before
"fn": "$code:(value, mapping, options) => …"
"condition": "$code:(value, mapping, collector) => …"
// after
"fn": "$code:(value, context) => …"
"condition": "$code:(value, context) => …"context.mapping replaces the second positional arg; context.collector,
context.logger, and context.consent are all available.
One-arg callbacks like (value) => value.toUpperCase() continue to work
unchanged.
On.* subscription callbacks
walker.on('consent', …), walker.on('ready', …), etc. now receive
(data, context: On.Context) => void | Promise<void>. The legacy Context
interface, *Config aliases, and Options discriminated union are removed.
interface Context {
collector: Collector.Instance; // required
logger: Logger.Instance; // required
}
type Fn<TData = unknown> = (
data: TData,
context: Context,
) => void | Promise<void>;
type ConsentFn = Fn<WalkerOS.Consent>;
type SessionFn = Fn<Collector.SessionData | undefined>;
type UserFn = Fn<WalkerOS.User>;
type ReadyFn = Fn<void>;
type RunFn = Fn<void>;
type GenericFn = Fn<unknown>;The new On.Subscription alias is the registerable union for
walker.on(action, X).
On.* upgrade
// before
walker.on('consent', { marketing: (collector, consent) => /* … */ });
walker.on('ready', (collector) => /* … */);
walker.on('session', (collector, session) => /* … */);
// after
walker.on('consent', { marketing: (consent, ctx) => /* … */ });
walker.on('ready', (_, ctx) => /* … */);
walker.on('session', (session, ctx) => /* … */);ctx.collector replaces the positional first arg; ctx.logger is also
available.
Why both at once
Both refactors follow the same (data, context) pattern. Shipping them in one
release means consumers do one search-and-replace pass instead of two, and the
codebase reaches full callback-signature consistency in v4.1.
Published Packages
- @walkeros/cli
- @walkeros/collector
- @walkeros/core
- @walkeros/destination-demo
- @walkeros/explorer
- @walkeros/mcp
- @walkeros/server-destination-amplitude
- @walkeros/server-destination-api
- @walkeros/server-destination-aws
- @walkeros/server-destination-bing
- @walkeros/server-destination-criteo
- @walkeros/server-destination-customerio
- @walkeros/server-destination-datamanager
- @walkeros/server-destination-file
- @walkeros/server-destination-gcp
- @walkeros/server-destination-hubspot
- @walkeros/server-destination-kafka
- @walkeros/server-destination-klaviyo
- @walkeros/server-destination-linkedin
- @walkeros/server-destination-meta
- @walkeros/server-destination-mixpanel
- @walkeros/server-destination-mparticle
- @walkeros/server-destination-pinterest
- @walkeros/server-destination-posthog
- @walkeros/server-destination-reddit
- @walkeros/server-destination-redis
- @walkeros/server-destination-rudderstack
- @walkeros/server-destination-segment
- @walkeros/server-destination-slack
- @walkeros/server-destination-snapchat
- @walkeros/server-destination-sqlite
- @walkeros/server-destination-tiktok
- @walkeros/server-destination-twitter
- @walkeros/server-source-aws
- @walkeros/server-source-express
- @walkeros/server-source-fetch
- @walkeros/server-source-gcp
- @walkeros/source-demo
- @walkeros/transformer-validator
- @walkeros/web-core
- @walkeros/web-destination-amplitude
- @walkeros/web-destination-clarity
- @walkeros/web-destination-fullstory
- @walkeros/web-destination-gtag
- @walkeros/web-destination-heap
- @walkeros/web-destination-meta
- @walkeros/web-destination-mixpanel
- @walkeros/web-destination-optimizely
- @walkeros/web-destination-pinterest
- @walkeros/web-destination-piwikpro
- @walkeros/web-destination-plausible
- @walkeros/web-destination-segment
- @walkeros/web-destination-snowplow
- @walkeros/web-source-browser
- @walkeros/web-source-cmp-cookiefirst
- @walkeros/web-source-cmp-cookiepro
- @walkeros/web-source-cmp-usercentrics
- @walkeros/web-source-datalayer
- @walkeros/web-source-session
- walkeros