Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ usually what it admits.
- **Say what the tool cannot do.** The analytics skills in `startup-data-kit`
have a "what this cannot tell you" section, because the alternative is an
agent producing a confident answer to a question the data cannot answer.
- **Say what the user has to decide.** `revenue-analytics` has ten decisions it
cannot make for you, because MRR genuinely depends on them. A resource that
picks silently teaches the user that a hard question is settled.
- **Say what the user has to decide.** The startup-data-kit skills list what
usually needs the user's input, because the numbers genuinely depend on it. A
resource that picks silently teaches the user that a hard question is settled.
- **Name the traps specific to that data.** Generic advice gets skipped. "GA4
thresholding means totals will not equal the sum of a breakdown" does not.
- **Write to the agent, imperatively.** Not prose about the tool.
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ questions from it. One domain per folder:
| [`product-analytics`](resources/startup-data-kit/product-analytics/) | experimental | approval-required | Activation, feature adoption, retention, usage-based churn signals. PostHog, Mixpanel, Amplitude |
| [`web-analytics`](resources/startup-data-kit/web-analytics/) | experimental | approval-required | Traffic, landing pages, channels, funnel drop-off. GA4, Search Console |
| [`ai-search-visibility`](resources/startup-data-kit/ai-search-visibility/) | experimental | approval-required | SEO, GEO and AEO. Search Console, AI crawler traffic, whether assistants mention you |
| [`finance-accounting`](resources/startup-data-kit/finance-accounting/) | experimental | approval-required | Receivables and aging, invoiced vs collected, customer concentration, vendor balances. QuickBooks Online |
| [`support-analytics`](resources/startup-data-kit/support-analytics/) | experimental | approval-required | Ticket volume, response and resolution time, CSAT, backlog, support load per customer. Gorgias, Zendesk, Intercom |
| [`ai-coding-spend`](resources/startup-data-kit/ai-coding-spend/) | experimental | approval-required | AI coding tool adoption, usage and estimated cost by team, model and platform. Claude Code, Cursor |
| [`sheets-and-notion`](resources/startup-data-kit/sheets-and-notion/) | experimental | approval-required | Hand-maintained plans, targets, budgets and mappings, joined to the other domains. Google Sheets, Notion |

**[`data-engineering-skills`](resources/data-engineering-skills/)**: keeping
pipelines healthy. Install Bruin's seven maintained skills, then add the
Expand Down Expand Up @@ -72,10 +76,7 @@ ship code you run yourself, with your own credentials.
| [`blog-image-generator`](resources/tools/blog-image-generator/) | experimental | approval-required | Finding a licence-friendly Unsplash photo and turning it into a cropped, treated cover image |
| [`linkedin-enrichment`](resources/tools/linkedin-enrichment/) | experimental | approval-required | Pulling public LinkedIn company, person, post or job data through paid Apify actors |

Everything is `experimental` today: the commands in `bruin-agent` were verified
against a live Bruin CLI, and the connector and template lists came from Bruin's
own tooling, but nobody other than the author has used any of these end to end.
A resource becomes `stable` when someone else has.
Everything is `experimental` today.

**Risk** is the worst a resource can do when followed as written. `read-only`
reads and produces local files. `approval-required` can write, run or send
Expand Down
49 changes: 20 additions & 29 deletions resources/startup-data-kit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
> is stale. Each skill states the version and date it was written against.
> Checked 2026-10-01.

Getting a startup's data into shape and answering questions from it. Each skill
has an agent work with the user to set up a maintained Bruin template and
customise it to how the business actually works, then answer questions from
what it built. One resource per domain, because the traps are domain-specific:
what ruins a revenue number is not what ruins an attribution number.

Each folder is an independent skill. Take the ones you need.
One skill per domain: an agent sets up a maintained Bruin template with the
user, customises it, then answers questions from it. Take the folders you need.

| Resource | Domain | Example sources |
|---|---|---|
Expand All @@ -20,47 +15,43 @@ Each folder is an independent skill. Take the ones you need.
| [`product-analytics`](product-analytics/) | Usage and activation | PostHog, Mixpanel, Amplitude, Firebase |
| [`web-analytics`](web-analytics/) | Traffic and acquisition | GA4, Search Console |
| [`ai-search-visibility`](ai-search-visibility/) | SEO, GEO, AEO | Search Console, server logs, third-party sampling tools |
| [`finance-accounting`](finance-accounting/) | Bookkeeping and accounting | QuickBooks Online |
| [`support-analytics`](support-analytics/) | Customer support | Gorgias, Zendesk, Intercom, Freshdesk |
| [`ai-coding-spend`](ai-coding-spend/) | AI coding tools | Claude Code, Cursor |
| [`sheets-and-notion`](sheets-and-notion/) | Hand-maintained data | Google Sheets, Notion |

The sources are examples, not the supported list. Check what Bruin can ingest
today with the local Bruin MCP server's `bruin_get_docs_tree` (the `ingestion/`
section), and read `ingestion/<source>` before promising one.
Sources are examples; read `ingestion/<source>` before promising one. Get one
domain reconciling against its source before adding a second.

## How each skill works

Every folder holds the same three kinds of file:
Every folder holds exactly these three files:

| File | What it is |
|---|---|
| `SKILL.md` | What is specific to the domain: which templates to consider, what usually needs the user's input, what to reconcile against |
| `workflow.md` | The shared process: check Bruin is installed and its MCP server connected, work inside the user's git repository, confirm the warehouse, pick a template, set up credentials, then ask, customise, run and reconcile |
| `workflow.md` | The shared setup process, from installing Bruin to reconciling the first run |
| `analysis.md` | How to answer questions once the pipeline exists |

`workflow.md` is identical in every folder, so a skill copied on its own still
works. `tests/check.py` fails if the copies drift apart; edit one and copy it to
the rest.

The skills do not carry a fixed list of questions. Templates change, so the
agent reads the template as it is and works out what this user needs to decide.
Answers go in a `decisions.md` beside the pipeline.

## Start here
`workflow.md` is identical in every folder, so a skill copied alone still works.
`tests/check.py` fails if the copies drift; edit one and copy it to the rest.

Take the domain that answers the question you actually have. Most startups
should get one domain reconciling against its own source before adding a second.
Connecting five sources before any of them is trusted produces a dashboard
nobody believes.
The skills carry no fixed list of questions: the agent reads the template as it
is today and works out what this user must decide. Answers go in `decisions.md`
beside the pipeline.

## The joins are where the value is

Each domain answers useful questions alone. The ones worth the setup cross two:
The questions worth the setup cross domains:

| Question | Domains |
|---|---|
| Which customers are about to churn | revenue + product |
| Which channels bring customers who stay | marketing + revenue |
| Where the funnel actually leaks | web + product + revenue |
| Whether content investment pays back | ai-search-visibility + web + revenue |
| Which customers cost more to support than they pay | support + revenue |
| Actuals against the plan | sheets-and-notion + revenue or finance |

Every one of these depends on a stable shared identifier existing between the
two sources. When it does not, that is the work, and the skills say so rather
than producing a number from whichever side is available.
Each needs a stable identifier shared by the sources. Where there is none, that
is the work, and the skills say so rather than answer from one side.
66 changes: 66 additions & 0 deletions resources/startup-data-kit/ai-coding-spend/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
name: ai-coding-spend
description: Use when a startup wants AI coding tool usage and spend set up or answered. Sets up the ai-coding-usage template (Claude Code and Cursor into DuckDB) and answers adoption, active user, token, estimated cost and model mix questions by team.
---

# AI coding spend

**Status:** experimental · **Risk:** approval-required

> **Upstream documentation wins.** Where this file disagrees with the [Bruin
> docs](https://getbruin.com/docs/bruin/overview.html), `bruin --help`, or
> Anthropic's or Cursor's API documentation, those are right and this file is
> stale. Written against Bruin CLI `v0.11.766`, checked 2026-10-01.

Sets up a Claude Code and Cursor usage pipeline and answers adoption and cost
questions from it. It exists to prevent an estimated cost being read as the
bill, and usage data being turned into a ranking of engineers.

## Set up

Follow [workflow.md](workflow.md).

> **Important: do not ask a fixed list of questions.** Read the template as it
> is today and work out which of its choices this user needs to confirm.
> Templates change, so the questions change with them.

**Templates:** `ai-coding-usage`; confirm with `bruin init --help`. Not on
DuckDB: read `ingestion/anthropic` and `ingestion/cursor`; the modelling is
theirs to build.

**Watch for:**

- Coverage is Claude Code on the first-party Anthropic API, and Cursor; Bedrock, Vertex AI, Foundry, Claude Platform on AWS, Claude Enterprise claude.ai users and every other tool are silently missing.
- Cost columns are estimates, not the bill, built differently per vendor, with no seat fees; no seat list is ingested.
- History lives only in the marts; `--full-refresh` drops it.

**Usually needs the user's input:**

- What "cost" should mean: spend, consumption, or both.
- Billing model: seats, pay-as-you-go or mixed, and whether to carry it into the marts.
- Identity: the cross-platform join is lowercased email; aliases, contractors, second accounts.
- Teams: neither source has one; a mapping from email to team, and where it lives.
- Seats: utilisation needs a seat or member list added.
- Users to exclude: test accounts, shared or CI keys, departed staff.
- How far back history matters.

**Reconcile against:** each vendor's own usage page for one settled UTC day;
tokens and active users should match, cost only once "cost" is defined.

## Answer questions

Read [analysis.md](analysis.md).

## Never

- Ask for or print a credential; write, run, backfill, `--full-refresh` or
touch production without a yes; put personal data in output.
- Rank, score or judge individual engineers from usage; report at team or organisation level.
- Call estimated cost "spend" or "the bill" without saying what it includes.
- Write to Anthropic or Cursor, or use an admin key outside the pipeline's ingestion.

## Unverified

- Whether rerunning a day duplicates Claude Code rows; after a rerun, check `raw.claude_code_usage` for repeated keys.
- How Anthropic computes `estimated_cost`, and whether it is filled for subscription usage; compare one day with the Console.
- Whether a read-only Cursor key covers the analytics endpoints; with approval, try one on a one-day run.
31 changes: 31 additions & 0 deletions resources/startup-data-kit/ai-coding-spend/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Answering AI coding spend questions

> **Upstream documentation wins.** Where this file disagrees with the [Bruin
> docs](https://getbruin.com/docs/bruin/overview.html), `bruin --help`, or
> Anthropic's or Cursor's API documentation, those are right and this file is
> stale. Written against Bruin CLI `v0.11.766`, checked 2026-10-01.

Read `decisions.md` beside the pipeline's `pipeline.yml` first. The Never rules
in [SKILL.md](SKILL.md) apply.

## Before answering

- Read the mart assets before writing SQL, and query the marts; raw and staging may hold only the last run's window.
- Check freshness: the last runs (Bruin Cloud MCP or `bruin cloud runs list`), then gaps per platform; one vendor missing days reads as a usage drop or a tool shift.
- State the definition, exact UTC window, coverage and what cost includes with every number.

## Traps

- Estimated cost is consumption at the vendor's rate, not spend; say which vendor dominates a total.
- When cost moves, check tokens and model mix first; cache reads inflate token totals cheaply.
- `sessions`, `requests` and `lines_added` are different measures per platform; compare platforms on tokens, active users and active days.
- Anthropic rows using several models arrive combined as a model set; do not split them, show their share.
- API-key actors are not people but count as active users; separate them, and check email overlap before counting cross-platform users.
- Adoption needs a denominator (seats or headcount) from outside the pipeline, and "active" needs the user's definition.

## What this data cannot tell you

- Productivity, quality or value; lines, tokens and commits measure activity.
- Who is a good engineer; heavy and light use each have good and bad explanations.
- ROI, without an outcome measure from elsewhere, and then only as a correlation.
- Use outside the covered channels.
108 changes: 108 additions & 0 deletions resources/startup-data-kit/ai-coding-spend/workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Setting up a template with the user

> **Upstream documentation wins.** Where this file disagrees with the [Bruin
> docs](https://getbruin.com/docs/bruin/overview.html) or `bruin <command>
> --help`, upstream is right and this file is stale. Written against Bruin CLI
> `v0.11.766`, checked 2026-10-01.

Identical in every startup-data-kit skill. Work in order.

## Working with the user

- **Check before acting;** say what you found. Never redo working steps.
- **Ask before every write** (install, init, config, model, run); show the diff, wait for a yes.
- **Ask a few questions at a time,** each with its default and the term in plain words.
- **Do not guess.** If the user does not know, record the default as unconfirmed.
- **When only the user can do a step,** give exact steps and wait.
- **Record answers in `decisions.md` beside `pipeline.yml`:** choice, pick, confirmed or default, date.

## Look it up live

- Commands and flags: `bruin <command> --help`.
- Docs: Bruin MCP `bruin_get_doc_content` for `getting-started/templates-docs/<name>-README`, `ingestion/<source>`, `platforms/<warehouse>`; or `https://getbruin.com/docs/bruin/<path>.html`.
- The user's pipelines, runs and connections: Bruin Cloud MCP (`cloud/mcp-setup`), if they run Bruin Cloud.

## 1. Bruin is installed

`bruin version`. If `Latest` is newer than `Current`, offer `bruin upgrade`. If missing, ask, then `curl -LsSf https://getbruin.com/install/cli | sh`; on Windows or failure, read `getting-started/introduction/installation`.

## 2. The Bruin MCP server is connected

If you lack the `bruin_get_doc_content` tool, read `getting-started/bruin-mcp`.

- If you can edit the host's MCP config, show the exact command (Claude Code: `claude mcp add bruin -- bruin mcp`) and its project or global scope; run it only after approval.
- Otherwise give the user the snippet; the host usually needs a restart.

## 3. You are inside the user's own git repository

`git rev-parse --show-toplevel`.

- **Not a repository:** ask which folder, then `git init`; otherwise `bruin init` creates a `bruin/` wrapper with its own git.
- **A repository:** confirm it is the user's, not a public catalogue or another Bruin project (a parent `.bruin.yml` gets picked up).
- **Bruin project exists:** ask whether to add (`--merge`; read `commands/init`) or start fresh.

## 4. Confirm the warehouse

Ask where the data lands; do not pick. It decides which templates exist.

- **None yet:** list destinations this domain's templates support (`bruin init --help`) and their setup cost; some run on local DuckDB.
- **No template supports it:** say so; offer the closest template elsewhere, or ingestion alone. Never improvise one.

## 5. Choose the template

1. `bruin init --help` for current names; keep those matching source and warehouse.
2. Read each candidate's README; if none, say so and read the scaffolded `README.md`.
3. Tell the user what each builds, needs and omits. Let them choose.
4. After a yes, `bruin init <template>`. If it opens an interactive wizard, give the user the command.
5. Read the scaffolded files, run `bruin validate <pipeline-folder>`, and tell the user anywhere they disagree with the README or fail.

If nothing fits, say so; agree before building modelling yourself. If no pipeline is needed, say so.

## 6. Credentials into `.bruin.yml`

The README and assets name the connections. A sample's inline key is a shape, not a value.

**Never ask for a credential in chat or pass one as a command argument.** If the user pastes one, tell them to rotate it.

1. Read `ingestion/<source>` or `platforms/<warehouse>` for the fields.
2. Walk the user to the narrowest credential: read-only or restricted, never admin when narrower exists.
3. The user sets an env var (gitignored `.env` or secret manager); you write `${VAR_NAME}` (`secrets/bruinyml`). Or the user runs `bruin connections add` with no flags.
4. `bruin connections test --name <connection>`. Report the result, never the value.

`git check-ignore .bruin.yml`; if not ignored, stop and fix first. Bruin Cloud: `bruin cloud login` or exported `BRUIN_CLOUD_API_KEY`, never `--api-key`.

## 7. Work out what to ask

> **The questions come from the template, not from a list.** Templates change:
> variables are added, defaults move, reports appear and disappear. Do not work
> from a remembered or hard-coded set of questions, including any in these
> files. Read the template as it is today, list every choice it makes on the
> user's behalf, and decide which ones this user needs to confirm.

- Read the README, `pipeline.yml` variables, asset filters, checks, and report metric definitions.
- Drop choices that do not apply; `SKILL.md` is a lens, not a script.
- Add what the template cannot infer (test accounts, history needed); lead with what moves headline numbers.

## 8. Customise

- Prefer a `pipeline.yml` variable to SQL edits; keep SQL edits small and update the asset description.
- After each change: `bruin validate <pipeline-folder>`, show the diff, record it.

## 9. First run, bounded

Agree and state back, then `bruin run --environment <env> --start-date <from> --end-date <to> <pipeline-folder>`:

- **Environment:** `bruin environments list`; creating one needs approval.
- **Window:** a local run defaults to yesterday only. Say the expected scan.
- **README first-load steps:** if one is `--full-refresh`, name what it replaces before asking.

## 10. Reconcile with the user

Compare one number from the source's own dashboard.

- **Differs only by a recorded decision:** note it in `decisions.md`.
- **Differs unexplained:** stop; investigate before anyone uses the reports.

## 11. Hand off

Report template, warehouse, environment, window, unconfirmed decisions, what is scheduled (nothing unless asked), and what to connect next. Then follow `analysis.md`.
Loading
Loading