create-destination
Use when creating a new walkerOS destination. Example-driven workflow starting with research and examples before implementation.
$ Instalar
git clone https://github.com/elbwalker/walkerOS /tmp/walkerOS && cp -r /tmp/walkerOS/skills/create-destination ~/.claude/skills/walkerOS// tip: Run this command in your terminal to install the skill
name: create-destination description: Use when creating a new walkerOS destination. Example-driven workflow starting with research and examples before implementation.
Create a New Destination
Prerequisites
Before starting, read these skills:
- understanding-flow - How destinations fit in architecture
- understanding-destinations - Destination interface
- understanding-mapping - Event transformation
- testing-strategy - How to test with env pattern
- writing-documentation - Documentation standards (for Phase 7)
Choose Your Template
| Complexity | Template | When to Use |
|---|---|---|
| Simple | plausible/ | Single SDK call, minimal config |
| Complex | gtag/ | Multiple services, sub-destinations |
| Server | gcp/ | Server-side, batching, SDK init |
Process Overview
1. Research → Find SDK, understand vendor API
2. Examples → Create dev entry with real usage patterns
3. Mapping → Define walkerOS → vendor transformation
4. Scaffold → Copy template and configure
5. Implement → Build using examples as test fixtures
6. Test → Verify against example variations
7. Document → Write README
Phase 1: Research
Goal: Understand the vendor API before writing any code.
1.1 Find Official Resources
- Vendor API Documentation - Endpoints, authentication, rate limits
- Official TypeScript SDK - Check npm for
@vendor/sdkorvendor-types - Event Schema - What fields are required/optional for each event type
# Search npm for official packages
npm search [vendor-name]
npm search @[vendor]
# Check for TypeScript types
npm info @types/[vendor]
1.2 Identify Event Types
List the vendor's event types and their required fields:
| Vendor Event | Required Fields | walkerOS Equivalent |
|---|---|---|
pageview | url, title | page view |
track | event, properties | product view, etc. |
identify | userId, traits | User identification |
1.3 Check Existing Patterns
Review similar destinations in the codebase:
# List existing destinations
ls packages/web/destinations/
# Reference implementations
# - plausible: Simple, script-based
# - gtag: Complex, multiple services
# - meta: Pixel with custom events
Gate: Research Complete
Before proceeding, confirm:
- API pattern identified (SDK function / HTTP / pixel)
- Auth method documented (API key, token, none)
- Event types mapped to walkerOS equivalents
Checkpoint: Research Review (Optional)
If working with human oversight, pause here to confirm:
- API pattern and auth method correct?
- Event mapping makes sense for the use case?
- Any vendor quirks or rate limits to handle?
Continue only after approval.
Phase 2: Create Examples (BEFORE Implementation)
Goal: Define expected API calls in dev entry FIRST.
2.1 Scaffold Directory Structure
mkdir -p packages/web/destinations/[name]/src/{examples,schemas,types}
2.2 Create Output Examples
What the vendor API expects when we call it:
src/examples/outputs.ts:
/**
* Examples of vendor API calls we will make.
* These define the CONTRACT - implementation must produce these outputs.
*/
// Page view call
export const pageViewCall = {
method: 'track',
args: ['pageview', { url: '/home', title: 'Home Page' }],
};
// E-commerce event call
export const purchaseCall = {
method: 'track',
args: [
'purchase',
{
transaction_id: 'T-123',
value: 99.99,
currency: 'USD',
items: [{ item_id: 'P-1', item_name: 'Widget', price: 99.99 }],
},
],
};
// Custom event call
export const customEventCall = {
method: 'track',
args: ['button_click', { button_id: 'cta', button_text: 'Sign Up' }],
};
2.3 Create Input Examples
walkerOS events that will trigger these outputs:
src/examples/events.ts:
import type { WalkerOS } from '@walkeros/core';
/**
* walkerOS events that trigger destination calls.
* Maps to outputs.ts examples.
*/
export const events: Record<string, WalkerOS.Event> = {
// Maps to pageViewCall
pageView: {
event: 'page view',
data: { title: 'Home Page', path: '/home' },
context: {},
globals: {},
user: { device: 'device-123' },
nested: [],
consent: { analytics: true },
id: '1-abc-1',
trigger: 'load',
entity: 'page',
action: 'view',
timestamp: 1700000000000,
timing: 0,
group: 'group-1',
count: 1,
version: { tagging: 1, config: 1 },
source: { type: 'web', id: '', previous_id: '' },
},
// Maps to purchaseCall
purchase: {
event: 'order complete',
data: { id: 'T-123', total: 99.99 },
// ... full event structure
},
// Maps to customEventCall
buttonClick: {
event: 'button click',
data: { id: 'cta', text: 'Sign Up' },
// ... full event structure
},
};
2.4 Create Environment Mock
src/examples/env.ts:
import type { DestinationWeb } from '@walkeros/web-core';
/**
* Mock environment capturing vendor SDK calls.
*/
export const env: { push: DestinationWeb.Env } = {
push: {
window: {
vendorSdk: jest.fn(), // Captures all calls for verification
} as unknown as Window,
document: {} as Document,
},
};
2.5 Export via dev.ts
src/dev.ts:
export * as schemas from './schemas';
export * as examples from './examples';
Gate: Examples Valid
- All example files compile (
npm run build) - Can trace: input event → expected output for each example
Phase 3: Define Mapping
Goal: Document transformation from walkerOS events to vendor format.
3.1 Create Mapping Examples
src/examples/mapping.ts:
import type { Mapping } from '@walkeros/core';
/**
* Default mapping: walkerOS events → vendor format.
*/
export const defaultMapping: Mapping.Rules = {
page: {
view: {
name: 'pageview', // Vendor event name
data: {
map: {
url: 'data.path',
title: 'data.title',
},
},
},
},
order: {
complete: {
name: 'purchase',
data: {
map: {
transaction_id: 'data.id',
value: 'data.total',
currency: { value: 'USD' },
},
},
},
},
button: {
click: {
name: 'button_click',
data: {
map: {
button_id: 'data.id',
button_text: 'data.text',
},
},
},
},
};
3.2 Verify Mapping Logic
Create a mental (or actual) trace:
Input: events.pageView
↓ Apply mapping
↓ page.view rule matches
↓ name: 'pageview'
↓ data.path → url, data.title → title
Output: Should match outputs.pageViewCall
Gate: Mapping Verified
- Mapping covers: page view + at least one conversion event
- Each mapping rule traces correctly to expected output
Phase 4: Scaffold
Template destination: packages/web/destinations/plausible/
cp -r packages/web/destinations/plausible packages/web/destinations/[name]
cd packages/web/destinations/[name]
# Update package.json: name, description, repository.directory
Directory structure:
packages/web/destinations/[name]/
├── src/
│ ├── index.ts # Main destination (init + push)
│ ├── index.test.ts # Tests against examples
│ ├── dev.ts # Exports schemas and examples
│ ├── examples/
│ │ ├── index.ts # Re-exports
│ │ ├── env.ts # Mock environment
│ │ ├── events.ts # Input events
│ │ ├── outputs.ts # Expected outputs
│ │ └── mapping.ts # Default mapping
│ ├── schemas/
│ │ └── index.ts # Zod schemas
│ └── types/
│ └── index.ts # Settings, Config types
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── jest.config.mjs
└── README.md
Phase 5: Implement
Now write code to produce the outputs defined in Phase 2.
5.1 Define Types
src/types/index.ts:
import type { DestinationWeb } from '@walkeros/web-core';
export interface Settings {
apiKey?: string;
// Add vendor-specific settings
}
export interface Config extends DestinationWeb.Config<Settings> {}
export interface Destination extends DestinationWeb.Destination<Config> {}
5.2 Implement Destination
src/index.ts:
import type { Config, Destination } from './types';
import type { DestinationWeb } from '@walkeros/web-core';
import { isObject } from '@walkeros/core';
import { getEnv } from '@walkeros/web-core';
export * as DestinationVendor from './types';
export const destinationVendor: Destination = {
type: 'vendor',
config: {},
init({ config, env }) {
const { window } = getEnv(env);
const settings = config.settings || {};
if (config.loadScript) addScript(settings, env);
// Initialize vendor SDK queue
(window as Window).vendorSdk =
(window as Window).vendorSdk ||
function () {
((window as Window).vendorSdk.q =
(window as Window).vendorSdk.q || []).push(arguments);
};
return config;
},
push(event, { config, data, env }) {
const params = isObject(data) ? data : {};
const { window } = getEnv(env);
// Call vendor API - must match outputs.ts examples
(window as Window).vendorSdk('track', event.name, params);
},
};
function addScript(settings: Settings, env?: DestinationWeb.Env) {
const { document } = getEnv(env);
const script = document.createElement('script');
script.src = `https://vendor.com/sdk.js?key=${settings.apiKey}`;
document.head.appendChild(script);
}
export default destinationVendor;
Gate: Implementation Compiles
-
npm run buildpasses -
npm run lintpasses
Phase 6: Test Against Examples
Verify implementation produces expected outputs.
src/index.test.ts:
import { destinationVendor } from '.';
import { examples } from './dev';
describe('destinationVendor', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('page view produces correct output', () => {
const mockSdk = jest.fn();
const env = {
...examples.env.push,
window: { vendorSdk: mockSdk } as unknown as Window,
};
destinationVendor.push(examples.events.pageView, {
config: {},
data: { url: '/home', title: 'Home Page' },
env,
});
// Verify against expected output
expect(mockSdk).toHaveBeenCalledWith(
examples.outputs.pageViewCall.method,
...examples.outputs.pageViewCall.args,
);
});
test('purchase produces correct output', () => {
// Similar test against purchaseCall
});
test('custom event produces correct output', () => {
// Similar test against customEventCall
});
});
Gate: Tests Pass
-
npm run testpasses - Tests verify against example outputs (not hardcoded values)
Phase 7: Document
Follow the writing-documentation skill for:
- README structure and templates
- Example validation against
apps/quickstart/ - Quality checklist before publishing
Key requirements for destination documentation:
- Event mapping table (walkerOS → vendor format)
- Configuration options table (use PropertyTable if schema exists)
- Working code example with imports
- Installation instructions
Destination-Specific Validation
Beyond understanding-development
requirements (build, test, lint, no any):
- Uses
getEnv(env)pattern (never directwindow/documentaccess) -
dev.tsexportsschemasandexamples - Examples match type signatures
- Tests use examples for assertions (not hardcoded values)
Reference Files
| What | Where |
|---|---|
| Simple template | packages/web/destinations/plausible/ |
| Complex example | packages/web/destinations/gtag/ |
| Types | packages/web/core/src/types/destination.ts |
Related
Repository
