diff --git a/cowork/README.md b/cowork/README.md new file mode 100644 index 000000000..70bb628c8 --- /dev/null +++ b/cowork/README.md @@ -0,0 +1,68 @@ +# Cacheplane GTM — Cowork skill + +A single Claude Cowork skill that operates Cacheplane's GTM motion: weekly PostHog snapshots, lead triage, workstream scaffolding, and "where are we?" status questions. + +The skill is **project-local**. It isn't published to a marketplace. Install steps are manual and one-time per machine. + +## What's in this directory + +``` +cowork/ +├── README.md # This file. +└── gtm/ + └── SKILL.md # The single Cowork skill. Edit here; install copies/symlinks elsewhere. +``` + +## Install (one-time per machine) + +The skill ships as `cowork/gtm/SKILL.md`. To make it loadable by Cowork / Claude Code on your machine, register it as a user-level skill: + +```bash +mkdir -p ~/.claude/skills/gtm +cp cowork/gtm/SKILL.md ~/.claude/skills/gtm/SKILL.md +``` + +Or symlink it so edits in this repo flow through immediately: + +```bash +mkdir -p ~/.claude/skills/gtm +ln -sf "$(pwd)/cowork/gtm/SKILL.md" ~/.claude/skills/gtm/SKILL.md +``` + +Verify: open a Claude Code session in this repo and type `/gtm`. The skill should load and announce its responsibilities. + +## Invoke + +- `/gtm` — drops into the GTM operator. Examples of what to ask: + - *"Run the weekly snapshot procedure."* + - *"Triage these inbound leads against the qualified-lead definition."* + - *"Scaffold a new workstream spec for `posthog-experiments`."* + - *"Where are we on comparison pages?"* + +## Schedule (optional, one-time per machine) + +Cowork has no in-repo scheduling primitive. To run the weekly snapshot automatically every Monday at 9am, create a routine once per machine: + +```bash +/schedule create weekly-snapshot 'every Monday 9am' /gtm "run the weekly snapshot procedure" +``` + +The routine itself lives at the user/runtime layer; it is not committed to the repo. The instruction to create it lives here. + +## Update + +Edit `cowork/gtm/SKILL.md` in this repo. If you symlinked, the change is live immediately. If you copied, re-run the `cp` command after committing. + +## Why one skill, not a plugin + +- **One file to grok** — anyone reading the repo can see what GTM operations look like. +- **No plugin packaging ceremony** until the motion proves out and we want to ship it as `@ngaf/gtm-plugin` for other Angular agent startups to adopt. +- **No per-workstream subagents** until context bleed proves to be a problem. Splitting later is a one-day refactor. + +## See also + +- [gtm.md](../gtm.md) — durable strategy +- [docs/gtm/](../docs/gtm/) — operational docs (ICP, messaging, taxonomy) +- [docs/superpowers/specs/gtm/](../docs/superpowers/specs/gtm/) — per-workstream design specs +- [tools/posthog/README.md](../tools/posthog/README.md) — dashboards-as-code conventions +- [libs/telemetry/README.md](../libs/telemetry/README.md) — telemetry trust contract diff --git a/cowork/gtm/SKILL.md b/cowork/gtm/SKILL.md new file mode 100644 index 000000000..6e4a3ebf9 --- /dev/null +++ b/cowork/gtm/SKILL.md @@ -0,0 +1,117 @@ +--- +name: gtm +description: Cacheplane GTM operator. Use to run weekly PostHog snapshots, draft the Notes section, triage inbound leads against the qualified-lead definition, scaffold new workstream specs, and answer "where are we?" questions by reading gtm.md plus the latest report. Invoke any time GTM motion work is happening or the weekly cadence fires. +disable-model-invocation: false +allowed-tools: Read, Edit, Write, Bash(npm run posthog:*), Bash(npm run gtm:*), Bash(gh pr *), Bash(git *), Glob, Grep +--- + +# Cacheplane GTM operator + +You are the GTM operator for Cacheplane. You own the operational layer of the GTM motion. Strategy decisions live in `gtm.md` and the per-workstream specs; you execute against them. + +## What you own + +- **Durable strategy:** `gtm.md` +- **Operational docs:** `docs/gtm/icp.md`, `docs/gtm/messaging.md`, `docs/gtm/taxonomy.md` +- **Workstream specs:** `docs/superpowers/specs/gtm/*-design.md` +- **Workstream plans:** `docs/superpowers/plans/gtm/*.md` +- **Weekly snapshots:** `docs/gtm/reports/-weekly.md` +- **Dashboards-as-code:** `tools/posthog/{dashboards,insights,cohorts}/*.json` +- **Telemetry library:** `libs/telemetry/` + +Read `gtm.md` first on any invocation. It is the source of truth for category, ICP, phases, exit gates, and non-goals. + +## When invoked, identify the intent + +Common intents and the procedure to run: + +| Intent | Procedure | +|--------|-----------| +| "Run the weekly snapshot." | **Weekly snapshot procedure** | +| "Triage these leads." | **Lead triage procedure** | +| "Scaffold a new workstream." | **New workstream procedure** | +| "Where are we on X?" | **Status read procedure** | +| Something unclear | Ask one clarifying question, then proceed. | + +## Weekly snapshot procedure + +1. Run `npm run posthog:report` from the repo root. It writes a draft to `docs/gtm/reports/-weekly.md`. +2. Read the prior 4 weekly reports in `docs/gtm/reports/` for context. +3. Read the recent commits on the `main` branch (last 7 days) to understand what shipped. +4. Draft the **Notes** section at the bottom of the new report. Three bullets max. Each bullet: + - Names a metric that moved meaningfully (≥15% week-over-week or any new event lighting up). + - Names the likely cause if it correlates with a recent ship. + - Names one suggested follow-up if the signal is concerning. +5. Open a PR: `gh pr create --title "chore(gtm): weekly snapshot YYYY-MM-DD" --body `. +6. Wait for human review of the Notes section before merge. **Do not auto-merge.** + +If a previous weekly PR is still unmerged, **comment on the existing PR** with the new snapshot rather than opening a duplicate. + +## Lead triage procedure + +The qualified-lead v1 definition (canonical: `docs/gtm/icp.md` §Enterprise track): + +- Non-personal `email_domain` (rules out gmail/outlook/yahoo/protonmail/icloud/aol/yandex/hotmail/live). +- Non-empty `company` field. +- `track=enterprise` (the surface they came from). + +For each inbound lead provided: + +1. Verify the three criteria. If any fail, the lead is **unqualified for v1** (still respond personally, but don't count it). +2. For qualified leads: confirm `marketing:lead_qualified` fired in PostHog (server side). If it didn't, flag the enrichment pipeline as broken. +3. Suggest a personal reply that: + - Names what they're building back to them (extracted from the body). + - Offers one concrete next step: code sketch, 15-minute call, or a documented pattern that fits. + - Avoids calendar-first responses (the contract says "code, not a calendar invite"). +4. Record the lead in `docs/gtm/reports/-weekly.md` Notes if it's the first qualified lead from a new `source_page`. + +## New workstream procedure + +1. Confirm the workstream isn't already in `gtm.md §6` or `gtm.md §7`. +2. Run `/brainstorming` to design the new workstream spec. +3. Drop the resulting spec into `docs/superpowers/specs/gtm/--design.md`. +4. Add a row to `gtm.md §7` linking the new spec. +5. Run `/writing-plans` for the implementation plan. +6. The new workstream's dependencies should be respected — see the DAG in `2026-05-13-gtm-meta-design.md §6`. + +## Status read procedure ("where are we?") + +The repo is the source of truth, not §7. Read in this order: + +1. **`gtm.md §6`** — what phase are we in, what's the exit gate. +2. **`gtm.md §7`** — which workstreams exist (it's a static inventory). +3. **`docs/superpowers/specs/gtm/`** — which specs exist (filesystem truth). +4. **`docs/superpowers/plans/gtm/`** — which plans exist and their checkbox progress (filesystem truth). +5. **Latest report in `docs/gtm/reports/`** — what the metrics say. +6. **`tools/posthog/dashboards/`** — which dashboards exist (and check whether their `posthog_id` is non-null to confirm they're synced). + +Answer with a tight status: what phase, what's next, what's blocked. + +## Decision rules + +- **Never claim a task is done without checking the PostHog dashboard signal.** Phase exit gates require non-trivial signal for ≥7 days. Read the dashboard via `posthog:report` output before marking complete. +- **Never send raw lead message text to PostHog.** Only `message_length` and `message_empty` booleans. See `docs/gtm/taxonomy.md`. +- **Always preserve `source_page` + `cta_id` attribution chains** across surfaces. If you see an event missing the chain, fix the emitter, not the report. +- **Phase exit gates in `gtm.md §6` are blocking.** Don't start Phase 2 work if Phase 1 hasn't passed its gate. +- **Edit `gtm.md §7` by hand.** Don't try to regenerate it. The Cowork skill (you) is not authoritative for status — the filesystem and PostHog are. + +## Out of scope (do not do these) + +- Run paid acquisition campaigns. +- Pursue GitHub stars as a metric. +- Add telemetry to `@ngaf/*` browser packages by default. +- Instrument the smoke/demo app. +- Auto-commit weekly snapshots without human review of Notes. +- Publish this skill as a marketplace plugin without explicit user approval. +- Open PRs that change `gtm.md §1–6` or `docs/gtm/messaging.md` without a brainstorm — those are strategy edits, not operational changes. + +## Reference + +- [../README.md](../README.md) — install instructions +- [../../gtm.md](../../gtm.md) — strategy +- [../../docs/gtm/icp.md](../../docs/gtm/icp.md) — ICP +- [../../docs/gtm/messaging.md](../../docs/gtm/messaging.md) — positioning, hero, comparison framing +- [../../docs/gtm/taxonomy.md](../../docs/gtm/taxonomy.md) — events, properties, CTA ids, redaction rules +- [../../tools/posthog/README.md](../../tools/posthog/README.md) — dashboards-as-code +- [../../libs/telemetry/README.md](../../libs/telemetry/README.md) — telemetry trust contract +- [../../docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md](../../docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md) — the meta-spec this skill operates against diff --git a/docs/gtm/icp.md b/docs/gtm/icp.md new file mode 100644 index 000000000..9bf3268e5 --- /dev/null +++ b/docs/gtm/icp.md @@ -0,0 +1,65 @@ +# ICP — Cacheplane + +> Operational doc. Edited by humans as we learn. The durable two-track ICP summary lives in [gtm.md §3](../../gtm.md). + +## Developer track + +**Buyer:** Angular engineer (senior / staff) actively building or evaluating an agent feature for a production Angular app. + +**Buying signals** +- Lands on a comparison page (`/compare/*`) from organic search or referral. +- Copies the install command (`hero_install` or `compare_*_install` CTA). +- Starts a cockpit recipe with a stack hint matching their backend (LangGraph, AG-UI, custom). +- Returns to the same comparison page within 7 days. +- Hits the six-signal activation funnel and drops off at "thread_persisted" or "interrupt_handled" — those drop-offs are the most actionable. + +These are the signals to instrument first in Spec 1. Baseline rates between them populate this section quantitatively once `developer-funnel` ships. + +**Disqualifiers** +- Greenfield app with no Angular constraint — Cacheplane is for teams that *must* stay on Angular. +- Hobby/learning project — we welcome them, but they aren't the ICP for prioritization. + +**Where they hang out** +- Angular Reddit, ng-conf community, Angular Discord/Slack equivalents, LangChain forum, AG-UI / A2UI communities, dev.to/medium. + +**What they need to see in 30 seconds** +- "Not another agent runtime. The Angular UI layer for LangGraph/AG-UI/A2UI." +- One install command. +- A working demo they can clone. + +## Enterprise track + +**Buyer:** Architect or engineering lead at an Angular-heavy company (SaaS, internal tools, fintech, healthcare, insurance, manufacturing, compliance-heavy workflows). + +**Buying signals** +- Already using LangGraph or evaluating an agent framework. +- React rewrite is politically or technically impossible. +- Has a defined design system and cannot ship arbitrary JSON-rendered components. +- 50+ engineers in the Angular org. + +**Disqualifiers** +- React-only frontend stack. +- "We'll figure out the UI later" — no committed agent project. +- Pure dev-tools company without an end-user-facing surface. + +**Qualified-lead v1 definition (server-side)** +- Non-personal `email_domain` (rules out gmail/outlook/yahoo). +- Non-empty `company` field. +- `track=enterprise` (the surface they came from). + +Tighten in Spec 7 if signal proves noisy. + +**Vertical priorities (initial)** +1. Fintech / insurance / compliance — strongest fit for human-approval flows. +2. Healthcare — adjacent compliance + design-system rigor. +3. Internal-tools-heavy SaaS — high agent-affinity, low channel cost. +4. Manufacturing — interesting fit for tool-call lifecycle UX. + +## What we do not yet know + +- Conversion rates between funnel stages (Spec 1 will produce baselines). +- Geographic distribution of qualified leads. +- Time from first `$pageview` to `lead_qualified` for the enterprise track. +- Average time-to-first-message for developer track (cockpit instrumentation needed). + +This document is updated when these become measurable. diff --git a/docs/gtm/messaging.md b/docs/gtm/messaging.md new file mode 100644 index 000000000..0f2f2a1f9 --- /dev/null +++ b/docs/gtm/messaging.md @@ -0,0 +1,75 @@ +# Messaging — Cacheplane + +> Operational doc. Hero copy, proof rows, comparison framing, launch lines. Edited by humans as we iterate. The durable category claim lives in [gtm.md §2](../../gtm.md). + +## Positioning statement (durable) + +> For Angular teams building AI agents on LangGraph, AG-UI, or custom backends, Cacheplane is the open-source agent UI framework that turns streaming agent events into production-grade Angular experiences: chat, tool progress, approvals, threads, generative UI, fallbacks, observability, and tests. Unlike React-first agent UI stacks or raw streaming SDKs, Cacheplane is signal-native, DI-friendly, design-system-first, self-hostable, and built for enterprise Angular apps. + +## Hero (locked for Spec 2 to implement) + +**H1:** Ship production agent UIs in Angular. + +**Subhead:** Signal-native chat, threads, interrupts, tool progress, and generative UI for LangGraph, AG-UI, and A2UI. MIT-licensed, self-hostable, opt-in telemetry, no React rewrite. + +**Primary CTA:** `Install @ngaf/chat` (copy-to-clipboard, fires `marketing:cta_click` with `cta_id=hero_install`, `track=developer`). + +**Secondary CTA:** `Talk to our engineers` (routes to `/contact?source=home_hero&track=enterprise`, fires `marketing:cta_click` with `cta_id=hero_talk_to_engineers`, `track=enterprise`). + +**Proof row:** `MIT · Angular-native Signals · LangGraph + AG-UI · A2UI-compatible · Self-hostable · Opt-in telemetry` + +**Subline under proof row:** *Not another backend agent runtime. Keep LangGraph, Genkit, Mastra, CrewAI, or your own service. Cacheplane solves the Angular UI layer.* + +## The five durable differentiation points + +Repeat across the site, comparison pages, and content. + +1. **Angular-native, not React-translated.** Signals, DI, OnPush, standalone components, Angular testing patterns, design-system ownership. +2. **Complete agent UI, not just stream plumbing.** Messages, status, errors, tool progress, interrupts, branching/history, thread persistence, reload, fallbacks, tests. +3. **Generative UI that respects the enterprise design system.** Approved components from your design system; no arbitrary code shipping. +4. **Enterprise OSS posture.** MIT, no end-user telemetry, no required cloud, self-hosting, optional paid support/SLA. +5. **Production patterns, not demo candy.** Real auth, real backends, observability, error boundaries, fallback strategies, CI/CD, load/chaos patterns, runbooks. + +## Risk-cleanup copy changes (Spec 2) + +- "No telemetry" → "**Opt-in telemetry**" with link to `libs/telemetry/README.md`. +- "All Angular versions" (pricing) → **real compatibility matrix** with supported/experimental/planned/unsupported. +- "A2UI v1" → **"A2UI v0.9-compatible"** until v1 is verified. +- "Angular Agent Framework" → **"Agent UI for Angular"** (category sweep, with care for substring overlap per existing memory note). + +## Contact page (Direction A.v2, locked) + +**Headline:** Talk to an engineer. + +**Subhead:** *Tell us what you're shipping. We'll reply within one business day — usually with code, not a calendar invite.* + +**SLA card:** *Brian or someone on the team replies personally — from a real inbox, not `noreply@`. We read every message.* + +**Alt-channel row (below form):** docs · GitHub issues · Discord. + +**Trust signal:** GitHub star count pill. No logo wall. + +**Fields:** email + free-text body. No stack dropdown, no company size, no "how did you hear." + +Hidden attribution fields (populated by URL params + referrer): `source_page`, `track`, `cta_id`, `paper`, `referrer_host`. + +## Comparison page framing (Spec 3) + +| Alternative | Cacheplane positioning vs. them | +|-----------------------|---------------------------------| +| `@langchain/angular` | "Use it for the stream. Use Cacheplane for the production Angular UI, design-system rendering, fallbacks, thread UX, testing, and enterprise patterns." | +| CopilotKit | "Broad agent frontend stack; Cacheplane is deeply Angular-native, signal/DI/design-system-first, optimized for enterprise Angular teams that don't want a React-first mental model." | +| Hashbrown | "Hashbrown is great for browser-running agents and LLM-driven frontend tools; Cacheplane is for LangGraph/AG-UI/A2UI-backed enterprise agent workflows with production chat, approvals, threads, observability, and runtime adapters." | +| A2UI renderer | "A2UI renderer support is table stakes; Cacheplane adds Angular app integration, fallback behavior, design-system registry patterns, thread/chat UX, and enterprise hardening." | + +## Launch narrative (Spec 6 spine) + +> Angular teams are building agents, but the last mile is still messy: streaming state, tool progress, interrupts, threads, generated UI, fallbacks, and tests. React has mature examples. Backend agent frameworks have protocols. Angular teams need something that speaks Signals, DI, templates, standalone components, and enterprise design systems. Cacheplane is an MIT-licensed agent UI framework for Angular that connects LangGraph, AG-UI, A2UI, and custom backends to production-ready Angular surfaces. + +## Avoid + +- "The Angular Agent Framework for LangChain." (Competes directly with `@langchain/angular`; narrows the story.) +- "Enterprise Angular agent framework." (Reads sales-first.) +- "We're building the React of Angular agents." (Doesn't land for our buyer.) +- Logo walls of unrelated F500s on the contact page. +- Progressive multi-step qualification forms. diff --git a/docs/gtm/taxonomy.md b/docs/gtm/taxonomy.md new file mode 100644 index 000000000..b8a253018 --- /dev/null +++ b/docs/gtm/taxonomy.md @@ -0,0 +1,138 @@ +# Event & Property Taxonomy — Cacheplane + +> Single source of truth for PostHog event names, properties, CTA ids, and surface ids. Implementation lands in `apps/website/src/lib/analytics/events.ts`, `apps/cockpit/src/lib/analytics/events.ts`, and `libs/telemetry/src/shared/events.ts`. Whenever those files change, this file changes. + +## Namespace rules + +Single PostHog project. Three event-name prefixes: + +| Prefix | Source | Notes | +|--------------|---------------------------------|---------------------------------------------| +| `marketing:` | `apps/website` | Carried forward from May-2 instrumentation plan. | +| `cockpit:` | `apps/cockpit` | Activation surface. New in Spec 1. | +| `ngaf:` | `libs/telemetry` | Library telemetry. Opt-out node, opt-in browser. | +| `docs:` | `apps/website` (docs surface) | Subset of website events scoped to docs interactions. Distinguished by prefix for filtering convenience. | + +The standard PostHog `$pageview` event is used as-is across all three surfaces. + +## Naming rules + +- lowercase snake_case after the prefix (`marketing:lead_form_submit`, not `marketing:LeadFormSubmit`). +- Static event names. Vary via properties, not event names. +- One event per discrete user action. Submits, successes, failures are distinct events. +- Server-side events for conversion truth; client-side for journey signal. + +## Marketing (website) + +| Event | When | +|---------------------------------------------|---------------------------------------------------| +| `$pageview` | Automatic, every route | +| `marketing:cta_click` | Any tracked CTA | +| `marketing:external_link_click` | External outbound (github, npm, cockpit) | +| `marketing:whitepaper_download_click` | Direct PDF download click | +| `marketing:whitepaper_signup_submit` | Submit attempt | +| `marketing:whitepaper_signup_success` | Server 2xx | +| `marketing:whitepaper_signup_fail` | Server non-2xx or validation error | +| `marketing:lead_form_submit` | Submit attempt (any surface) | +| `marketing:lead_form_success` | Server 2xx | +| `marketing:lead_form_fail` | Server non-2xx | +| `marketing:lead_qualified` | Server-side enrichment passes (qualified-lead def) | +| `marketing:newsletter_signup_submit` | Submit attempt | +| `marketing:newsletter_signup_success` | Server 2xx | +| `marketing:newsletter_signup_fail` | Failure | +| `docs:search_submit` | Docs search invocation | +| `docs:search_result_click` | Result click | +| `docs:copy_prompt_click` | Prompt-copy button | +| `docs:copy_code_click` | Code-copy button | +| `docs:tab_select` | MDX tab change | +| `docs:sidebar_section_toggle` | Sidebar nav toggle | + +## Cockpit (activation surface) + +| Event | When | +|------------------------------------------------|--------------------------------------------------------| +| `cockpit:recipe_start` | Recipe page loaded with intent (`?source=` present) | +| `cockpit:install_command_copied` | Install command copied | +| `cockpit:transport_connected` | LangGraph/AG-UI/custom adapter wired in tour | +| `cockpit:chat_first_message` | First user message sent in cockpit chat | +| `cockpit:thread_persisted` | Thread saved (re-load demonstrated) | +| `cockpit:interrupt_handled` | Human-approval interrupt completed | +| `cockpit:generative_component_rendered` | One generative Angular component rendered | +| `cockpit:six_signals_complete` | All six signals fired within 30 min for one session | + +## ngaf (library telemetry) + +| Event | When | Surface | Default | +|--------------------------------------|--------------------------------------------|-----------------|--------------| +| `ngaf:postinstall` | `npm install` of an `@ngaf/*` package | Node (script) | **Opt-out** | +| `ngaf:runtime_instance_created` | Server adapter init | Node | **Opt-out** | +| `ngaf:runtime_request_created` | Server adapter handles a request | Node | **Opt-out** | +| `ngaf:stream_started` | Stream begins | Node | **Opt-out** | +| `ngaf:stream_ended` | Stream ends normally | Node | **Opt-out** | +| `ngaf:stream_errored` | Stream errors | Node | **Opt-out** | +| `ngaf:browser_provided` | `provideNgafTelemetry({enabled:true})` | Browser | **Opt-in** | +| `ngaf:browser_chat_init` | Browser chat surface initialized | Browser | **Opt-in** | + +Browser events never fire unless the consumer explicitly opts in. See `libs/telemetry/README.md` for the trust contract. + +## Shared properties + +| Property | Type | Notes | +|------------------|--------|-------------------------------------------------------------| +| `source_page` | string | Stable pathname or surface id (`home`, `compare_langchain_angular`, `pricing`). | +| `source_section` | string | Stable section/component id where known. | +| `surface` | enum | `nav` `mobile_nav` `footer` `home` `pricing` `docs` `library_landing` `solution` `toast` `cockpit` `contact` | +| `destination_url`| string | Clicked URL where applicable. | +| `cta_id` | string | Stable CTA id (see below). | +| `cta_text` | string | Visible label where stable. | +| `track` | enum | `developer` `enterprise` `pricing` `pilot` | +| `paper` | enum | `overview` `angular` `render` `chat` | +| `library` | enum | `agent` `render` `chat` `unknown` | +| `email_domain` | string | Extracted server-side. Never raw email in client events. | +| `company` | string | Server-side only, on conversion events, if approved. | +| `is_success` | bool | Generic success flag for wrapper events. | +| `failure_reason` | string | Short stable code on failure events. | +| `referrer_host` | string | Sanitized host of HTTP referrer. | +| `message_length` | int | Lead form / whitepaper message length (never the content). | +| `message_empty` | bool | Whether the free-text body was empty. | + +## CTA ids (stable, lowercase snake_case) + +**Hero** +- `hero_install` — primary, copy-to-clipboard +- `hero_talk_to_engineers` — secondary, → `/contact` + +**Nav** +- `nav_get_started` `nav_docs` `nav_pricing` `nav_github` `nav_npm` `nav_cockpit` + +**Footer** +- `footer_github` `footer_npm` `footer_cockpit` `footer_pricing` `footer_pilot_to_prod` `footer_contact` + +**Comparison pages** (`/compare/`) +- `compare__install` — primary CTA on each comparison page +- `compare__talk_to_engineers` — secondary CTA on each comparison page +- `compare__view_demo` — link to cockpit recipe + +**Pricing & Pilot** +- `pricing_enterprise_lead` — pricing page form submit +- `pilot_book_call` — `/pilot-to-prod` form submit + +**Contact** +- `contact_send` — `/contact` form submit + +## Privacy & redaction rules + +- **Never send** raw lead form `message`, raw docs search query, copied code content, or any free-form customer text. +- **Always send** message *length* and *is_empty* booleans instead. +- **Email domains only** in client-side events; raw emails never leave the form. +- **Company** is server-side only, on conversion events. +- **Free-form lead body** is never forwarded to PostHog under any property name. +- Treat email, name, company, and any free-form customer text as sensitive. + +## Version + change log + +This file is human-edited. When events are added/renamed/removed, update the affected event-constant files in the same PR. CI guards `posthog:sync` will warn if a dashboard JSON references an event not listed here. + +| Date | Change | +|------------|--------| +| 2026-05-13 | Initial draft per Spec 0. | diff --git a/docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md b/docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md new file mode 100644 index 000000000..823ff7cef --- /dev/null +++ b/docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md @@ -0,0 +1,422 @@ +# GTM Meta Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Land the durable scaffolding for Cacheplane's GTM motion — `gtm.md` at repo root, operational docs under `docs/gtm/`, the Cowork skill under `cowork/`, and contract READMEs for `tools/posthog/` and `libs/telemetry/` — so future workstream specs can compose against a stable foundation. + +**Architecture:** Doc-scaffolding only. No code, no PostHog API calls, no website changes. The deliverables are eight markdown files plus a `.gitignore` line; their content was authored during the brainstorm and lives in the repo already. This plan validates the deliverables, smoke-tests the manual Cowork skill install, and commits. + +**Tech Stack:** Markdown, `gh`/`git`, the existing Claude Code skill loader at `~/.claude/skills/`. + +--- + +## File Structure + +All eight deliverables already exist on disk. No new files are created by this plan. The plan's job is to **verify shape and shipping**, not to author. + +- `docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md` — design (this plan implements it) +- `gtm.md` — durable strategy +- `docs/gtm/icp.md` — ICP doc +- `docs/gtm/messaging.md` — messaging doc +- `docs/gtm/taxonomy.md` — event/property taxonomy +- `tools/posthog/README.md` — dashboards-as-code conventions +- `libs/telemetry/README.md` — telemetry trust contract +- `cowork/README.md` — Cowork skill install instructions +- `cowork/gtm/SKILL.md` — the Cowork skill + +> `.gitignore` already covered `.superpowers/` (line 3, under `# Worktrees`) at the brainstorm start, so no `.gitignore` change is needed for this commit. + +--- + +### Task 1: Verify all deliverables exist + +**Files:** +- Check: all paths listed in File Structure above + +- [ ] **Step 1: List the eight deliverable files** + +Run: +```bash +ls -1 \ + gtm.md \ + docs/gtm/icp.md \ + docs/gtm/messaging.md \ + docs/gtm/taxonomy.md \ + tools/posthog/README.md \ + libs/telemetry/README.md \ + cowork/README.md \ + cowork/gtm/SKILL.md +``` + +Expected: each path prints; exit code 0. If any path is missing, stop and re-author the missing file from the meta-spec before continuing. + +- [ ] **Step 2: Verify `.gitignore` ignores `.superpowers/`** + +Run: +```bash +grep -E '^\.superpowers/?$' .gitignore +``` + +Expected: prints `.superpowers/`. If empty, append the line: +```bash +echo ".superpowers/" >> .gitignore +``` + +- [ ] **Step 3: Verify the meta-spec exists at the expected path** + +Run: +```bash +test -f docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md && echo OK +``` + +Expected: prints `OK`. + +--- + +### Task 2: Validate the meta-spec's plan frontmatter points at this plan + +The meta-spec frontmatter declares `plan: docs/superpowers/plans/gtm/gtm-meta.md`. This plan lives at `docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md`. Fix the spec frontmatter so it matches. + +**Files:** +- Modify: `docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md` (frontmatter only) + +- [ ] **Step 1: Confirm the mismatch** + +Run: +```bash +grep '^plan:' docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md +``` + +Expected output: `plan: docs/superpowers/plans/gtm/gtm-meta.md` + +- [ ] **Step 2: Update the frontmatter line** + +Edit `docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md` and replace: + +```yaml +plan: docs/superpowers/plans/gtm/gtm-meta.md +``` + +with: + +```yaml +plan: docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md +``` + +- [ ] **Step 3: Update §12 of the same spec to match** + +In the same file, find the §12 sentence: + +``` +The plan file at `docs/superpowers/plans/gtm/gtm-meta.md` will check off: +``` + +Replace with: + +``` +The plan file at `docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md` will check off: +``` + +- [ ] **Step 4: Verify the change** + +Run: +```bash +grep -n 'docs/superpowers/plans/gtm/' docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md +``` + +Expected: every match references `2026-05-13-gtm-meta.md`. No bare `gtm-meta.md` remains. + +--- + +### Task 3: Validate internal markdown links resolve + +The deliverables reference each other heavily. Broken links here propagate into Spec 1 quickly. Verify every relative markdown link resolves. + +**Files:** +- Check: all eight deliverables + the meta-spec + +- [ ] **Step 1: Extract all relative markdown links from the deliverables** + +Run: +```bash +for f in gtm.md docs/gtm/*.md tools/posthog/README.md libs/telemetry/README.md cowork/README.md cowork/gtm/SKILL.md docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md; do + echo "=== $f ===" + grep -oE '\]\(([^)]+)\)' "$f" | sed -E 's/\]\((.*)\)/\1/' | grep -vE '^(https?://|mailto:|#)' || true +done +``` + +Expected: a list of relative paths grouped by source file. Skim it. + +- [ ] **Step 2: Verify every relative link target exists** + +Run: +```bash +set -e +fail=0 +for f in gtm.md docs/gtm/*.md tools/posthog/README.md libs/telemetry/README.md cowork/README.md cowork/gtm/SKILL.md docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md; do + dir=$(dirname "$f") + while IFS= read -r link; do + target="${link%%#*}" + [ -z "$target" ] && continue + case "$target" in https://*|http://*|mailto:*) continue;; esac + if [ ! -e "$dir/$target" ]; then + echo "BROKEN: $f -> $target" + fail=1 + fi + done < <(grep -oE '\]\([^)]+\)' "$f" | sed -E 's/\]\((.*)\)/\1/') +done +exit $fail +``` + +Expected: no `BROKEN:` lines; exit code 0. If any link is broken, fix the source path in the offending file and re-run. + +--- + +### Task 4: Validate the Cowork skill frontmatter + +`cowork/gtm/SKILL.md` must have a valid Claude Code skill frontmatter so it loads when copied to `~/.claude/skills/gtm/SKILL.md`. + +**Files:** +- Check: `cowork/gtm/SKILL.md` + +- [ ] **Step 1: Verify frontmatter exists and has required keys** + +Run: +```bash +head -10 cowork/gtm/SKILL.md +``` + +Expected output (first 10 lines): +``` +--- +name: gtm +description: Cacheplane GTM operator. Use to run weekly PostHog snapshots, draft the Notes section, triage inbound leads against the qualified-lead definition, scaffold new workstream specs, and answer "where are we?" questions by reading gtm.md plus the latest report. Invoke any time GTM motion work is happening or the weekly cadence fires. +disable-model-invocation: false +allowed-tools: Read, Edit, Write, Bash(npm run posthog:*), Bash(npm run gtm:*), Bash(gh pr *), Bash(git *), Glob, Grep +--- +``` + +If the `name`, `description`, or `allowed-tools` lines differ materially, stop and re-author from the meta-spec §9.2. + +- [ ] **Step 2: Verify the body references the right procedures** + +Run: +```bash +grep -E '^## ' cowork/gtm/SKILL.md +``` + +Expected: at minimum these headings appear, in order: +- `## What you own` +- `## When invoked, identify the intent` +- `## Weekly snapshot procedure` +- `## Lead triage procedure` +- `## New workstream procedure` +- `## Status read procedure ("where are we?")` +- `## Decision rules` +- `## Out of scope (do not do these)` +- `## Reference` + +--- + +### Task 5: Smoke-test the Cowork skill install + +This is the manual install path documented in `cowork/README.md`. Confirms a fresh machine can pick up the skill. + +**Files:** +- Touched on local machine: `~/.claude/skills/gtm/SKILL.md` + +- [ ] **Step 1: Symlink the skill to the user's Claude Code skills directory** + +Run from the repo root: +```bash +mkdir -p ~/.claude/skills/gtm +ln -sf "$(pwd)/cowork/gtm/SKILL.md" ~/.claude/skills/gtm/SKILL.md +``` + +- [ ] **Step 2: Verify the symlink resolves** + +Run: +```bash +ls -l ~/.claude/skills/gtm/SKILL.md +test -L ~/.claude/skills/gtm/SKILL.md && readlink ~/.claude/skills/gtm/SKILL.md +``` + +Expected: the symlink prints with the repo path as its target. + +- [ ] **Step 3: Verify the content is reachable through the symlink** + +Run: +```bash +head -5 ~/.claude/skills/gtm/SKILL.md +``` + +Expected: prints the same first five lines as `head -5 cowork/gtm/SKILL.md`. + +- [ ] **Step 4: Type `/gtm` in a Claude Code session in this repo** + +Manual verification by the user. Expected: the skill loads and announces its responsibilities (the four procedures listed in `cowork/gtm/SKILL.md`). + +If the skill does not load, check that the symlink target file exists and that the frontmatter parses (no stray tabs, the `---` markers are on their own lines). + +--- + +### Task 6: Validate the dashboard slugs referenced in gtm.md match taxonomy.md + +The five dashboard slugs (`developer-funnel`, `enterprise-funnel`, `activation-six-signals`, `content-intent`, `package-telemetry`) appear in `gtm.md §5`, `tools/posthog/README.md`, and `docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md §6`. Confirm they're identical. + +**Files:** +- Check: `gtm.md`, `tools/posthog/README.md`, the meta-spec + +- [ ] **Step 1: Extract slugs from each file** + +Run: +```bash +echo "=== gtm.md ===" +grep -oE '`(developer-funnel|enterprise-funnel|activation-six-signals|content-intent|package-telemetry)`' gtm.md | sort -u +echo "=== tools/posthog/README.md ===" +grep -oE '(developer-funnel|enterprise-funnel|activation-six-signals|content-intent|package-telemetry)' tools/posthog/README.md | sort -u +echo "=== meta-spec ===" +grep -oE '(developer-funnel|enterprise-funnel|activation-six-signals|content-intent|package-telemetry)' docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md | sort -u +``` + +Expected: each section lists the same five slugs. No spelling variants. If a typo is found (e.g. `six-signal-activation` vs `activation-six-signals`), fix the source file so all three sections agree. + +--- + +### Task 7: Validate event namespace usage is consistent + +The three namespaces (`marketing:`, `cockpit:`, `ngaf:`) appear across `gtm.md`, `docs/gtm/taxonomy.md`, `libs/telemetry/README.md`, and the meta-spec. Confirm no stray events without prefixes and no fourth namespace. + +**Files:** +- Check: `gtm.md`, `docs/gtm/taxonomy.md`, `libs/telemetry/README.md`, the meta-spec + +- [ ] **Step 1: List all event-name-shaped strings (`prefix:snake_case`) across the docs** + +Run: +```bash +grep -hoE '\b(marketing|cockpit|ngaf|\$pageview)[a-z_:]*' \ + gtm.md docs/gtm/taxonomy.md libs/telemetry/README.md \ + docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md \ + | sort -u +``` + +Expected: every event starts with one of `$pageview`, `marketing:`, `cockpit:`, `ngaf:`. No bare `lead_form_*` or other unprefixed event-shaped tokens. If you see one, decide whether it's a deliberate stylistic shorthand inside `gtm.md §4` or a real omission, and fix accordingly. + +--- + +### Task 8: Commit the meta-spec deliverables atomically + +The work shipped during the brainstorm. One commit captures everything, makes Spec 1 a clean starting point, and gives `git blame` a single hash to point at. + +**Files:** +- Staged: all eight deliverables, the meta-spec, and this plan + +- [ ] **Step 1: Review what would be staged** + +Run: +```bash +git status --short +``` + +Expected: a list including `gtm.md`, `cowork/`, `docs/gtm/`, `docs/superpowers/specs/gtm/`, `docs/superpowers/plans/gtm/`, `libs/telemetry/README.md`, `tools/posthog/README.md`, and the `.gitignore` modification. No stray files outside the GTM scaffolding. + +- [ ] **Step 2: Stage the GTM scaffolding explicitly** + +Run: +```bash +git add \ + gtm.md \ + cowork/ \ + docs/gtm/ \ + docs/superpowers/specs/gtm/ \ + docs/superpowers/plans/gtm/ \ + libs/telemetry/README.md \ + tools/posthog/README.md +``` + +(`.gitignore` is not staged — `.superpowers/` was already ignored at the start of the brainstorm.) + +- [ ] **Step 3: Confirm staged diff** + +Run: +```bash +git diff --cached --stat +``` + +Expected: the eight deliverables + the meta-spec + this plan + the `.gitignore` change. Nothing else. If unexpected files appear, unstage them with `git restore --staged `. + +- [ ] **Step 4: Commit with a heredoc message** + +Run: +```bash +git commit -m "$(cat <<'EOF' +feat(gtm): scaffold durable GTM strategy + Cowork skill + +Establish the api/cli-first GTM foundation: + +- gtm.md at repo root: durable strategy (positioning, ICP, funnels, phases, + non-goals, cadence). +- docs/gtm/{icp,messaging,taxonomy}.md: operational docs (hand-edited). +- tools/posthog/README.md: dashboards-as-code conventions; implementation + lands in the analytics-foundation workstream. +- libs/telemetry/README.md: public trust contract for @ngaf/telemetry + (opt-out Node, opt-in browser, never default in @ngaf/* browser packages). +- cowork/README.md + cowork/gtm/SKILL.md: single Cowork skill that operates + the motion (weekly snapshots, lead triage, workstream scaffolding, + status reads). Manually installed; project-local; not a marketplace plugin. +- Meta-spec at docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md. +- This plan at docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md. + +No code, no PostHog API calls, no website changes. Subsumes the May-2 +PostHog instrumentation plan into the upcoming analytics-foundation spec. + +Co-Authored-By: Claude Opus 4.7 +EOF +)" +``` + +- [ ] **Step 5: Verify the commit landed** + +Run: +```bash +git log -1 --stat +``` + +Expected: the commit message above, with the file list matching Step 3's diff. + +--- + +### Task 9: Announce next workstream + +The meta-spec is shipped. The next workstream is `analytics-foundation` (Spec 1). It requires its own brainstorm → spec → plan cycle. + +- [ ] **Step 1: Surface the next step to the user** + +Print or say: +``` +Meta-spec shipped. Next: brainstorm Spec 1 (analytics-foundation). +Scope: dashboards-as-code infra, 5 PostHog dashboards, @ngaf/telemetry v0.0.1, +cockpit instrumentation. Reconciles with the May-2 instrumentation plan. +Run /brainstorming when ready. +``` + +Do not start the next brainstorm without user confirmation. + +--- + +## Self-Review + +**Spec coverage:** The meta-spec's §12 lists 9 deliverables (8 files + the `.gitignore` edit). Plan tasks cover them: Task 1 verifies existence of 8 deliverables and the `.gitignore` change; Task 2 corrects the spec's own plan-path frontmatter; Tasks 3, 4, 6, 7 validate cross-document consistency; Task 5 smoke-tests the manual Cowork install (the install path documented in `cowork/README.md`); Task 8 commits. Task 9 transitions to Spec 1. + +The meta-spec's §6 (workstream decomposition + DAG) is informational — no implementation task. ✓ +The meta-spec's §7 (analytics architecture) is informational — implementation lands in Spec 1. ✓ +The meta-spec's §8 (CTA fork) is informational — implementation lands in Spec 2. ✓ +The meta-spec's §9 (Cowork progress tracking) is implemented by `cowork/README.md` + `cowork/gtm/SKILL.md`, covered by Tasks 1, 4, 5. ✓ +The meta-spec's §10 (risks & non-goals) is informational. ✓ +The meta-spec's §11 (deferred workstreams) is informational. ✓ + +**Placeholder scan:** No `TBD`, `TODO`, "implement later", or "fill in details" strings remain in the plan. All commands are exact. All expected outputs are stated. ✓ + +**Type consistency:** No code in this plan; nothing to check. ✓ + +**Cross-document name consistency:** Tasks 6 and 7 explicitly check that dashboard slugs and event namespaces stay aligned. ✓ diff --git a/docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md b/docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md new file mode 100644 index 000000000..50a4f95db --- /dev/null +++ b/docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md @@ -0,0 +1,413 @@ +--- +workstream: gtm-meta +status: approved +owner: brian +phase: 0 +spec: docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md +plan: docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md +--- + +# GTM Meta — Design + +> Spec 0 of the Cacheplane GTM motion. Defines the shape of every other GTM spec: repo layout, sequencing, analytics architecture, progress tracking, and risks. No website copy changes, no PostHog API calls, no library code — those land in their own workstream specs. + +## 1. Goal + +Establish the durable scaffolding for an api/cli-first GTM motion: one strategy document (`gtm.md`), seven workstream specs that compose into four phases, a single PostHog project as the measurement surface, a `@ngaf/telemetry` library that preserves the "no end-user telemetry" trust claim, and a single Claude Cowork skill that operates the motion manually. + +## 2. Context + +- Cacheplane positions as **Production Agent UI for Angular** — not a backend agent runtime. The Angular final mile is the durable wedge. +- Existing PostHog instrumentation work landed partially: `apps/website/instrumentation-client.ts`, `apps/website/src/lib/analytics/*`, and a May-2 plan at `docs/superpowers/plans/2026-05-02-posthog-gtm-analytics.md` covering website event capture. This spec subsumes that plan into Spec 1; we do not re-spec event capture. +- The full strategy (positioning, ICP, phases, metrics, risks) is captured by the user in conversation and codified by this spec into `gtm.md`. +- "api/cli-first" = every artifact we build is machine-addressable: dashboards as JSON, telemetry as library, weekly reports as a CLI, GTM operations as a Cowork skill. No SaaS UI is the source of truth for anything. + +## 3. Scope + +**In scope (deliverables of Spec 0):** + +- `gtm.md` at repo root — durable strategy. +- `docs/gtm/{icp,messaging,taxonomy}.md` — operational doc skeletons. +- `tools/posthog/README.md` — dashboards-as-code conventions (implementation lands in Spec 1). +- `libs/telemetry/README.md` — telemetry trust contract (implementation lands in Spec 1). +- `cowork/README.md` + `cowork/gtm/SKILL.md` — the single Cowork skill, manually installable. +- This spec. + +**Out of scope:** website copy changes, PostHog dashboard JSON, telemetry library code, comparison pages, content pages, cockpit recipes, community launch artifacts, enterprise pipeline plumbing. Each lives in its own workstream spec. + +## 4. Repo layout + +``` +angular-agent-framework/ +├── gtm.md # Durable strategy. Top-level by design. +├── cowork/ +│ ├── README.md # Manual install instructions for the Cowork skill. +│ └── gtm/ +│ └── SKILL.md # The single Cowork skill — operates the GTM motion. +├── docs/ +│ ├── gtm/ +│ │ ├── icp.md # ICP definition (referenced by gtm.md §3). +│ │ ├── messaging.md # Positioning lines, hero variants, proof rows. +│ │ ├── taxonomy.md # Event/property/CTA-id taxonomy. Single source of truth. +│ │ └── reports/ # Weekly snapshots. Generated by `npm run posthog:report`. +│ └── superpowers/ +│ ├── specs/gtm/ # Per-workstream design specs. +│ │ ├── 2026-05-13-gtm-meta-design.md # This spec. +│ │ ├── 2026-05-13-analytics-foundation-design.md +│ │ ├── 2026-05-14-positioning-and-risks-design.md +│ │ ├── 2026-05-15-comparison-pages-design.md +│ │ ├── 2026-05-16-cockpit-activation-recipes-design.md +│ │ ├── 2026-05-17-content-pillar-pages-design.md +│ │ ├── 2026-05-18-community-launch-design.md +│ │ └── 2026-05-19-enterprise-pipeline-design.md +│ └── plans/gtm/ # Per-workstream implementation plans. +├── tools/posthog/ # Dashboards-as-code (PostHog Public API). +│ ├── sync.ts # Idempotent upsert. Implementation in Spec 1. +│ ├── report.ts # Weekly markdown export. Implementation in Spec 1. +│ ├── dashboards/*.json # One JSON per dashboard. +│ ├── insights/*.json +│ ├── cohorts/*.json +│ └── README.md # Conventions. +├── libs/telemetry/ # New @ngaf/telemetry library. +│ ├── src/{shared,node,browser}/ # Implementation in Spec 1. +│ └── README.md # User-facing trust contract. +├── apps/website/src/lib/analytics/ # Existing. Continues in Spec 1. +└── apps/cockpit/src/lib/analytics/ # New in Spec 1. Mirrors website analytics shape. +``` + +**Rationale:** + +- `gtm.md` is top-level alongside `README.md`. Discoverable, citable, version-controlled. +- `docs/gtm/` holds *operational living* docs. `docs/superpowers/specs/gtm/` holds *immutable plan-of-record*. Distinct directories prevent confusion about which is which. +- `tools/posthog/` is the api-first heart. Every dashboard is JSON. The CLI is the only way to make a dashboard. +- `libs/telemetry/` is a separate `@ngaf/*` package because (a) it ships to npm, (b) it's consumed by user apps, (c) its trust contract is different from website analytics. +- Cockpit analytics live in cockpit; no premature shared library. The shared artifact is the **taxonomy**, not a code lib. + +## 5. The `gtm.md` outline + +`gtm.md` is short, durable, hand-edited. Sections — full content drafted as part of this spec's deliverables, locked here at the section-title level: + +1. **What we are** — positioning statement. +2. **Category** — "Agent UI for Angular." Phrases to avoid. +3. **ICP** — two tracks (developer + enterprise), both addressed from the homepage via the CTA fork. Detailed personas in `docs/gtm/icp.md`. +4. **Funnel & activation** — two parallel funnels, sharing acquisition surfaces, diverging at the hero CTA. North-star activation milestone defined. +5. **Metrics** — index of dashboards (slugs in `tools/posthog/dashboards/`). Definitions in `docs/gtm/taxonomy.md`. Weekly snapshot in `docs/gtm/reports/`. +6. **Phases** — four phases (0 measurement, 1 developer clarity, 2 ecosystem path, 3 community launch, 4 enterprise design partners). Exit gates per phase. +7. **Workstream agents** — hand-edited inventory pointing into specs and dashboards. Not regenerated. Source of truth for *who owns what*; not for *what's done*. +8. **Non-goals** — explicit list to prevent scope creep. +9. **Cadence** — weekly snapshot via `/gtm` Cowork skill; monthly strategy review. +10. **References** — links to operational docs, CLIs, libraries, specs. + +## 6. Workstream decomposition + +Seven specs follow Spec 0. Dependencies form a DAG: + +``` +[0] gtm-meta + │ + ▼ +[1] analytics-foundation ──────┐ + │ │ + ▼ │ +[2] positioning-and-risks ─────┼────▶ [5] content-pillar-pages + │ │ │ + ▼ │ ▼ +[3] comparison-pages ──────────┘ [6] community-launch + │ │ + ▼ ▼ +[4] cockpit-activation-recipes [7] enterprise-pipeline +``` + +| # | Spec | Phase | Depends on | Exit | +|--:|------|------:|------------|------| +| 1 | analytics-foundation | 0 | — | 5 dashboards live, all 3 event namespaces emitting, `@ngaf/telemetry@0.0.1` published, weekly report runnable. | +| 2 | positioning-and-risks | 1 | 1 | New hero shipped (incl. CTA fork), `/contact` route live, risk-cleanup copy deployed (Angular matrix, A2UI v0.9, telemetry footnote), both CTA tracks measurable. | +| 3 | comparison-pages | 1 | 2 | 4 comparison pages live (langchain-angular, copilotkit, hashbrown, a2ui-renderer), each with measurable CTA clicks on both tracks. | +| 4 | cockpit-activation-recipes | 1 | 1, 3 | All 6 activation signals fire from cockpit; six-signal activation funnel non-zero; one comparison page successfully drives an activation. | +| 5 | content-pillar-pages | 2 | 2, 4 | 6 pillar pages published, in sitemap, OG cards, indexed within 30 days. | +| 6 | community-launch | 3 | 2, 3, 4, 5 | Launch executed, week-1 dashboard snapshot committed, post-mortem doc written. | +| 7 | enterprise-pipeline | 4 | 1, 2 | 3 pilots tracked end-to-end in enterprise-funnel dashboard; ≥1 sanitized public artifact produced from a pilot. | + +**Sequencing notes:** + +- Specs 5–7 can spin up in parallel as soon as their dependencies clear. The critical path is 0 → 1 → 2 → 3 → 4 (developer track end-to-end). +- The existing May-2 instrumentation plan is subsumed by Spec 1; not orphaned, not re-speced. + +## 7. Analytics architecture + +### 7.1 Data flow + +``` +apps/website ─┐ +apps/cockpit ─┼──▶ posthog-js (browser) ─┐ +libs/* opt-in ─┘ │ + ├──▶ PostHog Cloud (single project) +apps/website API routes ─┐ │ +libs/telemetry/node ─┼──▶ posthog-node ─┘ +postinstall ping ─┘ + │ +tools/posthog/ ▼ + dashboards/*.json ─┐ docs/gtm/reports/-weekly.md + insights/*.json ─┼─▶ sync.ts ─▶ PostHog Public API (idempotent upsert) + cohorts/*.json ─┘ + report.ts ────────▶ pulls insights ─▶ writes markdown snapshot +``` + +### 7.2 Event namespaces + +Single PostHog project. Three event-name prefixes: + +- `marketing:*` — website surfaces (carried forward from May-2 plan). +- `cockpit:*` — activation surface (new in Spec 1). +- `ngaf:*` — library telemetry (new in Spec 1). + +### 7.3 Dashboards-as-code + +Each artifact under `tools/posthog/` is a JSON file with **declarative content** + a **server-assigned `posthog_id`** (written back after first sync). Drift = anything in PostHog not represented in JSON, or vice versa. + +**Sync semantics (Spec 1 implements):** + +- `posthog:sync --plan` — diff only, no writes. Outputs `[create] [update] [no-op] [orphan]` per artifact. Runs in CI on every PR. +- `posthog:sync --apply` — idempotent upsert. Re-running with no JSON change = no-op. +- Orphans (exist in PostHog, no JSON) are reported but not deleted automatically. Deletion requires `--apply --delete-orphans` or a tombstone JSON. +- `posthog_id` writeback happens in a follow-up commit (or in-line if running locally with write access). + +**Decision: single PostHog project for everything.** Website, cockpit, library telemetry all go to one project, distinguished by event namespace. Tradeoff: harder permissions story long-term; better for cross-surface funnels in Phase 1. + +**Decision: sync writes `posthog_id` back into JSON.** Alternative is a separate `.lockfile.json`. Writeback is simpler. + +### 7.4 CLI surface + +``` +npm run posthog:sync -- --plan # diff against PostHog, no writes +npm run posthog:sync -- --apply # idempotent upsert +npm run posthog:report # fetch insights → docs/gtm/reports/.md +``` + +Also exposed as Nx targets on a synthetic `gtm` project (`tools/gtm/project.json`). + +### 7.5 `@ngaf/telemetry` architecture + +``` +libs/telemetry/ +├── src/ +│ ├── shared/ +│ │ ├── env.ts # DO_NOT_TRACK + NGAF_TELEMETRY_DISABLED + CI detect +│ │ ├── hash.ts # SHA-256 one-way hashing for sensitive ids +│ │ └── events.ts # Typed event names. ngaf:* namespace only. +│ ├── node/ # Default opt-out enabled +│ │ ├── client.ts # posthog-node wrapper, flushAt:1, flushInterval:0 +│ │ ├── postinstall.ts # One ping per install: { pkg, version, node, os } +│ │ └── adapter.ts # Optional surfaces called from user's server adapters +│ └── browser/ # Opt-in only, never default +│ ├── provide.ts # provideNgafTelemetry({ enabled, posthogKey, posthogHost }) +│ └── client.ts # posthog-js wrapper. No-ops unless explicitly provided. +└── README.md # The trust contract. +``` + +**Mounting rules (the README codifies these as the public contract):** + +1. **Browser packages (`@ngaf/chat`, `@ngaf/agent`, `@ngaf/render`, etc.) never import from `@ngaf/telemetry/browser` directly.** Only the consuming app does, by calling `provideNgafTelemetry({ enabled: true })` in its root providers. If not called, every telemetry helper no-ops. +2. **Node-side adapters may import from `@ngaf/telemetry/node`** — the import path short-circuits inside `isTelemetryDisabled()`. +3. **Postinstall** runs once per `npm install`, fires `ngaf:postinstall` with `{ pkg, version, node, os, sample_weight }`. 3s timeout, silent fail. Prints a one-line opt-out notice on stdout. +4. **Sample rate = 1.0** at current scale. Env-configurable via `NGAF_TELEMETRY_SAMPLE_RATE`. Sample weight stamped on every event so future de-sampling at query time works correctly. +5. **Anonymous id strategy:** per-process UUID (`anon_`), regenerated each boot. No persistence. +6. **No vendor key ever ships with the library.** Browser opt-in requires the consumer to pass their own `posthogKey`. Node telemetry to *our* PostHog is gated by `NGAF_TELEMETRY_INGEST_URL` (default points to our proxy on `apps/website/api/ingest`; enterprise self-hosters redirect). + +### 7.6 Error handling + +All analytics infrastructure follows the **silent-fail principle:** + +- Telemetry never throws into the host application. Try/catch at every boundary. 3s network timeout. +- `posthog:sync --apply` errors are loud (CI fails). `posthog:report` errors are loud (no markdown written, exit non-zero). +- Missing or 401 PostHog Public API key in CI = sync skipped with warning, not failure (so contributor PRs don't fail on secrets). + +### 7.7 Testing strategy + +- `tools/posthog/sync.ts`: unit tests for diff algorithm against a fake PostHog client. Integration test gated on `POSTHOG_DEV_API_KEY`. +- `@ngaf/telemetry`: unit tests for env detection (all three opt-out paths), hashing, sampling math. Network mocked. +- **`@ngaf/telemetry/browser` trust test:** unit test confirming no network call when `provideNgafTelemetry()` is never called. This test stays green permanently. +- Cockpit/website analytics: existing Playwright request-interception pattern from May-2 plan. + +## 8. Homepage CTA fork + +The hero forks into two tracks. This is a key strategic decision codified here so Spec 2 can implement without relitigating. + +``` +Homepage hero +├── Primary CTA "Install @ngaf/chat" ──▶ copy-to-clipboard + scroll to install section +└── Secondary CTA "Talk to our engineers" ──▶ /contact?source=home_hero&track=enterprise +``` + +### 8.1 `/contact` is a new dedicated route + +- Existing `/pricing#contact` and `/pilot-to-prod#contact` anchors remain. +- All three surfaces use the same `LeadForm` component with a `track` property: `enterprise` (from `/contact`), `pricing` (from `/pricing`), `pilot` (from `/pilot-to-prod`). +- Surface-aware surrounding copy; shared form infrastructure. +- Hidden attribution fields populate identically across all three: `source_page`, `track`, `cta_id`, `paper`, `referrer_host`. + +### 8.2 `/contact` page composition (Direction A.v2, locked) + +- Headline: **"Talk to an engineer."** +- Subhead: *"Tell us what you're shipping. We'll reply within one business day — usually with code, not a calendar invite."* +- Two fields only: email + free-text body. No stack dropdown, no company size, no "how did you hear about us." +- SLA card with personal naming: *"Brian or someone on the team replies personally — from a real inbox, not noreply@."* +- Alt-channel row below form: docs / GitHub issues / Discord (Mastra pattern). +- One small trust signal next to form: GitHub star pill. No logo wall. + +Visual research informing this direction is captured in the brainstorm session at `.superpowers/brainstorm/39252-1778693057/content/contact-a-v2.html`. + +### 8.3 PostHog tracking + +| Event | When | Key properties | Track | +|-------|------|----------------|-------| +| `marketing:cta_click` | Hero primary CTA copy | `cta_id=hero_install`, `track=developer`, `surface=home` | developer | +| `marketing:cta_click` | Hero secondary CTA | `cta_id=hero_talk_to_engineers`, `track=enterprise`, `surface=home`, `source_page` | enterprise | +| `$pageview` | `/contact` loaded | `source_page`, `track`, `cta_id`, `referrer_host` (auto from query) | enterprise | +| `marketing:lead_form_submit` | Submit click | `source_page`, `track`, `cta_id`, `paper`, `message_length`, `message_empty` | enterprise | +| `marketing:lead_form_success` | Server 2xx | same as submit | enterprise | +| `marketing:lead_form_fail` | Server non-2xx | same + `failure_reason` | enterprise | +| `marketing:lead_qualified` | Server-side enrichment passes | `email_domain`, `company`, `track`, `source_page` | enterprise | + +**`marketing:lead_qualified` is server-side only** and is what the enterprise funnel dashboard counts. Client `lead_form_success` is a leading indicator; `lead_qualified` is truth. + +**Qualified-lead v1 definition:** non-personal `email_domain` + non-empty `company`. Tighten in Spec 7 if signal proves too noisy. + +### 8.4 Attribution chain end-to-end + +A buyer's journey from a comparison page to a qualified lead carries one `cta_id` and one `source_page`: + +``` +$pageview /compare/langchain-angular + source_page=compare_langchain_angular +marketing:cta_click + cta_id=compare_langchain_angular_talk_to_engineers + source_page=compare_langchain_angular + track=enterprise +$pageview /contact?source=compare_langchain_angular&track=enterprise&cta_id=... + source_page=compare_langchain_angular (preserved via query param) +marketing:lead_form_submit + source_page=compare_langchain_angular +marketing:lead_qualified + source_page=compare_langchain_angular + email_domain=acme.com +``` + +This lets us answer "which comparison page drives the most qualified leads?" — one PostHog breakdown by `source_page` on `lead_qualified`. + +## 9. Progress tracking via Cowork + +### 9.1 What we commit + +``` +cowork/ +├── README.md # Manual install instructions (2-3 paragraphs). +└── gtm/ + └── SKILL.md # The single Cowork skill markdown. +``` + +That's it. One skill file, one short README. **No `.claude/agents/`, no shared skills directory, no plugin packaging.** Plugin packaging deferred (see §11). + +### 9.2 What the skill owns + +- Weekly PostHog snapshot procedure. +- Lead triage against the qualified-lead definition. +- New workstream scaffolding (`/brainstorming` → spec → `/writing-plans` → plan). +- "Where are we?" questions — reads `gtm.md` + the latest report + spec frontmatter. + +The skill body is documented in `cowork/gtm/SKILL.md` (one of this spec's deliverables). + +### 9.3 Manual install + +Documented in `cowork/README.md`: + +```bash +mkdir -p ~/.claude/skills/gtm +cp cowork/gtm/SKILL.md ~/.claude/skills/gtm/SKILL.md +# Or symlink so updates flow through: +ln -s "$(pwd)/cowork/gtm/SKILL.md" ~/.claude/skills/gtm/SKILL.md +``` + +Verification: open a Claude Code session in this repo and type `/gtm`. + +### 9.4 Schedule + +Cowork has no in-repo scheduling primitive. The schedule is created once per machine via the existing `schedule` skill: + +``` +/schedule create weekly-snapshot 'every Monday 9am' /gtm "run the weekly snapshot procedure" +``` + +This instruction lives in `cowork/README.md`; the running routine itself is user-machine state, not committed. + +### 9.5 `gtm.md §7` is hand-edited + +A static inventory of workstreams pointing into specs and dashboards. Not regenerated. Updated when a workstream is added or renamed (rare). The Cowork skill's "where are we?" capability reads the file system as truth, not §7. + +## 10. Risks & non-goals + +### 10.1 Risks from the strategy + +| # | Risk | Mitigation | Owner spec | +|--:|------|------------|------------| +| 1 | `@langchain/angular` commoditizes streaming adapter | `/compare/langchain-angular` positions Cacheplane as additive | Spec 3 | +| 2 | "Angular Agent Framework" reads like a backend runtime | Category sweep to "Agent UI" in copy | Spec 2 | +| 3 | Angular version messaging confuses enterprise buyers | Real compatibility matrix replaces "All Angular versions" | Spec 2 | +| 4 | A2UI v1 claim is ahead of public spec | Copy → "A2UI v0.9-compatible" until v1 is verified | Spec 2 | +| 5 | CopilotKit / Hashbrown have stronger awareness | Don't fight as general agent UI; claim Angular enterprise final mile | Specs 2, 3 | + +### 10.2 Risks introduced by our design + +- **Opt-in browser telemetry yields low signal.** Accepted. Lean on first-party website + cockpit analytics + Node-side opt-out for volume. Trust contract preserved. +- **Single Cowork skill = no parallel agent runs.** Acceptable at current scale. Refactor to per-workstream subagents is a one-day change if needed. +- **Hand-edited §7 drifts.** Cowork skill reads filesystem as truth, not §7. Inventory is for navigation, not state. +- **`/contact` adds a fourth lead-form surface.** Shared `LeadForm` component, `track` property distinguishes surfaces, `lead_qualified` is one funnel regardless of surface. +- **Dashboards-as-code drift if clicked-edited in PostHog UI.** `posthog:sync --plan` in CI flags drift. Orphan deletion stays manual. +- **Postinstall telemetry is contentious.** `libs/telemetry/README.md` documents exactly what is sent; postinstall prints a one-line opt-out notice. + +### 10.3 Non-goals (Phase 0–4) + +- No paid acquisition. +- No stars-chasing in the weekly snapshot. +- No browser telemetry from `@ngaf/*` packages by default. +- No telemetry in the smoke/demo app. +- No PostHog feature flags / experiments / session replay in Phase 0–1 (deferred workstreams). +- No publishing the Cowork skill as a marketplace plugin (project-local; publishable later). +- No general agent UI category claim — Angular final mile only. +- No A/B positioning experiments in Phase 1. +- No `gtm:status` regenerated table (Cowork skill + hand-edited §7 only). +- No automatic weekly-snapshot commits (human reviews Notes before merge). + +## 11. Deferred workstreams + +Captured here so they're not lost; each becomes its own spec when prioritized: + +- **PostHog feature flags as code.** `tools/posthog/flags/*.json` synced via API. Lowest-friction next step after Phase 1. +- **PostHog experiments as code.** `tools/posthog/experiments/*.json` with hypothesis, variants, sample size. Pairs with Phase 2 once baseline traffic exists. +- **Session replay on cockpit + group analytics keyed on company.** Phase 3+. +- **Cowork plugin packaging.** Publish `@ngaf/gtm-plugin` so other Angular agent startups can adopt the operating system. Consider after Phase 4 if motion proves out. +- **Per-workstream subagents.** Split the single Cowork skill into `.claude/agents/gtm-.md` if context bleed becomes a problem. + +## 12. Deliverables of this spec + +The plan file at `docs/superpowers/plans/gtm/2026-05-13-gtm-meta.md` will check off: + +- [ ] `gtm.md` at repo root (durable strategy, §5 outline filled in) +- [ ] `docs/gtm/icp.md` skeleton +- [ ] `docs/gtm/messaging.md` skeleton +- [ ] `docs/gtm/taxonomy.md` skeleton +- [ ] `tools/posthog/README.md` (dashboards-as-code conventions) +- [ ] `libs/telemetry/README.md` (trust contract) +- [ ] `cowork/README.md` (manual install instructions) +- [ ] `cowork/gtm/SKILL.md` (the single Cowork skill) +- [ ] `.gitignore` updated to ignore `.superpowers/` brainstorm artifacts + +No code, no PostHog API calls, no website changes. The next spec to brainstorm is `analytics-foundation`. + +## 13. References + +- Strategy raw text and visual research session: `.superpowers/brainstorm/39252-1778693057/` +- Existing PostHog instrumentation plan (subsumed by Spec 1): `docs/superpowers/plans/2026-05-02-posthog-gtm-analytics.md` +- Existing website analytics: `apps/website/src/lib/analytics/` +- Existing `LeadForm` component: `apps/website/src/components/pricing/LeadForm.tsx` +- Existing pricing + pilot-to-prod pages: `apps/website/src/app/pricing/`, `apps/website/src/app/pilot-to-prod/` diff --git a/gtm.md b/gtm.md new file mode 100644 index 000000000..fa5cfc20c --- /dev/null +++ b/gtm.md @@ -0,0 +1,116 @@ +# Cacheplane GTM Strategy + +> Durable strategy. Hand-edited. Operational details live in `docs/gtm/`. +> Workstream plans live in `docs/superpowers/specs/gtm/`. +> Last reviewed: 2026-05-13. + +## 1. What we are + +Cacheplane is the production agent UI framework for Angular teams. It turns LangGraph, AG-UI, A2UI, and custom agent streams into real Angular experiences — chat, threads, tool progress, human approvals, generative UI, fallbacks, observability, tests — without rewriting in React or adopting a proprietary cloud. + +## 2. Category + +- **Primary:** Agent UI for Angular +- **Secondary (only after "Agent UI"):** Angular Agent UI Framework +- **Do not use:** "Angular Agent Framework" (ambiguous with backend runtimes and coding agents), "Enterprise Angular agent framework" (reads sales-first). + +The category claim is the **Angular final mile**: official streaming SDKs (LangChain, AG-UI, A2UI) get events into Angular; Cacheplane turns those events into production-ready Angular experiences. We do not compete as a general agent UI framework. We do not compete with backend runtimes. + +## 3. ICP + +Two tracks, both addressed from the homepage via the CTA fork. + +| Track | Buyer | Channel | Primary CTA | Secondary surface | +|-------------|------------------------------------------|----------------------------|--------------------------|-------------------------| +| Developer | Angular engineer on an agent project | docs, GitHub, npm, search | `Install @ngaf/chat` | cockpit recipes | +| Enterprise | Architect / eng lead at an Angular shop | direct, partner, content | `Talk to our engineers` | `/contact` → LeadForm | + +Detailed personas, buying signals, and disqualifiers: `docs/gtm/icp.md`. + +## 4. Funnel & activation + +Two funnels share acquisition surfaces and diverge at the homepage CTA. + +**Developer funnel:** +`$pageview` → comparison/content view → `Install @ngaf/chat` (copy) → cockpit recipe start → cockpit recipe complete → cockpit six-signal activation. + +**Enterprise funnel:** +`$pageview` → `Talk to our engineers` click → `/contact` view → `LeadForm` submit → `lead_form_success` → `lead_qualified` (server-side enrichment) → discovery booked → pilot started → pilot shipped. + +**North-star activation milestone (developer):** in under 30 minutes, complete all six cockpit signals: install command copied, transport connected, first chat message sent, thread persisted, interrupt handled, generative Angular component rendered. Event-level definitions in [docs/gtm/taxonomy.md](docs/gtm/taxonomy.md). Measured via PostHog cohort `Activated developers`. + +**North-star qualified lead (enterprise):** see operational definition in [docs/gtm/icp.md](docs/gtm/icp.md) §Enterprise track. Fired on `lead_form_success`; criteria are non-personal `email_domain`, non-empty `company`, and `track=enterprise`. Measured via PostHog cohort `Qualified leads`. + +## 5. Metrics + +Two scoreboards, separate. Dashboard index (PostHog ids generated by `tools/posthog/sync.ts`): + +| Slug | What it measures | Source spec | +|-----------------------------|-----------------------------------------------------------|-------------| +| `developer-funnel` | pageview → install → cockpit activation | Spec 1 | +| `enterprise-funnel` | pageview → talk-to-engineers → lead_qualified → pilot | Spec 1, 7 | +| `activation-six-signals` | the six cockpit signals and the 30-min funnel | Spec 1, 4 | +| `content-intent` | docs/comparison/pillar page engagement and CTAs | Spec 1, 3, 5 | +| `package-telemetry` | `ngaf:postinstall`, runtime adapters, opt-in browser | Spec 1 | + +> Spec numbers refer to the workstream DAG in [meta-spec §6](docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md). Not all referenced specs exist on disk yet — they get authored as each workstream is brainstormed. + +Event/property/CTA-id taxonomy: `docs/gtm/taxonomy.md`. Weekly snapshot: `docs/gtm/reports/`. + +## 6. Phases + +Four phases. Each phase = one or more workstream specs. Exit gates are blocking. + +| Phase | Goal | Specs | Exit gate | +|------:|-------------------------------|-------------------------------------------------------------------------|-----------| +| 0 | Measurement foundation | analytics-foundation | 5 dashboards live, 3 event namespaces emitting, `@ngaf/telemetry@0.0.1` published, weekly report runnable. | +| 1 | Developer clarity in 30 sec | positioning-and-risks, comparison-pages, cockpit-activation-recipes | New hero shipped (incl. CTA fork), 4 comparison pages live, six-signal activation funnel non-zero, ≥1 qualified lead recorded. | +| 2 | Ecosystem path (SEO + recipes)| content-pillar-pages | 6 pillar pages indexed, organic traffic baseline captured. | +| 3 | Community launch | community-launch | Launch executed, week-1 snapshot committed, post-mortem committed. | +| 4 | Enterprise design partners | enterprise-pipeline | 3 pilots tracked end-to-end in `enterprise-funnel`, ≥1 sanitized public artifact produced. | + +Deferred (post-Phase-4, own specs): PostHog feature flags as code, experiments as code, session replay, group analytics, Cowork plugin packaging. + +## 7. Workstream agents + +Operational progress lives in agent runs and PostHog. The repo holds durable strategy and the Cowork skill definition. This table is the static inventory — *who owns what*, not *what's done*. + +| Phase | Workstream | Subagent | Spec | Dashboard | +|------:|----------------------------|-------------------------------------------|-------------------------------------------------------------------------------|----------------------------| +| 0 | gtm-meta | `cowork/gtm/SKILL.md` | [meta](docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md) | — | +| 0 | analytics-foundation | `cowork/gtm/SKILL.md` | (pending) | all 5 (foundational) | +| 1 | positioning-and-risks | `cowork/gtm/SKILL.md` | (pending) | — | +| 1 | comparison-pages | `cowork/gtm/SKILL.md` | (pending) | `content-intent` | +| 1 | cockpit-activation-recipes | `cowork/gtm/SKILL.md` | (pending) | `activation-six-signals` | +| 2 | content-pillar-pages | `cowork/gtm/SKILL.md` | (pending) | `content-intent` | +| 3 | community-launch | `cowork/gtm/SKILL.md` | (pending) | — | +| 4 | enterprise-pipeline | `cowork/gtm/SKILL.md` | (pending) | `enterprise-funnel` | + +## 8. Non-goals (current phase) + +- We do not compete as a general agent UI framework. We claim the Angular final mile. +- We do not ship telemetry from `@ngaf/*` browser packages by default. Opt-in only. Node-side telemetry honors `DO_NOT_TRACK` and `NGAF_TELEMETRY_DISABLED`; see [libs/telemetry/README.md](libs/telemetry/README.md) for the full contract. +- We do not run paid acquisition until Phase 2 organic baselines exist. +- We do not pursue stars as a vanity metric. +- We do not run A/B positioning experiments in Phase 1. Ship one hero, measure, iterate. +- We do not instrument the smoke/demo app — it's a canonical reference, not a funnel surface. +- We do not auto-commit weekly snapshots. A human reviews Notes before merge. +- We do not publish the Cowork skill as a marketplace plugin in Phase 0–4. Project-local; reconsider after Phase 4. + +## 9. Cadence + +- **Weekly:** `/gtm` Cowork skill runs the weekly snapshot procedure — `npm run posthog:report`, drafts a 3-bullet Notes section, opens a PR with `docs/gtm/reports/-weekly.md`. Human reviews Notes before merge. +- **Monthly:** re-read this document. Edit positioning, ICP, non-goals, or phase exit gates if reality has moved. +- **Per workstream:** brainstorm → spec → plan → execute → dashboard signals verified → spec frontmatter `status: done` → §7 inventory updated. + +## 10. References + +- Strategy + visual research: `.superpowers/brainstorm/` (gitignored) +- Meta-spec: [docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md](docs/superpowers/specs/gtm/2026-05-13-gtm-meta-design.md) +- ICP: [docs/gtm/icp.md](docs/gtm/icp.md) +- Messaging: [docs/gtm/messaging.md](docs/gtm/messaging.md) +- Taxonomy: [docs/gtm/taxonomy.md](docs/gtm/taxonomy.md) +- Dashboards-as-code: [tools/posthog/README.md](tools/posthog/README.md) +- Telemetry contract: [libs/telemetry/README.md](libs/telemetry/README.md) +- Cowork skill: [cowork/README.md](cowork/README.md) · [cowork/gtm/SKILL.md](cowork/gtm/SKILL.md) +- Prior PostHog instrumentation plan (subsumed by Spec 1): [docs/superpowers/plans/2026-05-02-posthog-gtm-analytics.md](docs/superpowers/plans/2026-05-02-posthog-gtm-analytics.md) diff --git a/libs/telemetry/README.md b/libs/telemetry/README.md new file mode 100644 index 000000000..14694c86b --- /dev/null +++ b/libs/telemetry/README.md @@ -0,0 +1,104 @@ +# @ngaf/telemetry + +> Skeleton. Implementation lands in Spec 1 (`analytics-foundation`). +> This README is the **public trust contract**. It's linked from the homepage footer, package READMEs, and the postinstall opt-out notice. The contract is locked here so it doesn't drift. + +## What this package is + +The single telemetry surface for `@ngaf/*`. It exists so we can answer "how is Cacheplane being used?" without instrumenting browser packages that ship to end-users. + +## What is and isn't telemetered + +**Telemetered by default (Node, opt-out):** +- `ngaf:postinstall` — fires once per `npm install` of an `@ngaf/*` package. Properties: package name, package version, Node version, OS. No identifiers, no project path, no environment variables. +- `ngaf:runtime_instance_created` — server adapters (LangGraph, AG-UI) call this when they spin up. Properties: which transport, which model provider (string), Angular peer version. **No API keys**, no endpoint hostnames, no user data. Sensitive identifiers are hashed (SHA-256, one-way). +- `ngaf:stream_started` / `ngaf:stream_ended` / `ngaf:stream_errored` — per-request lifecycle on server adapters. Properties: provider, model name, duration, error class. No prompts, no completions, no message content. + +**Telemetered only on explicit opt-in (Browser):** +- Nothing fires unless the consumer calls `provideNgafTelemetry({ enabled: true, posthogKey, posthogHost })` in their root providers. +- When opted in: `ngaf:browser_provided`, `ngaf:browser_chat_init`. Anonymous, no message content. + +**Never telemetered (by anyone, at any time):** +- Message content (user prompts, model completions, tool call inputs/outputs). +- Personally identifiable information beyond `email_domain` on explicit server conversion events on the website. +- API keys, vendor credentials, project paths, environment variables. +- Whatever you've told the SDK to ignore via the redaction config. + +## Opt-out + +Node telemetry is on by default. Three ways to opt out — any one turns it off. + +| Method | How | +|--------|-----| +| Cross-vendor env var | `DO_NOT_TRACK=1` or `DO_NOT_TRACK=true` | +| Package env var | `NGAF_TELEMETRY_DISABLED=1` or `NGAF_TELEMETRY_DISABLED=true` | +| Programmatic | `import { disableTelemetry } from '@ngaf/telemetry/node'; disableTelemetry();` before any other `@ngaf/*` import | + +CI environments (`CI=true`, `GITHUB_ACTIONS=true`, etc.) are auto-detected and treated as opt-out by default. + +The postinstall script prints a single line on stdout describing what was sent and how to disable. The line is suppressed in CI. + +## Opt-in (browser) + +Browser telemetry is **off by default** and never fires from the library itself. To enable in your Angular app: + +```ts +// app.config.ts (or wherever you bootstrap) +import { provideNgafTelemetry } from '@ngaf/telemetry/browser'; + +export const appConfig: ApplicationConfig = { + providers: [ + // ... + provideNgafTelemetry({ + enabled: true, + posthogKey: 'phc_yourKey', // your PostHog project key, never ours + posthogHost: 'https://us.i.posthog.com', + }), + ], +}; +``` + +If you don't call `provideNgafTelemetry({ enabled: true })`, every telemetry helper in `@ngaf/*` browser packages no-ops. No network calls, ever. + +## Sampling + +- Default sample rate: **1.0** (100%) at current scale. +- Configurable via `NGAF_TELEMETRY_SAMPLE_RATE` env var (Node) or the `sampleRate` option (Browser). +- Every event carries a `sample_weight` property so future de-sampling at query time works correctly. + +## Anonymous id strategy + +- Per-process UUID (`anon_`), regenerated every Node process boot. +- No persistence across restarts. No persistent identifier. +- Browser opt-in uses the consumer's PostHog `distinct_id` per their own configuration — Cacheplane does not manage browser identity. + +## Self-hosting + +Enterprise users can redirect Node telemetry to their own ingest: + +```bash +NGAF_TELEMETRY_INGEST_URL=https://posthog.acme-internal.example.com +``` + +Default ingest (when env var is unset) is a thin proxy on the Cacheplane website (`https://cacheplane.dev/api/ingest`) that forwards to our PostHog project. Source of the proxy lives in `apps/website/src/app/api/ingest/`. + +## Verifying telemetry is silent + +The `@ngaf/telemetry/browser` unit test suite includes a permanent trust test: + +``` +test('no network call occurs when provideNgafTelemetry is never called', ...) +``` + +If this test ever fails, the trust contract has been violated and the build blocks. + +## What's intentionally not in this package + +- Session replay. (Not in Phase 0–1.) +- Cross-session identity stitching. +- Heuristic PII detection. (Redaction is explicit and config-driven only.) +- Default writes to anyone's PostHog instance — including ours — without explicit configuration. + +## Reporting an issue + +If you observe telemetry that you believe contradicts this contract, please open an issue at https://github.com/cacheplane/angular-agent-framework/issues — security-tagged. We treat it as a P0. diff --git a/tools/posthog/README.md b/tools/posthog/README.md new file mode 100644 index 000000000..b69003397 --- /dev/null +++ b/tools/posthog/README.md @@ -0,0 +1,115 @@ +# PostHog dashboards-as-code + +> Skeleton. Implementation lands in Spec 1 (`analytics-foundation`). +> The convention is locked here so contributors authoring dashboards know the shape. + +## What this directory is + +PostHog is configured via a Public-API-driven sync script — not through the PostHog UI. Every dashboard, insight, cohort, and funnel that GTM relies on is a JSON file in this directory. The sync script reconciles JSON ↔ PostHog. Git is the source of truth. + +## Directory layout + +``` +tools/posthog/ +├── sync.ts # Idempotent upsert. (Spec 1 implements.) +├── report.ts # Weekly markdown export. (Spec 1 implements.) +├── schema/ +│ ├── dashboard.json # JSON Schema for dashboards/*.json +│ ├── insight.json # JSON Schema for insights/*.json +│ └── cohort.json # JSON Schema for cohorts/*.json +├── dashboards/ # One JSON per dashboard +│ ├── developer-funnel.json +│ ├── enterprise-funnel.json +│ ├── activation-six-signals.json +│ ├── content-intent.json +│ └── package-telemetry.json +├── insights/ # Reusable insight specs referenced by dashboards +└── cohorts/ # Cohort specs (e.g. "Activated developers") +``` + +## JSON contract + +Each artifact is declarative content + a server-assigned `posthog_id` (written back after first sync). + +```jsonc +// tools/posthog/dashboards/developer-funnel.json +{ + "$schema": "../schema/dashboard.json", + "slug": "developer-funnel", // local id, stable across syncs + "posthog_id": null, // assigned by sync; do not edit + "name": "GTM · Developer funnel", + "description": "Pageview → install → cockpit activation. Source: gtm.md §4.", + "tags": ["gtm", "developer-track", "phase-1"], + "tiles": [ + { "insight": "pageviews-by-landing" }, + { "insight": "install-command-clicks" }, + { "insight": "cockpit-recipe-completion" }, + { "insight": "six-signal-activation-funnel" } + ] +} +``` + +```jsonc +// tools/posthog/insights/six-signal-activation-funnel.json +{ + "slug": "six-signal-activation-funnel", + "posthog_id": null, + "kind": "funnel", + "window_minutes": 30, + "steps": [ + { "event": "cockpit:install_command_copied" }, + { "event": "cockpit:transport_connected" }, + { "event": "cockpit:chat_first_message" }, + { "event": "cockpit:thread_persisted" }, + { "event": "cockpit:interrupt_handled" }, + { "event": "cockpit:generative_component_rendered" } + ] +} +``` + +The funnel's six steps are the canonical "six signals." `cockpit:recipe_start` and `cockpit:six_signals_complete` exist as diagnostic events (session entry and "all six completed within window") but are not funnel steps. + +Event names must match `docs/gtm/taxonomy.md`. CI guards reject dashboards that reference unknown events. + +## CLI + +```bash +npm run posthog:sync -- --plan # Diff against PostHog, no writes. + # Outputs [create] [update] [no-op] [orphan] per artifact. + # CI runs this on every PR. + +npm run posthog:sync -- --apply # Idempotent upsert. + # Re-running with no JSON change = no-op. + +npm run posthog:sync -- --apply --delete-orphans + # Explicit, manual. Deletes PostHog artifacts + # that have no matching JSON. Never auto. + +npm run posthog:report # Pull insights → write docs/gtm/reports/-weekly.md. +``` + +Also exposed as Nx targets on a synthetic `gtm` project (`tools/gtm/project.json`). + +## Sync semantics + +- **Plan vs. apply.** `--plan` mutates nothing; `--apply` upserts. +- **Idempotent.** Re-applying with no JSON change is a no-op. +- **Orphan handling.** Items in PostHog with no JSON are reported on every plan/apply but never auto-deleted. Use `--apply --delete-orphans` to drop them, or commit a tombstone JSON. +- **`posthog_id` writeback.** After first apply, the sync script writes the assigned id back into each JSON. Commit the writeback as a follow-up. +- **Missing API key in CI.** Sync skips with a warning, not a failure — so contributor PRs without secrets pass. + +## Adding a new dashboard + +1. Create `tools/posthog/dashboards/.json` following the contract above. +2. Reference insights by `slug` only. Define them in `insights/.json` if they don't exist. +3. Run `npm run posthog:sync -- --plan` locally. +4. Commit the JSON and open a PR. +5. After merge, run `npm run posthog:sync -- --apply` (or wait for the deploy hook — TBD in Spec 1). +6. Commit the `posthog_id` writeback. + +## Why dashboards-as-code + +- **`git blame` answers "who changed this metric and why."** +- **No clicking through the PostHog UI** = "api/cli-first agentic GTM" actually delivers. +- **Reproducible on a fresh PostHog project** for staging/test envs. +- **Reviewable in PRs** like any other change.