From walkeros
Guides walkerOS mapping for transforming events from source→collector or collector→destination, configuring data/map/loop/set/condition/policy, and $code syntax in JSON configs.
npx claudepluginhub elbwalker/walkerosThis skill uses the workspace's default tool permissions.
Mapping transforms data at multiple points in the walkerOS flow:
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Mapping transforms data at multiple points in the walkerOS flow:
Core principle: Mapping is the universal transformation layer. Same strategies work everywhere in the flow.
See packages/core/src/mapping.ts for implementation.
| Function | Purpose |
|---|---|
getMappingEvent(event, rules) | Find mapping rule for an event |
getMappingValue(value, data, options) | Transform a value using mapping config |
processEventMapping(event, config, collector) | Unified processing for sources/destinations |
1. Apply config.policy (modifies event)
2. Find matching rule via getMappingEvent()
3. Apply rule.policy (modifies event)
4. Transform config.data (global)
5. Check rule.ignore (short-circuits if true)
5b. Read rule.skip (informational — destination honors it)
6. Override event.name if rule.name
7. Transform rule.data (event-specific)
interface Config {
consent?: Consent; // Required consent for ALL events
data?: Value; // Global data transformation
policy?: Policy; // Pre-processing for ALL events
mapping?: Rules; // Event-specific rules
}
interface Rule {
name?: string; // Override event name
data?: Value; // Event-specific data transformation
ignore?: boolean; // Skip this event entirely (no processing, no push)
skip?: boolean; // Process settings side effects, skip destination default push
policy?: Policy; // Event-specific pre-processing
condition?: Function; // Match condition (for arrays)
consent?: Consent; // Required consent for this rule
settings?: unknown; // Custom event configuration
batch?: number; // Batch size for grouping
}
Both flags control rule behavior but have different semantics:
ignore: true — the rule matched but nothing happens. No data transform,
no destination call, no side effects. Use for suppression.skip: true — the rule matched and the destination push() is called.
settings.identify, settings.revenue, settings.group, etc. still run.
Only the destination's default forwarding call (e.g. track(), capture(),
event()) is suppressed. Use for "identify without an event" style flows.If both flags are set on the same rule, ignore wins.
Common use case: a user login event that should call amplitude.identify()
but should not create a separate track("user login") event in Amplitude.
interface ValueConfig {
key?: string; // Extract from path
value?: Primitive; // Static fallback value
fn?: Function; // Custom transformation
map?: Record; // Object transformation
loop?: [path, config]; // Array transformation
set?: Value[]; // Create array from values
condition?: Function; // Conditional extraction
consent?: Consent; // Consent-gated extraction
validate?: Function; // Value validation
}
Match events to transformation rules by entity and action.
const mapping = {
// Exact match: "product view" → view_item
product: {
view: { name: 'view_item' },
add: { name: 'add_to_cart' },
},
// Wildcard action: "foo *" → foo_interaction
foo: {
'*': { name: 'foo_interaction' },
},
// Wildcard entity: "* click" → generic_click
'*': {
click: { name: 'generic_click' },
},
};
Array of rules - first matching condition wins:
order: {
complete: [
{
condition: (event) => event.data?.value > 100,
name: 'high_value_purchase',
},
{ name: 'purchase' }, // Fallback (no condition)
],
}
JSON with $code:
{
"order": {
"complete": [
{
"condition": "$code:(event) => event.data?.value > 100",
"name": "high_value_purchase"
},
{ "name": "purchase" }
]
}
}
Common patterns shown below. For detailed examples of all 12 strategies, see value-strategies.md.
// Key extraction (string shorthand)
'data.price' // → event.data.price
// Key with fallback
{ key: 'data.currency', value: 'USD' } // Use USD if missing
// Static value
{ value: 'USD' }
// Function transform
{ fn: (event) => event.data.price * 100 } // Convert to cents
// Object map
{ map: { item_id: 'data.id', item_name: 'data.name' } }
// Array loop
{ loop: ['nested', { map: { item_id: 'data.id' } }] }
// Loop with "this" (single item as array)
{ loop: ['this', { map: { item_id: 'data.id' } }] }
// Set (create array)
{ set: ['data.id'] } // → ["SKU-123"]
// Fallback array (first success wins)
[{ key: 'data.sku' }, { key: 'data.id' }, { value: 'unknown' }]
// Consent-gated
{ key: 'user.email', consent: { marketing: true } }
// Validate
{ key: 'data.email', validate: (v) => v.includes('@') }
Policy modifies the event BEFORE mapping rules are applied. Use for:
Applied to ALL events:
config: {
policy: {
'user_data.external_id': 'user.id',
'custom_data.server_processed': { value: true },
},
mapping: { /* ... */ }
}
Applied after config policy, only for specific event:
mapping: {
order: {
complete: {
policy: {
'enriched.total_cents': {
fn: (event) => Math.round(event.data.total * 100)
}
},
name: 'purchase',
data: { /* ... */ }
}
}
}
{
"policy": {
"user_data.em": {
"key": "user.email",
"consent": { "marketing": true }
}
}
}
mapping: {
test: { '*': { ignore: true } }, // Ignore all test events
}
mapping: {
'*': {
'*': {
batch: 5, // Send after 5 events
}
}
}
mapping: {
order: {
complete: {
name: 'purchase',
settings: { priority: 'high', retryCount: 3 }
}
}
}
The $code: prefix enables JavaScript functions in JSON configurations:
{
"fn": "$code:(event) => event.data.price * 100",
"condition": "$code:(event) => event.data?.value > 100",
"validate": "$code:(value) => value > 0"
}
Important: The $code: prefix is processed by the CLI bundler. It converts
JSON strings to actual JavaScript functions during build.
| Context | Signature |
|---|---|
fn | (value, mapping, options) => result |
condition (value) | (value, mapping, collector) => boolean |
condition (rule) | (event) => boolean |
validate | (value) => boolean |
loop condition | (item) => boolean |
| Pattern | Result |
|---|---|
"data.id" | Extract event.data.id |
{ value: "USD" } | Static "USD" |
{ key: "x", value: "y" } | Extract x, fallback to "y" |
{ fn: (e) => ... } | Custom function |
{ map: {...} } | Object transformation |
{ loop: ["nested", {...}] } | Array transformation |
{ loop: ["this", {...}] } | Single-item as array |
{ set: ["a", "b"] } | Create array [valA, valB] |
[m1, m2, m3] | Fallback chain |
{ consent: {...} } | Consent-gated |
{ condition: fn } | Conditional |
{ validate: fn } | Validated |
| Feature | Purpose |
|---|---|
name | Override event name |
data | Transform event data |
ignore | Skip event entirely (no processing, no push) |
skip | Run settings side effects, skip default forwarding |
policy | Pre-process event |
condition | Match condition (arrays) |
consent | Required consent |
settings | Custom configuration |
batch | Batch size |
| Feature | Purpose |
|---|---|
consent | Required consent (all events) |
data | Global data transformation |
policy | Global pre-processing |
mapping | Event-specific rules |
For full destination configuration examples (TypeScript + JSON), see complete-examples.md.
| Location | Purpose |
|---|---|
| Source config | Transform raw input → walkerOS events |
| Destination config | Transform walkerOS events → vendor format |
packages/core/src/mapping.ts | Core mapping functions |
packages/core/src/types/mapping.ts | Type definitions |
packages/cli/examples/flow-complete.json | Comprehensive example (53 features) |
Source Files:
Detailed References:
Examples: