walkeros-create-cmp-so…
A CMP source is a specialized walkerOS source that listens to a consent management platform's events and translates consent…
Destinations receive processed events from the collector and deliver them to third-party tools (analytics, marketing, data warehouses).
$ npx -y skills add elbwalker/walkerOS --skill walkeros-understanding-destinations --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/walkeros-understanding-destinationsContext preview
The summary Claude sees to decide when to auto-load this skill.
Destinations receive processed events from the collector and deliver them to third-party tools (analytics, marketing, data warehouses).
name: walkeros-understanding-destinations description: Use when working with walkerOS destinations, understanding the destination interface, or learning about env pattern and configuration. Covers interface, lifecycle, env mocking, and paths.
Destinations receive processed events from the collector and deliver them to third-party tools (analytics, marketing, data warehouses).
**Core principle:** Destinations transform and deliver. They don't capture or process—that's sources and collector.
See [packages/core/src/types/destination.ts](../../packages/core/src/types/destination.ts) for canonical interface.
| Method | Purpose | Required | | --------------------------- | -------------------------- | ------------ | | `init(context)` | Load scripts, authenticate | Optional | | `push(event, context)` | Transform and send event | **Required** | | `pushBatch(batch, context)` | Batch processing | Optional | | `destroy(context)` | Cleanup on shutdown | Optional | | `config` | Settings, mapping, consent | **Required** |
`destroy?: DestroyFn` — Optional cleanup method. Called during `command('shutdown')`. Use to close DB connections, flush buffers, or release SDK clients. Receives `{ id, config, env, logger }`.
Destinations use dependency injection via `env` for external APIs. This enables testing without mocking.
// Destination defines its env type
export interface Env extends DestinationWeb.Env {
window: {
gtag: Gtag.Gtag;
dataLayer: unknown[];
};
}
// Destination uses env, not globals
async function push(event, context) {
const { env } = context;
env.window.gtag('event', mappedName, mappedData);
}**REQUIRED SKILL:** See [testing-strategy](../walkeros-testing-strategy/SKILL.md) for full testing patterns.
import { mockEnv } from '@walkeros/core';
import { examples } from '../dev';
const calls: Array<{ path: string[]; args: unknown[] }> = [];
const testEnv = mockEnv(examples.env.push, (path, args) => {
calls.push({ path, args });
});
await destination.push(event, { ...context, env: testEnv });
expect(calls).toContainEqual({
path: ['window', 'gtag'],
args: ['event', 'purchase', expect.any(Object)],
});The env pattern is also the interception seam for trace-level vendor-call capture. At `trace` level the collector may attach an `observe` recorder under the `observe` key of the env, and `@walkeros/web-core`'s `getEnv` wraps the callables the destination declared as observable, recording each call. A destination that reaches its vendor through `getEnv(env)` is automatically observable; one that reaches a global directly, bypassing `env`, is not. This is one more reason to route every external call through `env`.
Rules that keep the seam intact:
client, writer) is taken from `env` when present and created only otherwise (`env?.BigQuery ?? BigQuery`). Every key the mock env declares must be read as `env.<key>` in `src`.
`call:PubSub.topic.publishMessage`, `call:JSONWriter.appendRows`), not a constructor. The one recorder is `observeEnv` in `@walkeros/core`; it navigates constructors, factories and Promises, and records only the leaf.
so a client built in `init` is recorded. Runtime trace mode wraps the env per push only, so calls through a client built in `init` are not recorded there.
TikTok, Snapchat, Pinterest, Bing, Reddit, Criteo, X, Data Manager, Piwik PRO) expose `ip` and `userAgent` settings (`Mapping.Value | false`), defaulting to `['ingest.ip', 'event.user.ip']` and `['ingest.userAgent', 'event.user.userAgent']`, resolved with `getMappingValue(createMappingRoot(ingest, event), setting, { collector })`. `false` disables, an explicit mapped vendor field wins, each package carries its own few lines (no shared helper).
config: {
settings: { /* destination-specific */ },
mapping: { /* event transformation rules */ },
data: { /* global data mapping */ },
consent: { /* required consent states */ },
policy: { /* processing rules */ },
queue: boolean, // queue events
dryRun: boolean, // test mode
queueMax: number, // consent-queued events cap (default 1000)
dlqMax: number, // dead-letter queue cap (default 100)
}Each destination keeps two internal buffers: `queuePush` (consent-denied events) and `dlq` (failed pushes). Both are size-bounded with FIFO drop-oldest eviction. Defaults: `queueMax: 1000`, `dlqMax: 100`. Set either on a destination's config to override per destination. Operators read drop counts from `collector.status.dropped[stepId('destination', id)]?.queue` (consent-denied evictions) and `?.dlq` (DLQ evictions). Build the key with `stepId()` from `@walkeros/core`. Point-in-time sizes stay on `collector.status.destinations[id].queuePushSize` / `dlqSize`.
`queuePush` drains back into the destination once consent allows delivery. The DLQ is never replayed: an event that reaches it is gone once it is evicted, which is what makes the delivery rules below worth getting right.
`config.timeout` bounds one delivery. A `push` or `pushBatch` that has not settled within it is abandoned, its events are routed to the DLQ and `failed` is incremented. The default is 10000 ms, applied whenever `timeout` is `0` or unset, so one slow destination never wedges the collector push.
**A destination's own client timeout has to fit inside it
From browser to BigQuery and ad platforms - warehouse-native, and ready for AI agents via MCP.
A CMP source is a specialized walkerOS source that listens to a consent management platform's events and translates consent…
Use when creating a new walkerOS destination to send events to a vendor or API (GA4/gtag, Meta/Facebook Pixel, Mixpanel,…
Use when creating a new walkerOS source to capture events (browser source, dataLayer interception, server/HTTP source, webhook…
| Symptom | Likely Cause | Check | | ---------------------------------- | ---------------------------- |…
Read [understanding-mapping](../walkeros-understanding-mapping/SKILL.md) first for core concepts.