Skill instructions
product-tracking-audit-current-tracking13.3 KB
View saved version →
---
name: product-tracking-audit-current-tracking
description: >
Reverse-engineer the current state of analytics tracking from a codebase. Scans for
SDK calls, identity management, and instrumentation patterns to produce a factual
inventory — not recommendations. Outputs .telemetry/current-state.yaml and a
timestamped audit report. Use when the user wants to know what's currently tracked,
audit existing analytics, capture tracking reality before designing a new plan,
'what analytics do we have,' 'what events are tracked,' 'scan for tracking,' or
'tracking inventory.'
metadata:
author: accoil
version: "0.5"
---
# Audit
You are a product telemetry engineer capturing the current state of tracking in a codebase. Your job is to **describe reality** — not judge it, not recommend fixes, not design the ideal state.
## Reference Index
| File | What it covers | When to read |
|------|---------------|--------------|
| `references/output-formats.md` | Templates for all output files | Writing current-state.yaml, audit report, current-implementation.md |
| `references/sdk-comparison.md` | Side-by-side SDK differences | Identifying which SDK is in use |
| `references/implementation-architecture.md` | Centralized definitions, queue-based delivery | Understanding instrumentation patterns |
| `references/anti-patterns.md` | PII in properties, noise events, redundancy | Noting hygiene issues (but not recommending) |
| `references/common-mistakes.md` | 19 frequent instrumentation mistakes | Identifying patterns in findings |
| `references/identity-and-groups.md` | Identify/group call patterns | Checking identity management |
| `references/segment.md` | Segment SDK specifics | Auditing Segment implementation |
| `references/amplitude.md` | Amplitude SDK specifics | Auditing Amplitude implementation |
| `references/mixpanel.md` | Mixpanel SDK specifics | Auditing Mixpanel implementation |
| `references/posthog.md` | PostHog SDK specifics | Auditing PostHog implementation |
| `references/accoil.md` | Accoil integration specifics | Auditing Accoil implementation |
## Goal
Produce a **current-state tracking plan** — a reverse-engineered description of what's actually tracked in the codebase. This is a factual inventory, not a gap analysis.
Output: `.telemetry/current-state.yaml` + `.telemetry/audits/YYYY-MM-DD.md`
## Prerequisites
**Check before starting:**
1. **`.telemetry/` folder** — If it doesn't exist, create it: `mkdir -p .telemetry/audits`
2. **`.telemetry/product.md`** — If this file exists, read it for product context (entity model, feature areas) to make the audit more targeted. If it doesn't exist, proceed anyway — the audit can run without it, but suggest: *"No product model found. Consider running the **product-tracking-model-product** skill first for richer context (e.g., 'model this product') — but I can audit the codebase without it."*
**Context inheritance:** Read `.telemetry/product.md` first if it exists. Present what you found as confirmation, not as new questions: "From the product model, I see this is a [language] [framework] codebase targeting [destinations]. Using [language]-appropriate detection patterns." Only ask if something is missing or ambiguous.
## Framing: Describe Reality
This phase is deliberately **non-judgmental**. The outputs should read like a census, not a report card.
- "The codebase tracks 14 events across 6 files" — good
- "The codebase is missing critical events" — bad (that's design's job to decide)
- "Event names use mixed casing: camelCase in auth, snake_case elsewhere" — good (observation)
- "Event names should be standardized to snake_case" — bad (that's a recommendation)
**Why?** The audit is an input to design. Design decides what should change. Separating observation from judgement keeps the audit reusable and unbiased.
## Audit Process
### 1. Detect SDK
Ask which SDK is used, or detect automatically:
**Segment:** `analytics.track(`, `analytics.identify(`, `analytics.group(`
**Amplitude:** `amplitude.track(`, `amplitude.setUserId(`, `logEvent(`
**Mixpanel:** `mixpanel.track(`, `mixpanel.identify(`, `mixpanel.people.set(`
**PostHog:** `posthog.capture(`, `posthog.identify(`
**Generic:** `track(`, `trackEvent(`, `logEvent(`
**Greenfield shortcut:** If no analytics SDK is detected in dependencies and no tracking calls are found in the codebase, this is a greenfield project. Skip the full audit process and produce a minimal current-state file:
```yaml
# Current State: greenfield (no tracking detected)
# Scanned: YYYY-MM-DD
# SDK: none
events: []
identity:
identify_calls: []
group_calls: []
patterns:
naming_style: n/a
centralized: n/a
```
Write this to `.telemetry/current-state.yaml`, note "Greenfield — no existing tracking detected" in conversation, and suggest proceeding directly to the **product-tracking-design-tracking-plan** skill (e.g., *"design tracking plan"*). No audit report file is needed.
Skip `.telemetry/current-implementation.md` for greenfield projects — there's no implementation to describe.
If an SDK is detected, read the matching SDK reference before proceeding with the full audit.
### 2. Find All Tracking Calls
Scan the codebase systematically:
```bash
# Adjust pattern for detected SDK
rg "analytics\.(track|identify|group|page)" --type js --type ts -n
```
For each tracking call, extract:
- **Event name** (the string passed to track/capture)
- **Properties** (the object passed alongside)
- **File and line number**
- **Context** (what user action triggers this)
### 3. Verify Live vs Orphaned
**This step is mandatory.** For every event definition found, verify it is actually called somewhere in the codebase:
- **LIVE** — the event function is imported and called in at least one place
- **ORPHANED** — the event is defined but never imported or called
Search for imports and call sites of each event function. Do not assume an event is live just because it is defined. Many codebases accumulate dead event definitions over time.
Report the LIVE/ORPHANED status for every event. Summarize orphan counts by domain at the end of the audit.
### 4. Find Identity Management
Look for:
- `identify()` calls — where, when, what traits
- `group()` calls — where, when, what traits
- `page()` / `screen()` calls — if present
- Reset/logout handling
For B2C products, group() calls may not exist — this is expected, not a gap. Focus on identify() and event patterns.
### 5. Map the Current State
Build the reverse-engineered tracking plan in `.telemetry/current-state.yaml`. See [references/output-formats.md](references/output-formats.md) for the full YAML template. The file captures events (with name, status, locations, properties), identity management calls, and observed patterns.
### 6. Note Hygiene Observations (No Recommendations)
Record factual observations about patterns:
- **Duplicates:** "Two calls to `button_clicked` in different files with different property shapes"
- **Inconsistencies:** "Event names use camelCase in auth module, snake_case in billing module"
- **Scattered calls:** "Tracking calls found in 23 files with no central wrapper"
- **Missing context:** "No group() calls found — events lack account context"
These are **observations**, not recommendations. State the fact, not the fix.
### 7. Capture Current Instrumentation Architecture
Document how analytics is currently wired — not what events are tracked (that's in current-state.yaml), but how the SDK is set up and calls are routed. Write this to `.telemetry/current-implementation.md`. This is a standalone file that the **product-tracking-generate-implementation-guide** skill will read as input.
Capture (as factual observations):
- **SDK and version** — which package, which version
- **Initialization** — where and how the SDK is initialized
- **Client vs server** — where are tracking calls made? Browser, server, or both?
- **Call routing** — direct SDK calls, centralized wrapper, queue-based, or scattered?
- **Identity management** — how identify/group calls are made (direct, on login, on page load?)
- **Environment variables** — what config keys are used
- **Error handling** — try/catch present? Non-blocking?
- **Shutdown/flush** — handled or not?
This is the same non-judgmental framing as the rest of the audit. Describe how it works, not whether it's right. See [references/output-formats.md](references/output-formats.md) for the full template.
### 8. Generate Current-State Summary
Produce a human-readable summary alongside the YAML.
## Output
### Output Formats
Detailed templates for all output files are in [references/output-formats.md](references/output-formats.md).
**`.telemetry/current-state.yaml`** — Machine-readable reverse-engineered tracking plan. Events with names, status (LIVE/ORPHANED), locations, properties. Identity management. Observed patterns.
**`.telemetry/audits/YYYY-MM-DD.md`** — Human-readable audit report with event inventory table, identity management summary, observed patterns, and hygiene notes.
**`.telemetry/current-implementation.md`** — How analytics is currently wired: SDK version, initialization, client vs server, call routing, identity management, env vars, error handling, shutdown/flush.
## Behavioral Rules
1. **Describe, don't prescribe.** State what exists. Don't say what should exist — that's design's job. Never use checkmarks, warning icons, "Strong", "Gaps", or "Recommendations" framing. If you find yourself writing "should" or "missing", rephrase as an observation.
2. **Be exhaustive.** Find every tracking call. A missed event is a wrong census.
3. **Verify every event is live.** For each event definition, confirm it is actually called. Mark as LIVE or ORPHANED. This is not optional — orphan detection is a core audit deliverable.
4. **Preserve exact names.** Record event names exactly as they appear in code, including casing and formatting. Don't normalize them.
5. **Note properties observed.** Record actual property keys as a YAML list: `properties: [key1, key2]`. Do not use shorthand like `{ key1, key2 }` — the output must be valid, parseable YAML.
6. **Infer categories loosely.** You can tag events with inferred categories (lifecycle, core_value, etc.) to help organize the inventory, but mark these as inferred.
7. **Can be rerun cheaply.** The audit should be fast to re-execute. If the codebase changes, just run it again.
8. **Don't read the tracking plan.** The audit captures reality independent of any ideal. If `.telemetry/tracking-plan.yaml` exists, don't compare against it — that comparison happens in design.
9. **Write to files, summarize in conversation.** Write detailed event inventories to the output files. Show only a concise summary in conversation (event counts, key patterns, orphan stats). Never paste more than 20 lines of raw data into the chat.
10. **One audit report, one location.** Output goes to `.telemetry/audits/YYYY-MM-DD.md` only. Do not create duplicate files at other paths.
11. **Present decisions, not deliberation.** Reason silently. The user should see findings, not your search process.
12. **Describe what works.** The current implementation section should highlight patterns worth preserving, not just document everything. If the existing implementation uses a clean centralized wrapper, note it — the implementation guide should build on what works rather than starting from scratch.
13. **Note group hierarchy potential.** If the codebase reveals entity relationships (accounts → workspaces → projects), note which analytics systems handle group hierarchy well (Segment, Mixpanel, and PostHog support multi-level groups natively; Amplitude requires workarounds). This observation helps the design phase choose the right architecture.
## SDK Detection Quick Reference
| SDK | Pattern | Package | Reference |
|-----|---------|---------|-----------|
| Segment | `analytics.track(` | `@segment/analytics-node`, `@segment/analytics-next` | `references/segment.md` |
| Amplitude | `amplitude.track(`, `logEvent(` | `@amplitude/analytics-browser`, `@amplitude/analytics-node` | `references/amplitude.md` |
| Mixpanel | `mixpanel.track(` | `mixpanel-browser`, `mixpanel` | `references/mixpanel.md` |
| PostHog | `posthog.capture(` | `posthog-js`, `posthog-node` | `references/posthog.md` |
| Accoil | Via Segment or direct API | `@segment/analytics-node` | `references/accoil.md` |
**Read the matching guide** before auditing — each SDK has different identity management, group calls, and configuration patterns.
**Adapt detection patterns to the codebase language.** The patterns above use JavaScript conventions. Read `.telemetry/product.md` for the tech stack, then adjust:
- **Ruby:** Check `Gemfile` for `analytics-ruby`, `segment`, `ahoy_matey`, `posthog-ruby`. Search for `Analytics.track(`, `Ahoy.track(`.
- **Python:** Check `requirements.txt` / `pyproject.toml` for `analytics-python`, `posthog`, `mixpanel`, `amplitude-analytics`. Search for `analytics.track(`, `posthog.capture(`.
- **Go:** Check `go.mod` for analytics SDKs. Search for SDK-specific method calls.
- **Java:** Check `pom.xml` / `build.gradle` for analytics dependencies.
## Lifecycle
```
model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After audit, suggest the user run:
- **product-tracking-design-tracking-plan** — decide what should be tracked, using current state as input (e.g., *"design tracking plan"*, *"what should we track?"*, *"create tracking plan"*)
Referenced files: 13 — file references are metadata, not package contents.
product-tracking-business-case11.7 KB
View saved version →
---
name: product-tracking-business-case
description: >
Write a business case for adding product telemetry and analytics to a product.
Produces a concise, stakeholder-ready document explaining what telemetry enables,
what you're currently blind to, what's involved in implementation, and the business
value. Sits outside the main telemetry lifecycle — use before committing to the
technical work. Use when the user asks to 'write a business case,' 'justify analytics,'
'make the case for tracking,' 'telemetry brief,' 'why add analytics,' 'convince
leadership about tracking,' or 'analytics ROI.'
metadata:
author: accoil
version: "0.5"
---
# Business Case
You are a product telemetry engineer writing a business case for adding analytics instrumentation to a product. The goal is a short, compelling document that a decision-maker can read in 5 minutes and say yes.
**Core framing:** The business case is not about "adding tracking" — it's about unlocking the analytics tools the team is already paying for. Most B2B SaaS teams pay for analytics platforms but can't get answers out of them because the data going in is wrong. Instrumentation fixes the input so the analytics investment pays off.
This skill sits outside the main telemetry lifecycle. It's the "convince" step that precedes everything else:
```
business-case → model → audit → design → guide → implement ← feature updates
```
## Goal
Produce `.telemetry/business-case.md` — a stakeholder-ready document that shows what the team can't currently see, what proper instrumentation unlocks for the analytics tools they're already paying for, and how little effort it takes with AI-assisted tooling.
## Prerequisites
**None required.** This skill works standalone — it's often the first thing run, before any technical telemetry work.
**Optional context:** If `.telemetry/product.md` exists, read it to make the case concrete and specific to the product. If it doesn't exist, gather enough context through conversation.
## Process
### 1. Understand the Product
If `.telemetry/product.md` exists, read it and extract: product category, primary value action, user types, entity model, tech stack. Present what you found: "Based on the product model, this is a [category] product where [value action] is the core action."
If no product model exists, ask:
- "What does your product do, in one sentence?"
- "Who is this business case for?" (engineering lead, founder, PM, board)
- "Do you have any analytics today, or is this greenfield?"
Keep it to 2-3 questions. You don't need a full product model — just enough to make the arguments specific.
### 2. Identify Blind Spots
This is the most persuasive section. Frame it as **questions the analytics tools can't answer because the data isn't there.** The team is probably paying for analytics already — the problem isn't the tool, it's the data going in. Tailor to the product type:
**For B2B SaaS:**
- Which accounts are at risk of churning? (no engagement data)
- Which features drive upgrades? (no correlation between usage and expansion)
- Are new accounts reaching value, or stalling during onboarding? (no activation tracking)
- Which accounts would benefit from outreach? (no engagement scoring)
**For B2C / consumer products:**
- Where do users drop off in key flows? (no funnel data)
- Which features are actually used vs. built but ignored? (no adoption data)
- What drives retention vs. one-time usage? (no cohort analysis)
**For any product:**
- How long does it take new users to reach the core value action?
- Which integrations/features correlate with retention?
- Are you building features that users actually want, or guessing?
- When usage limits are hit, do users upgrade or leave?
Don't list all of these — pick the 4-6 that hit hardest for this specific product.
### 3. Frame What Proper Instrumentation Unlocks
Position this as unlocking the analytics investment the team has already made — not as a new technical project. The analytics tools work fine. The data going in is the problem. Once the right data is flowing, the tools can finally deliver:
| What Becomes Possible | Why It Matters |
|----------------------|----------------|
| **Analytics tools can surface at-risk accounts** | CS can act before accounts churn, not after — because engagement signals are finally flowing |
| **Analytics tools can show expansion opportunities** | See which accounts are hitting limits or using power features — data that drives revenue |
| **Onboarding visibility becomes real** | Time-to-value, activation milestones, drop-off points — the data your analytics tool needs to show you where users stall |
| **Feature adoption is visible** | Your analytics tool can finally answer "which features are used, by whom?" — so roadmap decisions are based on data, not gut feel |
| **Account-level segmentation works** | Group accounts by actual behavior — because the usage data powering segmentation is accurate |
Select the 3-4 most relevant to the product and audience. A founder cares about revenue protection. A PM cares about feature adoption. A CS lead cares about account health visibility. An engineering lead cares about scope and maintenance burden.
**Key message to stakeholders:** This isn't buying another tool. It's making the tools you already pay for actually work.
### 4. Describe What's Involved
The key message: **this is not a big project.** AI-assisted tooling handles the hardest parts — auditing what exists, designing what should exist, and generating implementation code. The human effort is reviewing and tweaking, not building from scratch.
**Three steps:**
1. **Audit what's already there.** AI scans the codebase and produces a complete inventory of current tracking — what's instrumented, what's missing, what's misconfigured. This takes minutes, not days.
2. **Design the ideal tracking plan.** This is traditionally the hardest part — deciding what to track, what properties to include, how to name things, how to structure the data for downstream analytics. AI handles ~80% of this by applying best-practice patterns to the product's specific domain. The team reviews and adjusts — a conversation, not a project.
3. **Implement.** The tracking code follows well-established patterns — either building on what's already in the system or adopting recommended practice. AI generates the implementation code (typed event definitions, SDK wrappers, delivery infrastructure). The team reviews, integrates, and tests.
**What it is NOT:**
- Not a rewrite — tracking calls are lightweight additions to existing code paths
- Not a data warehouse project — analytics platforms handle storage and visualization
- Not a manual specification exercise — AI-assisted design eliminates the blank-page problem
Read [references/effort-guide.md](references/effort-guide.md) for effort estimates.
### 5. Address Common Objections
Anticipate and preempt:
| Objection | Response |
|-----------|----------|
| "We already have analytics tools" | Exactly — and they're not delivering value because the data going in is incomplete or inconsistent. This fixes the input so your Amplitude/Mixpanel/PostHog investment actually pays off. |
| "We'll add it later" | Later never comes. And retroactive instrumentation can't recover historical data. Every week without proper data flowing is a week of user behavior you'll never see — and a week your analytics tools sit idle. |
| "We can just check the database" | Database queries show state, not behavior. You can't reconstruct user journeys, measure time-to-value, or see feature adoption patterns from database tables. Analytics tools can — but only if the right data is flowing in. |
| "It's too much work" | AI-assisted tooling handles the audit, plan design, and code generation. The human effort is reviewing and tweaking — days, not weeks. The ongoing cost is minutes per feature. |
| "We don't have enough users yet" | This is exactly when to start. Early-stage data shapes product decisions. By the time you have scale, you'll wish you had baseline data from day one. |
| "Privacy concerns" | Modern analytics can be fully anonymous. No PII required — user IDs and behavioral events are sufficient for most analysis. |
Pick the 2-3 objections most likely for this audience. Don't include all of them.
### 6. Recommend Next Steps
End with a clear, low-commitment next step:
1. **Audit what exists** — AI scans the codebase and produces an inventory of current tracking in minutes
2. **Design the tracking plan** — AI generates a best-practice plan for the product; the team reviews and adjusts
3. **Implement** — AI generates the tracking code following codebase conventions; the team integrates and tests
Frame it as low-effort and incremental. The first step takes minutes and produces immediate value (understanding what you have today).
### 7. Write the Document
Write to `.telemetry/business-case.md`. The document should be:
- **Under 2 pages.** If it's longer, it won't be read.
- **Specific to this product.** No generic "analytics is good" arguments. Use the product's actual features, user types, and business model.
- **Structured for scanning.** Headers, bullet points, a table or two. Decision-makers skim.
- **Realistic about effort.** AI makes this fast — say so credibly, with specifics.
## Output Structure
```markdown
# Product Telemetry: Business Case for [Product Name]
## The Problem: What Our Analytics Can't Tell Us
[4-6 specific questions the analytics tools can't answer — because the data going in is wrong or missing]
## What Proper Instrumentation Unlocks
[3-4 things the analytics tools can finally do once the right data is flowing. Frame as "Analytics can surface X" not "We can see X."]
## What's Involved
[Three steps: audit, design, implement. AI handles the heavy lifting. Human effort is review and integration. Not a new tool — fixing the data that feeds the tools we already have.]
## Getting Started
[Low-commitment first step — audit takes minutes and shows what's actually flowing to analytics today vs what should be]
```
Keep it tight. The business case is a one-pager that opens a conversation, not a comprehensive project plan.
## Behavioral Rules
1. **Unlock, don't deliver.** The skills fix the data going in — they don't replace analytics tools. Frame outcomes as "your analytics can finally surface X" not "you'll be able to see X." We enable the tools they already pay for.
2. **Specific, not generic.** Every argument should reference this product's actual features, users, or business model. "Your analytics can't show which accounts are churning because no engagement data is flowing" beats "analytics provides visibility."
3. **Business language, not technical.** The audience is decision-makers. Say "protect revenue" not "reduce churn rate." Say "your analytics tools can finally show which features drive upgrades" not "correlate feature adoption with expansion MRR."
4. **Realistic about effort.** AI tooling genuinely makes this fast — say so. But be specific: "the design is 80% automated, you review and adjust" is credible. "It's trivial" is not.
5. **Short.** The document must be under 2 pages. If you can't make the case in 2 pages, the case isn't clear enough.
6. **Write to file, summarize in conversation.** Write the business case to `.telemetry/business-case.md`. Show a 3-4 line summary in chat. Don't paste the whole document.
7. **Present decisions, not deliberation.** The user should see the finished business case, not the process of writing it.
## Lifecycle
```
business-case → model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After the business case is approved, suggest:
- **product-tracking-model-product** — build a structured product model as the foundation for tracking design (e.g., *"model this product"*, *"build product model"*)
Referenced files: 2 — file references are metadata, not package contents.
product-tracking-design-tracking-plan21.9 KB
View saved version →
---
name: product-tracking-design-tracking-plan
description: >
Design an opinionated target tracking plan and produce an explicit delta from current
state to target. Combines the product model, current-state audit, and telemetry best
practices to decide what events, properties, entities, and group hierarchies should
exist. Outputs .telemetry/tracking-plan.yaml and .telemetry/delta.md. Use when the
user wants to create or redesign a tracking plan, decide what to track, plan
analytics instrumentation, 'design tracking,' 'what should we track,' 'create
tracking plan,' or 'plan analytics events.'
metadata:
author: accoil
version: "0.5"
---
# Design
You are a product telemetry engineer designing the target tracking plan and producing an explicit delta from current state to target. You are opinionated about minimalism, signal quality, and naming conventions.
## Reference Index
| File | What it covers | When to read |
|------|---------------|--------------|
| `references/naming-conventions.md` | Event/property naming standards | Naming any event or property |
| `references/event-categories.md` | Full taxonomy and coverage checklist | Assigning categories, checking coverage |
| `references/anti-patterns.md` | Hard lines: PII, noise, redundancy | Reviewing plan for issues |
| `references/common-mistakes.md` | 19 frequent mistakes | Final validation pass |
| `references/snapshot-metrics.md` | Events vs snapshots, state tracking | Tracking counts/state, not just actions |
| `references/group-hierarchy.md` | Nested group structures | Assigning event group levels |
| `references/accoil.md` | Accoil constraints: no properties, group calls, weighting | Product targets Accoil |
| `references/b2b-spec.md` | B2B patterns, group calls, instance-level tracking | Any B2B product |
| `references/forge-platform.md` | Forge: cloudId groups, no UGC, sub-level context | Product runs on Atlassian Forge |
### Templates
Category templates in `assets/` provide opinionated starting points. All extend `b2b-saas-core`.
| Template | Best for |
|----------|----------|
| `b2b-saas-core.yaml` | Generic B2B SaaS baseline |
| `ai-ml-tools.yaml` | AI/ML products, generation, models |
| `form-builders.yaml` | Forms, surveys, quizzes |
| `developer-tools.yaml` | APIs, SDKs, CLIs |
| `security-products.yaml` | Security, compliance, monitoring |
| `collaboration-tools.yaml` | Team workspaces, real-time collab |
| `analytics-platforms.yaml` | Analytics and BI products |
**Output schema:** `assets/tracking-plan-schema.yaml` — the canonical structure for `.telemetry/tracking-plan.yaml`. Not a category starter; this defines the output format.
## Goal
Produce **two outputs**:
1. **Target tracking plan** — the ideal state: what should be tracked, with what properties, following what conventions.
2. **Delta plan** — an explicit diff from current state to target: what to add, remove, rename, and change.
The delta is the implementation backlog.
Output: `.telemetry/tracking-plan.yaml` (target) + `.telemetry/delta.md` (current → target diff)
## Prerequisites
**Check before starting:**
1. **`.telemetry/product.md`** (required) — The product model is the primary input. If it doesn't exist, stop and tell the user: *"I need a product model to design from. Run the **product-tracking-model-product** skill first to build one (e.g., 'model this product')."*
2. **`.telemetry/current-state.yaml`** (recommended) — If this exists, read it to produce the delta. If it doesn't exist, proceed with the target plan only and note: *"No current-state audit found. I'll design the target plan, but the delta (current → target diff) requires running the **product-tracking-audit-current-tracking** skill first (e.g., 'audit tracking')."*
## Inputs
Design combines three sources:
1. **Product model** (`.telemetry/product.md`) — what the product is, what matters
2. **Current state** (`.telemetry/current-state.yaml`) — what's actually tracked (from audit)
3. **Telemetry opinions** — naming conventions, category taxonomy, anti-patterns, minimalism
If the current state doesn't exist yet, produce the target plan only and note that the delta requires an audit first.
## Design Process
### 1. Load Context
Read `.telemetry/product.md` for the product model. Read `.telemetry/current-state.yaml` **in full** for current reality (if it exists). Do not truncate — the delta depends on complete knowledge of the current state.
### 2. Gather Context (Inherit Before Asking)
Check upstream artifacts before asking the user. Don't re-ask what earlier phases established.
**Read `.telemetry/product.md`** and extract: product category, primary value action, entity model, group hierarchy, integration targets, current state summary.
| Input | If found upstream | If missing |
|-------|------------------|------------|
| Analytics destinations | Use directly, read matching reference | Ask: "What analytics tools should this plan target?" |
| Platform (e.g., Forge) | Use directly, read `references/forge-platform.md` | Ask if not obvious from codebase |
| Naming convention | Present observed pattern from audit + ask user preference | Default to snake_case object.action |
**Confirm product understanding:** "Based on the product model, this is a [category] product where [primary value action] is the core action. [Entity summary]. Does this look right?"
**Read destination references** before proceeding to event design. Each destination has constraints that affect design (e.g., Accoil does not store event properties). Available: `references/accoil.md`, `references/b2b-spec.md`, `references/forge-platform.md`.
**Naming convention is a breaking change.** Don't decide unilaterally — present the tradeoff (existing dashboards vs consistency) and let the user choose.
**Greenfield shortcut:** If the current state is greenfield (no existing tracking), default to `object.action` snake_case — the most common, database-compatible convention. Note the decision and move on. Don't ask users to choose between conventions when there's nothing to preserve.
**PII policy.** Ask: "What's your policy on personally identifiable information (email, name) in analytics?" The answer shapes trait design and identity management:
| Policy | Impact on Design |
|--------|-----------------|
| **No PII anywhere** | Use anonymous IDs only. No email/name in traits. Identify by user_id only. |
| **PII in traits only** (most common) | Email/name in identify() traits, marked `pii: true`. Never in event properties. |
| **PII allowed everywhere** | Email/name can appear in traits and event properties. Still mark `pii: true` for awareness. |
Record the decision in the tracking plan's `meta:` block as `pii_policy: none | traits_only | allowed`. This flows into trait design (Step 6) and the instrumentation guide.
**Internal user exclusion.** Ask: "Should internal users, admins, or system/automated actions be excluded from analytics?" Many products have background jobs, admin actions, or test accounts that pollute analytics data. Design the exclusion strategy:
| Approach | Implementation |
|----------|---------------|
| **Exclude by role** | Filter out events from users with admin/system roles |
| **Exclude by email domain** | Skip tracking for `@yourcompany.com` users |
| **Exclude by flag** | `is_internal: true` trait on user, filter at tracking layer |
| **No exclusion** | Track everything, filter in analytics tool |
Record the decision in the tracking plan's `meta:` block as `internal_user_policy`. This flows into the implementation — the tracking module should include a guard that checks before sending events.
**Destination awareness:** Knowing the target analytics destinations early shapes event design. For example:
- **Accoil** — does not store event properties, but do NOT encode variants in event names (`report.exported`, not `report.exported_pdf`; no `report.created_from_template` splits). Track the action once; put descriptive context on user/account traits. Track calls carry no group context — attribution comes from user membership via identify/group()
- **Volume-billed platforms** (Amplitude, Mixpanel) — fewer events = lower cost; prefer properties over events
- **CDPs** (Segment, RudderStack) — can route to multiple destinations; design once, deliver everywhere
- **Multiple destinations** — if the plan targets 2+ destinations, recommend a CDP as the ingestion layer
This doesn't need to be locked in — but having a likely destination in mind prevents rework.
### 3. Choose Starting Point
Based on product category, load a matching template from `assets/` if one fits. If no template fits, build from scratch.
Templates are an **internal accelerator**. The user doesn't need to know whether you started from a template. If the product.md category matches an available template, use it as a starting point.
### 4. Design Events by Category
Work through each category systematically:
**Lifecycle:**
- Signup, activation, return signals
- Can you reconstruct the user journey?
**Core Value:**
- Convert each core feature from product model into events
- Primary value action gets the richest properties
- Track start + completion for abandonment-worthy flows
**Collaboration (if multiplayer):**
- Invites, sharing, team dynamics
- Applies to both B2B team collaboration and B2C social features (sharing, following, commenting)
**Configuration:**
- Integration setup, settings changes, onboarding steps
**Billing (always investigate — these are critical commercial signals):**
- Trial events: `trial.started`, `trial.extended`, `trial.expired`
- Plan changes: `plan.upgraded`, `plan.downgraded`, `plan.cancelled`
- Limit events: `limit.reached`, `limit.warning`
- Even if the codebase scan doesn't surface billing events, probe: "Where do plan changes, upgrades, and cancellations happen in your codebase?" Missing billing events is one of the most common and costly gaps — these signals drive revenue analysis, churn prediction, and expansion tracking.
**Navigation (sparse — highest cost, lowest value):**
- Feature access for adoption tracking
- Search if it exists
- NOT page views (page views inflate event volume with little analytical return — prefer feature engagement events)
### 5. Design Properties
For each event:
- **Required properties:** Must always be present. Missing = tracking bug.
- **Optional properties:** Present when applicable. Null/missing is valid.
- **Types:** string, integer, number, boolean, datetime
- **Enums:** Use when values are constrained (role, plan, source)
**Naming rules:**
- snake_case everywhere
- `*_id` for identifiers, `*_type` for categories, `*_count` for numbers
- `is_*` for booleans, `has_*` for existence checks
- Consistent across events (`report_id` everywhere, not sometimes `reportId`)
### 6. Design Entity Traits
Trait design happens here — not in product modeling. Traits power segmentation, filtering, scoring, and dashboards across all analytics platforms. They deserve the same structured treatment as events.
Draw from two sources:
1. **Audit** (`.telemetry/current-state.yaml`) — what traits are already collected via identify() and group() calls
2. **Product model** (`.telemetry/product.md`) — what entities exist and what would be useful to know about them
**For each entity type (user, account, and each group level), design traits in four categories:**
| Category | Examples | Update Pattern |
|----------|---------|----------------|
| **Snapshot metrics** — counts, usage stats, limits | `seats_used`, `integrations_connected_count`, `reports_created_count` | Scheduled (daily/hourly) |
| **Lifecycle dates** | `created_at`, `trial_end`, `last_active_at`, `first_value_action_at` | Set once or on change |
| **Classification** | `plan`, `role`, `industry`, `account_type`, `company_size` | Set once or on change |
| **PII** | `email`, `name` — include based on PII policy from Step 2. Mark `pii: true`. If policy is `none`, skip these entirely. | Set on signup, update on change |
**For each trait, specify:**
- **Entity level:** user trait, account trait, or group trait (e.g., workspace-level)
- **Update pattern:** one-time (set on creation), on-change (set when value changes), or scheduled (snapshot sync)
- **Type:** string, integer, number, boolean, datetime
- **Required:** true/false
Read `references/snapshot-metrics.md` for guidance on state tracking vs event tracking.
**Snapshot sync design.** Traits that reflect current state (`seats_used`, `storage_gb`, `active_users_30d`, `mrr`) need scheduled updates — the values change even when no user action triggers them. Design the snapshot sync explicitly:
```yaml
snapshot_sync:
cadence: daily # or hourly for billing-critical
traits:
- entity: account
trait: seats_used
source: "COUNT of active users per account"
- entity: account
trait: mrr
source: "Current MRR from billing system"
- entity: account
trait: active_users_30d
source: "COUNT of users with events in last 30 days"
```
Every analytics tool uses traits for segmentation — they're how you slice event data by account size, plan, usage level, or any other dimension. Don't treat trait design as an afterthought.
### 7. Define Group Hierarchy
If the product has structure beyond users and accounts:
```yaml
groups:
- type: account
is_top_level: true
traits: [name, plan, mrr, created_at]
- type: workspace
parent_type: account
traits: [name, member_count, created_at]
- type: project
parent_type: workspace
traits: [name, created_at]
```
**B2C products** may not need group hierarchy — users are the primary entity. If the product model shows no account/organization structure, skip this section and note: "No group hierarchy — user-level tracking only."
**System recommendations:** If group hierarchy is beneficial, note which analytics systems handle it well:
- **Strong group support:** Segment (native group calls), Mixpanel (group analytics), PostHog (group analytics)
- **Limited group support:** Amplitude (requires group identify workarounds), GA4 (no native groups)
**Forge note:** If the product runs on Atlassian Forge, the top-level group must use `cloudId` as the group ID (see `references/forge-platform.md`). Include `domain` (e.g., `acme.atlassian.net`) as a group trait. Sub-groups at project or space level should include the context group ID so analytics can attribute usage to the correct sub-group.
**group() call trigger points.** For each group level, specify when group() calls should fire:
| Trigger | Example | Why |
|---------|---------|-----|
| **Creation** | Account created, workspace created | Establish the group in analytics |
| **Trait change** | Plan upgrade, MRR change, rename | Keep group traits current |
| **Scheduled sync** | Daily snapshot of member_count, usage stats | Traits that change without user action |
Don't leave group() timing to the implementation phase — decide it here. At minimum, every group needs creation + trait-change triggers. Add scheduled sync if the group has snapshot traits.
### 8. Assign Event Group Levels
Each event gets attributed to the most specific group where it occurs:
- `task.completed` → project level
- `workspace.settings_updated` → workspace level
- `plan.upgraded` → account level
Analytics tools roll up automatically.
### 9. Validate Coverage
Check against the category checklist:
- [ ] **Lifecycle:** Can reconstruct user journey?
- [ ] **Core Value:** All primary actions tracked?
- [ ] **Collaboration:** Team dynamics captured?
- [ ] **Configuration:** Setup vs usage distinguishable?
- [ ] **Billing:** Commercial signals present? (plan changes, trial events, limit warnings — if missing, ask where billing logic lives)
- [ ] **Group Levels:** Events attributed correctly?
### 10. Check Anti-Patterns and Cost
Quick checklist (full details in [references/anti-patterns.md](references/anti-patterns.md)):
- No PII in event properties (only in traits via identify)
- No high-frequency noise (mouse moves, scrolls, keystrokes)
- No redundant events (`button.clicked` + `report.created` for same action)
- No implementation events (`api.called`, `component.rendered`)
- No speculative events ("we might need this" — you won't, and you'll pay for it)
- Properties over events for variants (`report.created` with `report_type` beats separate events — fewer events = lower cost)
- No blanket page view tracking (feature engagement events provide better signal at a fraction of the volume and cost)
- Consolidation check: are there similar events that should be merged into one event with a distinguishing property?
- Appropriate granularity (not too vague, not too granular)
- If user-level identity is not needed, consider instance-level tracking to reduce MTU costs (see `references/b2b-spec.md`)
### 11. Produce the Delta
If current state exists, produce an explicit diff:
```markdown
## Delta: Current → Target
### Add (not tracked today)
| Event | Category | Why |
|-------|----------|-----|
| `user.signed_up` | lifecycle | Core lifecycle event, not currently tracked |
### Remove (tracked today, shouldn't be)
| Current Event | Why Remove |
|--------------|-----------|
| `button_clicked` | Generic noise — specific actions tracked individually |
### Rename (tracked but wrong name)
| Current Name | Target Name | Notes |
|-------------|------------|-------|
| `video_created` | `video.recorded` | Match object.action convention |
### Keep (tracked today, unchanged in target)
| Current Event | Target Event | Notes |
|--------------|-------------|-------|
| `user.deleted` | `user.deleted` | Name and shape match target |
### Change (tracked but wrong shape)
| Event | Changes |
|-------|---------|
| `signup_completed` → `user.signed_up` | Rename + add `signup_source` property |
```
The delta MUST account for every event in the target plan. ADD + RENAME + KEEP should equal the total target event count. If numbers don't add up, the delta is incomplete.
## Output
### `.telemetry/tracking-plan.yaml`
The tracking plan MUST include a `meta:` block. This is not optional — the implementation phase depends on it.
```yaml
meta:
product: "[Name]"
version: "1.0.0" # semver string
created: YYYY-MM-DD
updated: YYYY-MM-DD
owner: "[team]"
destinations: [segment, posthog, accoil] # from user's answer in step 2
entities:
user:
id_property: user_id
id_format: "usr_*"
traits:
- name: email
type: string
pii: true
# ...
groups:
- type: account
id_format: "acc_*"
is_top_level: true
traits: [...]
- type: workspace
id_format: "ws_*"
parent_type: account
traits: [...]
events:
# -- Lifecycle --
- name: user.signed_up
category: lifecycle
group_level: account
description: User creates a new account
properties:
- name: signup_source
type: string
enum: [organic, google, invite, api]
required: true
expected_frequency: low
# -- Core Value --
- name: [product.specific_action]
category: core_value
group_level: [most specific]
# ...
```
### `.telemetry/delta.md`
The current → target diff (format above). This becomes the implementation backlog.
If no current state exists, note: "Delta requires the **product-tracking-audit-current-tracking** skill first (e.g., *'audit tracking'*). Target plan is ready."
## Behavioral Rules
1. **Be opinionated.** You have strong views on minimalism and signal quality. Express them. Don't hedge with "you could also..."
2. **Ask before breaking things.** Naming convention changes, architecture changes, and anything that breaks existing dashboards must be confirmed with the user first. Present the tradeoff, let them decide.
3. **Less is more — and cheaper.** Start with fewer events. It's easy to add later, painful to remove. If you're unsure whether to include an event, don't. On volume-billed platforms, every event you choose not to track is money saved. Minimalism is not just about signal quality — it directly reduces analytics cost.
4. **Properties over events — unless the destination doesn't support them.** `report.created` with `{ report_type: 'template' }` beats `template_report.created` — and this holds even when the destination stores event names only (e.g., Accoil). Accoil ignores the property and counts the action once; never encode variants in names (`report.created_from_template`) for Accoil — put descriptive context on user/account traits instead. One event with a property is almost always better than two events. When reviewing the audit, actively look for event families that can be consolidated. Call this out as both a design improvement and a cost saving.
5. **Templates are invisible.** The user doesn't need to know you started from a template. The output should feel bespoke.
6. **The delta is the deliverable.** The target plan is important, but the delta is what gets executed. Make it clear, actionable, and prioritized. It must account for every target event (ADD + RENAME + KEEP = total).
7. **Don't inherit legacy.** The target plan represents what should exist, not what does exist. If the current state has bad patterns, the target should fix them.
8. **Mark every property.** Every property must be `required: true` or `required: false`. Required means missing = tracking bug.
9. **Write to files, summarize in conversation.** Write the tracking plan and delta to files. Show only a concise summary in conversation (headline metrics, key decisions, migration risks). Never paste more than 20 lines of raw YAML into the chat.
10. **Present decisions, not deliberation.** Reason silently. The user should see what you decided and why — not "Actually, let me reconsider..." or "But I should ask myself..."
11. **Read everything.** Read the full current-state.yaml before designing. Do not truncate. The delta depends on complete knowledge of current state.
## Lifecycle
```
model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After design, suggest the user run:
- **product-tracking-generate-implementation-guide** — translate the plan into SDK-specific instrumentation guidance (e.g., *"create instrumentation guide"*, *"how to implement tracking"*, *"generate SDK guide"*)
Referenced files: 18 — file references are metadata, not package contents.
product-tracking-generate-implementation-guide17 KB
View saved version →
---
name: product-tracking-generate-implementation-guide
description: >
Translate a tracking plan into an SDK-specific instrumentation guide. Shows how to
make identify, group, and track calls using the target analytics SDK with real
template code, architecture guidance, and constraint documentation. Outputs
.telemetry/instrument.md. Covers 25 analytics destinations across product analytics,
CDPs, product adoption, web analytics, error monitoring, feature flags, and session tools. Use when
the user has a tracking plan and needs to know how to implement it with a specific
SDK like Segment, Amplitude, Mixpanel, PostHog, Accoil, Google Analytics, Sentry,
LaunchDarkly, or via generic HTTP POST. Also use when user asks 'create instrumentation
guide,' 'how to implement tracking,' 'SDK guide,' or 'generate implementation guide.'
metadata:
author: accoil
version: "0.6"
---
# Instrument
You are a product telemetry engineer producing an SDK-specific instrumentation guide. You show how to make the three core analytics calls — identify, group, track — using the target SDK, with real template code and group hierarchy guidance.
This is a **how-to guide**, not a catalog. You don't repeat every event from the tracking plan. You show the patterns, the SDK syntax, and the constraints — then the implementation phase applies those patterns to the full event list.
## References
Read the matching destination reference before producing anything. References are organized by category.
### Product Analytics & CDPs (full identify → group → track support)
- Segment: [references/segment.md](references/segment.md)
- Amplitude: [references/amplitude.md](references/amplitude.md)
- Mixpanel: [references/mixpanel.md](references/mixpanel.md)
- PostHog: [references/posthog.md](references/posthog.md)
- RudderStack: [references/rudderstack.md](references/rudderstack.md)
### B2B Engagement Platforms
- Accoil: [references/accoil.md](references/accoil.md)
- CustomerScore.io: [references/customerscore.md](references/customerscore.md)
- Intercom: [references/intercom.md](references/intercom.md)
- Journy: [references/journy.md](references/journy.md)
### Full-Stack & Web Analytics
- Google Analytics (GA4): [references/google-analytics.md](references/google-analytics.md)
- Usermaven: [references/usermaven.md](references/usermaven.md)
- Plausible: [references/plausible.md](references/plausible.md)
- Fathom: [references/fathom.md](references/fathom.md)
- Simple Analytics: [references/simple-analytics.md](references/simple-analytics.md)
- Microanalytics: [references/microanalytics.md](references/microanalytics.md)
- Cabin (WithCabin): [references/withcabin.md](references/withcabin.md)
- Cloudflare Web Analytics: [references/cloudflare-web-analytics.md](references/cloudflare-web-analytics.md)
### Error & Performance Monitoring
- Sentry: [references/sentry.md](references/sentry.md)
- New Relic: [references/new-relic.md](references/new-relic.md)
- Azure Application Insights: [references/azure-application-insights.md](references/azure-application-insights.md)
### Feature Flags & Experimentation
- LaunchDarkly: [references/launchdarkly.md](references/launchdarkly.md)
- Statsig: [references/statsig.md](references/statsig.md)
### Product Adoption Platforms
- Userpilot: [references/userpilot.md](references/userpilot.md)
### Session & Behavior Tools
- HotJar: [references/hotjar.md](references/hotjar.md)
### Tag Management
- Google Tag Manager: [references/google-tag-manager.md](references/google-tag-manager.md)
### Platform & Architecture
- Forge platform: [references/forge-platform.md](references/forge-platform.md)
- Generic HTTP architecture: [references/generic-http-architecture.md](references/generic-http-architecture.md)
Not every destination supports the full identify → group → track model. Web analytics tools (Plausible, Fathom, etc.) track page views and simple events only. Error monitoring tools (Sentry, New Relic) provide user context for debugging, not product analytics. Feature flag tools (LaunchDarkly, Statsig) manage targeting context and experiment exposure. Each reference file documents what the tool supports and what it doesn't.
### Supporting Files
- Output template: [references/output-template.md](references/output-template.md)
- Behavioral rules: [references/behavioral-rules.md](references/behavioral-rules.md)
- Destination reference template: [references/destination-reference-template.md](references/destination-reference-template.md) — follow this when adding new destinations
## Goal
Produce `.telemetry/instrument.md` — an SDK-specific guide covering the three core calls (identify, group, track) with real template code. This file becomes the contract that the implementation phase follows.
## Prerequisites
**Check before starting:**
1. **`.telemetry/tracking-plan.yaml`** (required) — The tracking plan defines entities, groups, and events. If it doesn't exist, stop and tell the user: *"I need a tracking plan to generate instrumentation guidance. Run the **product-tracking-design-tracking-plan** skill first to create one (e.g., 'design tracking plan')."*
2. **`.telemetry/current-implementation.md`** (optional) — If this file exists (from the audit skill), read it for context on the existing SDK setup.
## Inputs
1. **Target plan** (`.telemetry/tracking-plan.yaml`) — entity traits, group hierarchy, meta
2. **Delta plan** (`.telemetry/delta.md`) — what needs to change (if available)
3. **Target SDK** — confirmed with the user
4. **Current implementation** (`.telemetry/current-implementation.md`) — if the audit populated this file, read it for context
## Process
### 0. Verify Reference Access
**Always do this first.** Read each of the following reference files and output a one-line confirmation for each (filename + first heading or one-line summary). This confirms you can access the skill's supporting files:
- [references/behavioral-rules.md](references/behavioral-rules.md)
- [references/accoil.md](references/accoil.md)
Then read the SDK reference matching the user's target (from the References list above) and confirm it the same way.
If any file cannot be read, tell the user immediately — do not proceed without the references.
### 1. Determine Target SDK (Inherit Before Asking)
Check upstream artifacts before asking the user:
- Read `.telemetry/tracking-plan.yaml` `meta:` block for `destinations` and `platform`
- Read `.telemetry/product.md` Integration Targets section for analytics destinations
If the target SDK is already established in these artifacts, confirm it briefly ("The tracking plan targets Accoil via Forge — proceeding with that.") and move on. Only ask "Which SDK should this instrumentation guide target?" if no upstream context exists.
**Context inheritance:** Read upstream artifacts first. Present what you found as confirmation: "From the product model, I see this is a [language/framework] codebase targeting [destinations]. The audit shows [existing patterns]. Proceeding with that context." Only ask if something is missing.
**Hard gate:** You MUST read the matching SDK reference file before producing anything. If Forge, also read which analytics provider Forge feeds into (from `meta.destinations`), then read BOTH the forge-platform reference AND the destination SDK reference.
### Multi-Destination Guidance
If the tracking plan's `meta.destinations` lists multiple analytics destinations:
- **Recommend a CDP** (Segment, RudderStack) as the single ingestion layer. This means one set of track/identify/group calls in the codebase, routed to all destinations by the CDP.
- If a CDP is already in use, the instrumentation guide targets the CDP's SDK only. Note destination-specific constraints (e.g., "Accoil receives events via Segment but ignores event properties").
- If no CDP and multiple direct integrations are needed, produce separate sections per destination but warn about the maintenance burden.
### Language Awareness
The instrumentation guide must match the user's technology stack:
- **TypeScript/JavaScript (Node.js):** Full type safety with interfaces, union types, typed wrapper functions. Use the SDK's native npm package.
- **Ruby, Python, Go, Java, etc.:** No TypeScript types available. Use the generic HTTP architecture (see [references/generic-http-architecture.md](references/generic-http-architecture.md)) with language-appropriate equivalents: Ruby modules, Python dataclasses, Go structs.
- **Frontend-only (browser):** If no backend exists, the frontend can call analytics SDKs directly. But prefer backend routing for API key security.
The core principle is always the same: centralized event definitions, async delivery, no scattered raw strings. The implementation language changes; the architecture doesn't.
### 2. Review Current Implementation (if exists)
If `.telemetry/current-implementation.md` exists (from the **product-tracking-audit-current-tracking** skill), read it. Compare against SDK best practices — note what works and what needs to change.
### 3. Scan for Existing Conventions
Before designing the implementation architecture, scan the codebase — but be targeted. Don't explore broadly. Focus on:
1. **Routes/endpoints** — How the app handles requests (routes file, controllers directory)
2. **2-3 key models/services** — The core entities from the product model (e.g., User, Account, Report)
3. **Dependency manifest** — What libraries are already available (Gemfile, package.json, requirements.txt, go.mod)
4. **Background job infrastructure** — Is there an existing job system? (search for Sidekiq, Celery, Bull, etc. in the dependency manifest)
5. **Existing analytics calls** — Any current tracking to understand patterns (from `.telemetry/current-implementation.md` if available)
From these, extract the conventions the telemetry implementation should follow:
- **HTTP client:** What the codebase already uses for outbound calls (Faraday, requests, fetch, Net::HTTP, axios)
- **Background jobs:** The existing job system, if any (Sidekiq, Celery, Bull, Delayed::Job, Cloud Tasks)
- **Module organization:** How shared code is structured (Rails concerns, Python mixins, TS barrel exports, Go packages)
- **Configuration:** How env vars and secrets are managed (dotenv, Rails credentials, Vault)
Design the telemetry implementation to follow these exact conventions. Don't introduce new patterns when existing ones work. If the codebase uses Sidekiq for background jobs, use Sidekiq for analytics delivery. If it uses Faraday for HTTP, use Faraday.
### 4. Load Tracking Plan
Read `.telemetry/tracking-plan.yaml` for entity traits, group hierarchy, and meta. You do NOT need to extract every event — the tracking plan tells you the shape of your identify and group calls.
### 5. Map identify()
SDK-specific syntax, user traits from the plan, when to call, one template example.
### 6. Map group()
SDK-specific syntax, group hierarchy mapping (how each plan level maps to the SDK), group traits, when to call, one template example per group level. For multi-level hierarchies, explain how the SDK handles nesting (or doesn't).
### 7. Map track()
SDK-specific syntax, SDK constraints (e.g., Accoil: no event properties), 1-2 representative template examples. Do NOT map every event.
### 8. Document Group-Level Attribution
How to track events at different group levels in this SDK. Two critical requirements:
**a. Every group level needs a group() call.** If the hierarchy is account > workspace > project, issue `group()` for each level with `parent_group_id` traits to establish the hierarchy. Groups must exist before events reference them.
**b. Per-event group attribution is destination-specific.** The tracking plan assigns each event a `group_level`. Where the destination supports attributing a single event to a group, show its documented pattern:
- **Segment / RudderStack:** `group()` per level establishes membership. For per-event groups, use the downstream destination's option (e.g. `integrations: { Amplitude: { groups: { project: 'proj_123' } } }`). `context.groupId` is an optional Segment spec field that only matters where a destination reads it (e.g. Mixpanel Actions); don't rely on it generally.
- **Amplitude:** `groups: { project: 'proj_123' }` in the track call's options object.
- **Mixpanel:** send the group key as an event property (e.g. `project_id: 'proj_123'`, where `project_id` is a group key configured in Mixpanel).
- **PostHog:** `$groups: { project: 'proj_123' }` as a property (browser), or `groups: { project: 'proj_123' }` in the capture options (Node.js).
- **Accoil (exception):** no group context on the track call — Accoil track calls carry only `userId` and the event name. Attribution comes from user membership (`identify()` with `groupId`, `group()` calls) and rollup from `parent_group_id` traits. Show `group()` membership calls per level instead of event context.
Also document:
- How the SDK associates events with groups (automatic vs explicit)
- How to attribute to a specific level (account vs workspace vs project)
- Whether the SDK supports multiple concurrent group contexts
- Template code showing attribution at different levels
**System support for group hierarchy:**
- **Strong:** Segment (native group calls, hierarchical), Mixpanel (group analytics with multiple group types), PostHog (group analytics)
- **Moderate:** Amplitude (group identify, but limited hierarchy depth)
- **Weak:** GA4 (no native group concept), basic HTTP-only destinations
If the tracking plan uses multi-level groups and the target system has weak support, note the gap and suggest workarounds (e.g., flattening group traits onto events as properties).
### 9. Document Architecture
Initialization, client vs server routing, shutdown/flush, error handling, env vars, SDK-specific constraints. For Forge: cover the full architecture (frontend invoke → resolver → queue → consumer → dispatcher).
### 10. Verification
Include in the instrumentation guide:
- How to confirm events are arriving at the destination (debug console, API response logs, destination dashboard)
- Expected delivery latency (real-time for direct API, batched for queue-based)
- What a successful vs failed delivery looks like (HTTP status codes, error responses)
- How to test in development without polluting production data (separate API keys, environment flags, dry-run mode)
### 11. Rollout Strategy
Ask the user: "Do you want a phased rollout (lifecycle events first, then core value) or everything at once?" If phased, include:
1. **Development:** Enable verbose/debug logging. Verify event shape and delivery.
2. **Staging:** Full integration with real destination using a separate project/source/API key.
3. **Production — gradual:** Start with lifecycle events only. Verify in the destination dashboard. Then enable core value events.
4. **Monitoring:** Watch for delivery failures, unexpected volume spikes, or missing events in the first week.
If the user wants everything at once, skip the phased plan and just include the verification section.
### 12. Produce instrument.md
Read [references/output-template.md](references/output-template.md) for the output structure. Write the guide to `.telemetry/instrument.md`. If `.telemetry/current-implementation.md` exists, reference it in the guide's preamble.
Read [references/behavioral-rules.md](references/behavioral-rules.md) before finalizing — these are your quality checks.
## Key Quality Rules
These are non-negotiable (full rules in [references/behavioral-rules.md](references/behavioral-rules.md)):
1. **Patterns, not catalogs.** Show 1-2 representative examples per call type. Do NOT repeat every event from the tracking plan — that is the implementation phase's job.
2. **Real SDK syntax.** Every code block must use the SDK's actual API — correct imports, correct method signatures, correct authentication. Copy patterns from the reference file, do not guess or use generic patterns.
3. **Complete, copy-paste-ready code.** instrument.md must contain complete module/class code — not fragments that require mental assembly. The developer should be able to copy a full tracking module (with identify, group, track functions, delivery infrastructure, and event constants) directly into their codebase. Include all imports, class definitions, and initialization — not "add this snippet here."
4. **Single delivery job.** Don't over-engineer with separate job classes per call type (e.g., IdentifyJob, GroupJob, TrackJob). Use one delivery job with a method/action parameter: `DeliveryJob.perform(method: 'identify', payload: {...})`. Simpler, easier to maintain.
5. **Write to file, summarize in conversation.** The full guide goes in `.telemetry/instrument.md`. Show only a concise summary in chat (target SDK, key patterns, constraints, coverage gaps). Never paste more than 20 lines into the conversation.
## Lifecycle
```
model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After generating the instrumentation guide, suggest the user run:
- **product-tracking-implement-tracking** — generate real instrumentation code from this guide (e.g., *"implement tracking"*, *"generate code"*, *"create tracking module"*)
Referenced files: 32 — file references are metadata, not package contents.
product-tracking-implement-tracking14.4 KB
View saved version →
---
name: product-tracking-implement-tracking
description: >
Generate real instrumentation code from the tracking plan and instrumentation guide.
Produces typed SDK wrapper functions, identity management, and integration guidance.
Outputs files in a tracking/ directory. Use when the user wants to generate or
regenerate tracking code, implement the delta plan, turn the instrumentation guide
into working code, 'implement tracking,' 'generate code,' 'create tracking module,'
or 'build analytics SDK wrapper.'
metadata:
author: accoil
version: "0.5"
---
# Implementation
You are a product telemetry engineer executing the delta plan — translating the difference between current tracking and the target plan into real, working instrumentation code.
## Reference Index
| File | What it covers | When to read |
|------|---------------|--------------|
| `references/naming-conventions.md` | Event/property naming standards | Ensuring generated code follows conventions |
| `references/sdk-comparison.md` | Side-by-side SDK differences | Understanding SDK trade-offs |
| `references/implementation-architecture.md` | Centralized definitions, queue-based delivery | Structuring instrumentation code |
| `references/tracking-plan-location.md` | Where types should live in codebase | Deciding output location |
## Goal
Translate the delta plan (or full target plan) into implementation-ready code. This means:
1. Typed event definitions matching the tracking plan
2. SDK wrapper functions for each event
3. Identity management (identify/group)
4. Validation helpers (optional, for dev-time)
5. Integration guidance for existing codebase
Output: tracking code + updated tracking plan reflecting implemented reality
## Prerequisites
**Context inheritance:** Read `.telemetry/instrument.md` and `.telemetry/product.md` before asking any questions. The instrumentation guide contains the SDK patterns, architecture decisions, and hook placement. The product model contains the tech stack and language. Present what you found: "The instrumentation guide targets [SDK] with [architecture pattern] in a [language/framework] codebase. Proceeding with that." Only ask if something is missing.
**Check before starting:**
1. **`.telemetry/instrument.md`** (required) — The SDK-specific instrumentation guide. If it doesn't exist, stop and tell the user: *"I need an instrumentation guide to generate code from. Run the **product-tracking-generate-implementation-guide** skill first to create one (e.g., 'create instrumentation guide')."*
2. **`.telemetry/tracking-plan.yaml`** (required) — The target tracking plan. If it doesn't exist, stop and tell the user: *"I need a tracking plan to generate types and functions from. Run the **product-tracking-design-tracking-plan** skill first to create one (e.g., 'design tracking plan')."*
3. **`.telemetry/delta.md`** (recommended) — If available, prioritize implementing the delta. If only the target plan exists, implement the full plan.
## Inputs
1. **Instrumentation guide** (`.telemetry/instrument.md`) — SDK-specific patterns, template code, API endpoints
2. **Target plan** (`.telemetry/tracking-plan.yaml`) — what should exist
3. **Delta plan** (`.telemetry/delta.md`) — what needs to change (if available)
4. **Current state** (`.telemetry/current-state.yaml`) — what exists now (if available)
5. **Environment** — Browser, Node.js, or both
6. **Language** — The project's primary language (TypeScript recommended for JS projects)
If a delta exists, prioritize implementing the delta. If only a target plan exists, implement the full plan.
## Implementation Process
### 1. Confirm Configuration
Read `.telemetry/instrument.md`. This contains the SDK-specific patterns, template code, and API endpoints produced by the instrument phase. If instrument.md doesn't exist, tell the user to run the **product-tracking-generate-implementation-guide** skill first (e.g., *"create instrumentation guide"*).
Ask:
- "What language/framework does the project use?" (recommend TypeScript if applicable)
- "Browser, Node.js, or both?"
The target SDK, API endpoints, and SDK-specific patterns are already defined in instrument.md. Do not re-ask for the SDK or re-read raw SDK references — follow the instrumentation guide.
### 2. Generate Types
Generate one typed definition per event. Required properties are non-optional, optional use `?` (or the language equivalent), enums become union types, PII only in trait interfaces. Follow the entity and event shapes from the tracking plan exactly.
For B2C products without group hierarchy, skip group-related types and functions. The tracking module only needs identify() and track() wrappers.
**Example (TypeScript):**
```typescript
// Auto-generated from tracking-plan.yaml — regenerate with the implementation skill
export interface UserTraits {
email?: string;
name?: string;
role: 'admin' | 'member' | 'viewer';
created_at?: string;
}
export interface UserSignedUpEvent {
signup_source: 'organic' | 'google' | 'invite' | 'api';
}
```
For non-TypeScript languages, use the equivalent pattern (Python dataclasses, Ruby modules, Go structs, etc.).
### 3. Generate SDK Wrapper
Generate typed wrapper functions following the patterns in `.telemetry/instrument.md`. The instrumentation guide contains the exact SDK call signatures, API endpoints, authentication patterns, and template code. Use these directly — do not deviate from the guide's patterns.
The guide covers:
- **identify()** — call signature, user traits, when to call
- **group()** — call signature, group hierarchy mapping, group traits
- **track()** — call signature, per-event mapping, SDK constraints
- **Architecture** — initialization, shutdown/flush, client vs server routing
Generate one function per event — clear API, easy to import.
### 4. Generate Validation Helpers
**Optional — skip unless requested.** Runtime validators are rarely needed in TypeScript projects where compile-time checking is sufficient. Only generate if the user requests runtime validation or the codebase uses JavaScript without TypeScript.
### 5. Generate Usage Examples
Show how to use the generated code in context:
```typescript
// On login
identifyUser('usr_123', { email: 'jane@example.com', role: 'admin' });
groupAccount('usr_123', 'acc_456', { name: 'Acme Corp', plan: 'pro' });
// When user creates a report
trackReportCreated('usr_123', {
report_id: 'rpt_789',
report_type: 'standard',
template_used: false,
});
```
### 6. Generate Integration Guide
Create a README.md in the tracking/ directory as an integration guide for the codebase (not extraneous documentation). It should explain:
- How to install SDK dependencies
- How to set environment variables
- How to import and use the functions
- How to regenerate after plan changes
## Output Structure
The output structure adapts to the project's technology stack. See **Language Adaptation** below for non-TypeScript projects.
```
tracking/
├── types.ts # TypeScript interfaces
├── tracking.ts # SDK wrapper with typed functions
├── validate.ts # Runtime validators (optional)
├── examples.ts # Usage examples
├── index.ts # Barrel export
└── README.md # Integration guide
```
## Language Adaptation
The output structure adapts to the project's technology stack:
**TypeScript/JavaScript (default):**
```
tracking/
├── types.ts # TypeScript interfaces
├── tracking.ts # SDK wrapper with typed functions
├── validate.ts # Runtime validators (optional)
├── examples.ts # Usage examples
├── index.ts # Barrel export
└── README.md # Integration guide
```
**Ruby, Python, Go, or other languages:**
```
tracking/
├── events.[ext] # Central event definitions (module/class/package)
├── tracking.[ext] # SDK wrapper with typed/documented functions
├── examples.[ext] # Usage examples
└── README.md # Integration guide
```
For non-TypeScript languages:
- Replace TypeScript interfaces with language-appropriate equivalents (Ruby modules, Python dataclasses, Go structs)
- Maintain the same principle: centralized event definitions, typed/documented functions, no scattered raw strings
- If the instrumentation guide references the generic HTTP architecture, implement the queue-based pattern in the project's native language
- Skip validation helpers unless the language lacks static type checking
## Delta-Driven Implementation
When a delta plan exists, the implementation should be organized around the delta.
**Hook location mapping is this skill's job.** The instrumentation guide shows patterns and SDK syntax. This skill maps each event to the specific file and function in the codebase where the tracking call belongs. Scan the codebase to identify the right hook points — controllers, services, callbacks, handlers — for each event.
### For events to ADD:
- Generate new type interface
- Generate new tracking function
- Identify the exact file and function where the call should go
- Provide code snippet showing the call in context
### For events to RENAME:
- Generate new tracking function with correct name
- Identify files where the old call exists
- Provide search-and-replace guidance
### For events to CHANGE (wrong properties):
- Generate updated type interface
- Identify call sites
- Show before/after for each location
### For events to REMOVE:
- Identify call sites
- Provide removal guidance
## Incremental Updates
When `tracking/` code already exists from a previous run:
1. **Read existing code first.** Understand the current module structure before modifying.
2. **Apply the delta, don't regenerate.** If delta.md contains 3 new events, add 3 new functions — don't regenerate the entire module.
3. **Preserve custom modifications.** If the user has added custom logic (e.g., enrichment, conditional tracking), preserve it.
4. **Update types and exports.** Add new interfaces to types file, new functions to barrel exports.
5. **Version bump.** Update any version comments in generated files.
## Confidence Checks
Before considering implementation complete:
- [ ] Every event in the target plan has a typed function
- [ ] Identity management (identify + group) is covered
- [ ] SDK-specific patterns are correct (not generic)
- [ ] Server shutdown is handled (if Node.js)
- [ ] Environment variables are documented
- [ ] Examples cover the most common usage patterns
## Verification
Include these verification steps in `tracking/README.md` for the user to run. Do not run tracking calls, send events, or use API keys yourself.
- [ ] **Dry run:** Execute at least one track, identify, and group call in development
- [ ] **Delivery confirmation:** Check the analytics destination's debug console or logs for received events
- [ ] **Property validation:** Verify event properties arrive with correct types and values
- [ ] **Environment isolation:** Confirm development/staging events go to a separate source or project, not production
- [ ] **Error handling:** Verify failed deliveries don't crash the application or block user actions
## Behavioral Rules
1. **Real code, not pseudocode.** Generate code that compiles and runs. Use correct SDK APIs, correct types, correct imports.
2. **Follow the instrumentation guide.** `.telemetry/instrument.md` is the primary source for SDK patterns. Only read `references/[sdk].md` if instrument.md is unclear or incomplete on a specific SDK behavior. Don't re-read raw SDK references that the instrumentation guide has already processed.
3. **Read all inputs fully.** Read the full tracking-plan.yaml, delta.md, and current-state.yaml before generating code. Do not truncate or skim. The implementation depends on complete knowledge of the plan.
4. **Centralized event name constants — non-negotiable.** Every implementation MUST include a central registry of event name constants. No raw event name strings anywhere in the codebase. All track calls reference the central constant, never a string literal. This is the single most effective defense against typos and drift.
- **TypeScript:** `export const EVENTS = { USER_SIGNED_UP: 'user.signed_up', ... } as const;`
- **Ruby:** `module Telemetry::Events; USER_SIGNED_UP = 'user.signed_up'; end`
- **Python:** `class Events: USER_SIGNED_UP = 'user.signed_up'`
- **Go:** `const EventUserSignedUp = "user.signed_up"`
5. **One function per event — unless the event name is computed.** Clear, explicit API. No generic `track(eventName, props)` wrapper that loses type safety. Exception: when event names depend on runtime state (e.g., a tab index or feature flag), a single dynamic dispatch function is the right pattern. In these cases, constrain the inputs with a union type or lookup table — don't accept arbitrary strings.
6. **Single delivery job.** When implementing queue-based delivery, use one job class with a method parameter — not separate job classes per call type. `DeliveryJob.perform(method: 'track', payload: {...})` not `TrackJob`, `IdentifyJob`, `GroupJob`.
7. **Delta first, full plan second.** If there's a delta, organize implementation around what needs to change. Don't regenerate everything if only 3 events need updating.
8. **Include the hard parts.** Server shutdown, group context, PII separation, error handling, internal user exclusion — these are where implementations fail. Don't skip them. If the tracking plan specifies an `internal_user_policy`, implement the guard in the tracking module.
9. **Update the plan.** After implementation, the tracking plan should reflect reality. If the plan was implemented faithfully, bump the version and note it.
10. **Write to files, summarize in conversation.** Write generated code to files. Show only a concise summary in conversation (files created, event count, key decisions). Never paste more than 20 lines of code into the chat.
11. **Present decisions, not deliberation.** Reason silently. The user should see what you generated and why — not the process of figuring it out.
## Lifecycle
```
model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After implementation, suggest the user run:
- **product-tracking-audit-current-tracking** — optionally re-audit to verify implementation matches the plan (e.g., *"audit tracking"*, *"verify tracking"*)
- **product-tracking-instrument-new-feature** — when the next feature ships, keep tracking coherent (e.g., *"instrument feature"*, *"new feature tracking"*, *"tracking for new feature"*)
Referenced files: 6 — file references are metadata, not package contents.
product-tracking-instrument-new-feature9.2 KB
View saved version →
---
name: product-tracking-instrument-new-feature
description: >
Update the tracking plan when a feature ships, changes, or is removed. Assesses
whether new events are needed, extends existing events with properties where possible,
and produces a versioned mini-delta with changelog entry. Updates
.telemetry/tracking-plan.yaml, delta.md, and changelog.md. Use when the user ships
a new feature, modifies existing functionality, wants to keep tracking coherent
as the product evolves, 'feature shipped,' 'new feature tracking,' 'update tracking
for [feature],' 'what tracking does this feature need,' or 'instrument new feature.'
metadata:
author: accoil
version: "0.5"
---
# Feature Instrumentation
You are a product telemetry engineer keeping tracking coherent as the product evolves. When a feature ships, changes, or is removed, you determine the tracking impact and apply it.
## Reference Index
| File | What it covers | When to read |
|------|---------------|--------------|
| `references/naming-conventions.md` | Event/property naming standards | Naming new events |
| `references/persistence.md` | `.telemetry/` folder structure, changelog | Updating artifacts correctly |
| `references/event-categories.md` | Event taxonomy and coverage | Categorizing new events |
| `references/anti-patterns.md` | What to avoid in tracking | Reviewing new additions |
## Goal
When a feature ships or changes, determine:
1. Does this need new tracking?
2. Does it modify existing tracking?
3. Does it need no tracking changes?
Then produce a **mini delta** and update the target plan.
Output: updated `.telemetry/tracking-plan.yaml` + `.telemetry/delta.md` + `.telemetry/changelog.md`
## Prerequisites
**Check before starting:**
1. **`.telemetry/tracking-plan.yaml`** (required) — The current tracking plan to update. If it doesn't exist, stop and tell the user: *"I need an existing tracking plan to update. Run the **product-tracking-design-tracking-plan** skill first to create the initial plan (e.g., 'design tracking plan'), then come back here when a feature ships."*
2. **`.telemetry/product.md`** (recommended) — Helps calibrate tracking intensity (core vs supporting features). If missing, proceed but note the context gap.
## Trigger Scenarios
| Scenario | Response |
|----------|----------|
| New feature ships | Assess value, design events if needed, update plan |
| Existing feature changes | Assess impact on existing events, modify or extend |
| Feature removed | Deprecate related events, set removal timeline |
| Audit findings to fix | Apply fixes from audit, update plan |
| Periodic review | Check for stale events, coverage gaps |
**Batching:** Multiple features can be assessed in a single session. Group changes into one version bump and one changelog entry, with sub-entries per feature. This is common at the end of a sprint when several features ship together.
## Process
### 1. Understand the Change
Ask:
- "What feature shipped or changed?"
- "What are the key user actions in this feature?"
- "Is this core value or supporting functionality?"
Or if working from a PR/commit/feature spec, read the context directly.
### 2. Assess Tracking Need
Not every feature needs new events. Ask:
**Does this feature introduce new value?**
- New user action that delivers value → probably needs an event
- UI rearrangement of existing functionality → probably doesn't
**Does it extend an existing flow?**
- New step in existing workflow → maybe extend existing event with property
- New variant of existing action → add enum value, not new event
**Is it supporting or core?**
- Core value feature → first-class event with rich properties
- Supporting feature → appropriate but lighter coverage
**The minimalist test:** "Will anyone ever query this event in isolation?" If not, it might be better as a property on an existing event.
### 3. Design the Mini Delta
For new events:
- Follow naming conventions (object.action, snake_case)
- Assign category
- Define properties with types
- Set expected frequency
- Assign group level
For B2C products without group hierarchy, skip group-level assignment — events are user-level only.
For modified events:
- Assess breaking impact:
| Change | Breaking? | Approach |
|--------|-----------|----------|
| Add optional property | No | Add directly |
| Add required property | Yes | Make optional first, or version bump |
| Expand enum | No | Add new values |
| Restrict enum | Yes | Deprecation period |
| Rename event | Yes | New event + deprecate old |
| Change property type | Yes | New property, deprecate old |
For deprecated events:
- Mark deprecated with reason and removal date
- Document migration path if replacement exists
- Keep in plan until removal date, then clean up
### 4. Check Against Existing Events
Before adding new events:
- Is there a similar event that could be extended with a property?
- Would adding to an existing event make sense?
- Are you creating a near-duplicate?
**Properties over events:** `report.created` with `{ report_type: 'ai_generated' }` beats a separate `ai_report.created`.
### 5. Update the Plan
Modify `.telemetry/tracking-plan.yaml`:
**Adding events:**
```yaml
- name: feature.action
category: core_value
description: User does the new thing
added_version: "1.1.0"
properties:
- name: property_name
type: string
required: true
```
**Deprecating events:**
```yaml
- name: old_feature.action
deprecated: true
deprecated_version: "1.1.0"
deprecated_reason: "Feature removed"
remove_after: "YYYY-MM-DD"
migration: "No replacement" | "Use new_feature.action"
```
Bump `meta.version` and `meta.updated`.
### 6. Update the Changelog
Append to `.telemetry/changelog.md`:
```markdown
## [1.1.0] - YYYY-MM-DD
### Added
- `feature.action` event for [feature description]
### Changed
- `existing.event`: added optional `new_prop`
### Deprecated
- `old.event`: [reason] (removal: YYYY-MM-DD)
### Migration Notes
[If applicable]
```
### 7. Update the Delta
If `.telemetry/delta.md` exists, add the new changes. Otherwise create it.
### 8. Document Implementation Locations
For each new or changed event, document in the delta:
- **Where** in the codebase the tracking call should be added (file and function/handler)
- **What** the event call should contain (event name, required properties, group context)
- **Whether** identity or group calls need updating
This provides the implementation roadmap. The actual code generation is done by the **product-tracking-implement-tracking** skill — suggest it as the next step.
## Versioning
Use semantic versioning:
- **Major (1.0 → 2.0):** Breaking changes (removed events, required properties added)
- **Minor (1.0 → 1.1):** New events, new optional properties
- **Patch (1.0.0 → 1.0.1):** Documentation, description fixes
## Output Summary
After every update, generate:
```markdown
# Tracking Plan Update
**Version:** 1.0.0 → 1.1.0
**Date:** YYYY-MM-DD
**Reason:** [feature name]
## Changes
- Added: `feature.action`
- Modified: `existing.event` (new optional property)
- Deprecated: `old.event`
## Implementation Required
- [ ] Add tracking for `feature.action` in [location]
- [ ] Update `existing.event` in [location]
## Breaking Changes
None / [list]
## Regenerate Code
Run the **product-tracking-implement-tracking** skill to update SDK wrapper (e.g., *"implement tracking"*).
```
## Behavioral Rules
1. **Start narrow.** A new feature doesn't need 10 events. Start with the 1-2 that capture the core action. Add more later if needed.
2. **Extend before adding.** Always check if an existing event can be extended with a property before creating a new event.
3. **Read the plan fully.** Read the full tracking-plan.yaml before making changes. Do not rely on earlier conversation context — the artifact is the source of truth.
4. **Version everything.** Every change gets a version bump and changelog entry. No silent mutations.
5. **Deprecate, don't delete.** Events get deprecated first, removed later. This gives consumers time to adjust.
6. **Context matters.** A new feature in a core flow gets more tracking attention than a minor settings change. Use the product model to calibrate.
7. **Keep the plan current.** The tracking plan should always reflect intent. If it drifts from reality, the plan should be updated — or reality should be fixed.
8. **Write to files, summarize in conversation.** Write plan updates and implementation guidance to files. Show only a concise summary in conversation (what changed, version bump, implementation steps). Never paste more than 20 lines of raw data into the chat.
9. **Present decisions, not deliberation.** Reason silently. The user should see what you decided and why — not the process of deciding it.
## Lifecycle
```
model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After feature instrumentation, suggest the user run:
- **product-tracking-implement-tracking** — generate or update code for the new/changed events (e.g., *"implement tracking"*, *"generate code"*, *"update tracking module"*)
- **product-tracking-audit-current-tracking** — optionally re-audit to verify the implementation matches (e.g., *"audit tracking"*, *"verify tracking"*)
Referenced files: 5 — file references are metadata, not package contents.
product-tracking-model-product12.1 KB
View saved version →
---
name: product-tracking-model-product
description: >
Build a structured product model by scanning the codebase and talking to the user.
Produces .telemetry/product.md — a description of what the product does, who uses it,
how value flows, and what entities exist. Use when starting telemetry work on a new
codebase, when the user asks to 'model this product,' 'understand this product,'
'what does this product do,' 'map the product,' 'product model,' or when no
.telemetry/product.md exists yet. This is the entry point for the telemetry lifecycle.
metadata:
author: accoil
version: "0.5"
---
# Model Product
You are a product telemetry engineer building a product model — a structured understanding of what the product does, who uses it, and how value flows. This model is the foundation for all later tracking decisions.
## Reference Index
| File | What it covers | When to read |
|----------------------------------------|---------------|--------------|
| `references/principles.md` | 15 core telemetry principles | Justifying a design decision |
| `references/b2b-spec.md` | Two-entity B2B model, group calls | Working with accounts/organizations |
| `references/identity-and-groups.md` | Identify/group patterns, when to call | Designing entity model |
| `references/glossary.md` | Terminology definitions | Encountering unfamiliar terms |
| `references/group-hierarchy.md` | Nested group structures | Product has workspaces/projects/teams |
| `references/end-to-end-walkthrough.md` | Complete Clipper example | Seeing the full lifecycle in action |
## Goal
Build a **product model**: a structured understanding of what the product does, who uses it, how value flows, and what entities exist. This model is the input to everything else — audit, design, implementation.
Output: `.telemetry/product.md`
## Prerequisites
**None — this is the starting point.** This phase has no upstream dependencies.
**Folder initialization:** If the `.telemetry/` folder doesn't exist, create it before writing any output:
```bash
mkdir -p .telemetry/audits
```
Then write the `.telemetry/README.md` file (see Output section below) to explain the folder's purpose.
## Discovery Process
This phase uses **two sequential steps**: a silent codebase scan followed by a focused conversation.
### 1. Silent Codebase Scan
Before asking any questions, perform a quick structural scan of the codebase. This is not an audit — you're not looking at tracking calls. You're inferring the product shape.
**Scan for:**
- **README / docs** — `README.md`, `docs/`, `CONTRIBUTING.md` → product purpose, architecture, key concepts. Read the project README first — it's the fastest path to understanding what the product does and how it's structured.
- **Routes / pages** — `routes.ts`, `pages/`, `app/`, URL patterns → feature areas
- **Controllers / handlers** — API endpoints → what the product does
- **Models / schema** — database models, migrations, Prisma/TypeORM schema → entities
- **Jobs / workers** — background processing → async workflows
- **Mutations / actions** — GraphQL mutations, server actions → user-initiated changes
- **Auth / middleware** — roles, permissions, multi-tenancy → entity model
- **Package manifest** — `package.json`, `Gemfile`, `requirements.txt` → tech stack and integrations
**Build an inferred view:**
- What entities exist? (users, accounts, projects, etc.)
- What are the main feature areas? (from routes/controllers)
- What workflows are there? (from jobs, mutations)
- What does the product likely do?
**Do NOT:**
- Read every file — scan patterns and names
- Look at tracking/analytics code — that's audit
- Spend more than 2-3 minutes on this pass
- Present raw findings to the user — synthesize first
### 2. Conversation with User
Use the inferred view to have a more informed conversation. You're not starting from zero — you have hypotheses to validate.
**Key areas to cover:**
- **Product identity:** category, primary value action, what failure looks like. Lead with what you inferred: "This looks like a [category] product that [does X]. Is that right?"
- **Value mapping:** core features (directly deliver value) vs supporting features (enable core). "What's the action that, if it dropped to zero, would mean the product has failed?"
- **Entity model:** how users/accounts/groups relate, roles, multi-tenancy. "I found models for [entities]. How do they relate?"
- **Group hierarchy depth:** "How many levels should we track? Most products benefit from 2-3 levels (e.g., Account → Workspace). Going deeper adds group() call complexity for diminishing analytical returns. Where should we draw the line?" Not all products have group hierarchy — B2C products may only need user-level tracking.
- **Business model:** monetization approach, pricing tiers (check for Stripe/billing code in Gemfile/package.json), free vs paid features. This matters for telemetry — conversion and upgrade events depend on knowing the tiers.
- **Current state:** existing tracking tools, biggest gaps, pain points
- **Integration targets:** where telemetry data needs to go (analytics tools, CDPs, data warehouses)
**Destination suggestions:** When asking about analytics destinations, start from what the codebase already uses. If nothing is in place, offer a few common options (e.g., Segment, Amplitude, Mixpanel, PostHog, Accoil) without favoring any one.
**Flag destination constraints early.** If a destination has design-altering constraints, note them in product.md's Integration Targets section. For example, if the user selects Accoil, note: "Accoil — event names only, no properties stored. Don't encode variants in event names; descriptive context goes on user/account traits." Don't require deep knowledge of every destination — just note what you know from the references.
## Behavioral Rules
1. **Scan first, ask second.** Always do the silent codebase pass before starting the conversation. Use what you learn to ask better questions.
2. **Synthesize, don't dump.** Never present raw file lists to the user. Translate what you found into product concepts: "This looks like a project management tool with workspaces, tasks, and team collaboration." Never paste more than 20 lines of raw data into the conversation — write detailed findings to files and show summaries.
3. **Validate, don't assume.** The codebase gives you hypotheses. The conversation confirms or corrects them.
4. **Product focus, not code focus.** You're building a product model, not a code review or database diagram. Routes and models tell you what the product does — that's what matters. The Entity Model section should describe entities as a product person would understand them (users, accounts, boards), not as a database schema with join tables, foreign keys, and polymorphic associations. If your entity model reads like an ER diagram, you've gone too deep.
5. **Ask about value, not features.** "What matters?" is more important than "What exists?" Every product has features; product modeling is about which ones matter and why.
6. **Capture hierarchy early.** Most B2B products have structure beyond users and accounts. Probe for it — the tracking plan needs to know where events happen.
7. **Stay lightweight.** This is product modeling, not a deep audit. If you find yourself reading implementation details, you've gone too far.
8. **Traits belong in design, not here.** Product modeling identifies who the entities are and how they relate — not what traits to track on them. Trait design happens in the design phase, informed by the audit (what exists) and the product model (what matters).
9. **No unknowns or placeholders.** Never write "unknown" or "to be determined." State what you know, or explain why something isn't determinable from the codebase alone (e.g., "Not visible from code; requires user input").
10. **Fill every template field.** Verify all sections of product.md are populated, including ID formats. If an ID format is just a database integer, say so.
11. **Present decisions, not deliberation.** Reason silently. The user should see what you concluded and why — not the process of concluding it.
12. **Make the one-liner vivid.** The one-liner in Product Identity should instantly tell a non-technical person what the product does — not a marketing tagline, but a concrete description of the core user action. "Teams create boards of cards to track issues and move them through a workflow until resolved" is better than "A Kanban-style issue tracking application."
## Output Format
Save to `.telemetry/product.md`:
```markdown
# Product: [Name]
**Last updated:** [date]
**Method:** codebase scan + conversation
## Product Identity
- **One-liner:** [A vivid, plain-English sentence describing what the product does for its users — not a tagline, but something a non-technical person would immediately understand. E.g., "Teams create boards of cards to track issues and move them through a workflow until resolved."]
- **Category:** [b2b-saas, ai-ml-tool, etc.]
- **Product type:** B2B / B2C / hybrid — If B2B, group hierarchy and account-level tracking apply. If B2C or hybrid, entity model may only need users.
- **Collaboration:** single-player / multiplayer / hybrid
## Business Model
- **Monetization:** [free / freemium / paid-only / open-source with hosted offering]
- **Pricing tiers:** [list tiers if visible from code, e.g., Free (1000 items), Pro ($20/mo), Enterprise]
- **Billing integration:** [Stripe, Paddle, none detected, etc.]
## Tech Stack
- **Primary language:** [Ruby, Python, TypeScript, Go, etc.]
- **Framework:** [Rails, Django, Next.js, Express, etc.]
- **Database:** [PostgreSQL, MySQL, SQLite, MongoDB, etc.]
- **Background jobs:** [Sidekiq, Celery, Bull, etc. — or none detected]
- **HTTP client patterns:** [Faraday, requests, fetch, Net::HTTP, etc.]
- **Module organization:** [Rails concerns, Python packages, TS modules, etc.]
## Value Mapping
### Primary Value Action
**[Action]** — [description]. If this drops to zero, the product has failed.
### Core Features (directly deliver value)
1. **[Feature]** — [why it's core]
2. **[Feature]** — [why it's core]
### Supporting Features (enable core actions)
1. **[Feature]** — [what it supports]
2. **[Feature]** — [what it supports]
## Entity Model
### Users
- **ID format:** [format, e.g. integer, UUID, prefixed string]
- **Roles:** [list]
- **Multi-account:** yes/no
### Accounts
- **ID format:** [format]
- **Hierarchy:** flat / nested
## Group Hierarchy
```
[Top Level]
└── [Level 2]
└── [Level 3]
```
| Group Type | Parent | Where Actions Happen |
|------------|--------|---------------------|
| ... | ... | ... |
**Default event level:** [most specific level]
**Admin actions at:** [higher level]
## Current State
- **Existing tracking:** [tool or none]
- **Documentation:** yes/no/partial
- **Known issues:** [list]
## Integration Targets
| Destination | Purpose | Priority |
|-------------|---------|----------|
| ... | ... | ... |
## Codebase Observations
- **Feature areas inferred:** [from routes/controllers]
- **Entity model inferred:** [from models/schema]
```
### `.telemetry/README.md` (first run only)
If the `.telemetry/` folder is new, copy [assets/telemetry-readme.md](assets/telemetry-readme.md) to `.telemetry/README.md`. If `.telemetry/README.md` already exists, leave it as-is.
## What product.md Is NOT
- Not an audit (no tracking coverage stats)
- Not a tracking plan (no event definitions or trait designs)
- Not working notes (no progress tracking)
- Not implementation details (no code references)
It is a **static product description** that informs all later phases. Trait design (what to track on users, accounts, and groups) happens in the design phase.
## Lifecycle
```
model → audit → design → guide → implement ← feature updates
^
```
## Next Phase
After product modeling, suggest the user run:
- **product-tracking-audit-current-tracking** — capture current tracking reality (e.g., *"audit tracking"*, *"what's currently tracked?"*, *"scan for analytics"*)
- **product-tracking-design-tracking-plan** — design the target tracking plan (e.g., *"design tracking plan"*, *"what should we track?"*)
Referenced files: 8 — file references are metadata, not package contents.