diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index adbf571..586eec2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,6 +60,9 @@ The rules the checker enforces: - Every resource is listed in the root `README.md` index. - Local links resolve, and no internal identifiers (Slack channel IDs, project ULIDs, service accounts) or forbidden files (`.bruin.yml`, `.env`) appear. +- Files shared across a group of skills stay identical. Every + `startup-data-kit` skill carries the same `workflow.md`; change one copy and + copy it to the rest. Push depth into sibling files referenced by relative path, so `SKILL.md` stays short enough to load whole. The checker warns past 2,000 words. diff --git a/README.md b/README.md index bc3f1aa..1fa7b76 100644 --- a/README.md +++ b/README.md @@ -30,16 +30,17 @@ saying there as much as in an issue. |---|---|---|---| | [`bruin-agent`](resources/bruin-agent/) | experimental | read-only | Installing the Bruin CLI, creating a project, choosing a template, connecting a source, registering the Bruin MCP server, installing Bruin's agent skills | -**[`startup-data-kit`](resources/startup-data-kit/)**: answering business -questions from a startup's data, one domain per folder: +**[`startup-data-kit`](resources/startup-data-kit/)**: an agent works with you +to set up and customise a Bruin template for your startup, then answers +questions from it. One domain per folder: | Resource | Status | Risk | Use it when | |---|---|---|---| -| [`revenue-analytics`](resources/startup-data-kit/revenue-analytics/) | experimental | read-only | MRR, churn, expansion, failed payments, cash collection. Stripe, Chargebee, Paddle | -| [`marketing-analytics`](resources/startup-data-kit/marketing-analytics/) | experimental | read-only | CAC, ROAS, attribution, campaigns, CRM pipeline. Google Ads, Meta, HubSpot, Klaviyo | -| [`product-analytics`](resources/startup-data-kit/product-analytics/) | experimental | read-only | Activation, feature adoption, retention, usage-based churn signals. PostHog, Mixpanel, Amplitude | -| [`web-analytics`](resources/startup-data-kit/web-analytics/) | experimental | read-only | Traffic, landing pages, channels, funnel drop-off. GA4, Search Console | -| [`ai-search-visibility`](resources/startup-data-kit/ai-search-visibility/) | experimental | read-only | SEO, GEO and AEO. Search Console, AI crawler traffic, whether assistants mention you | +| [`revenue-analytics`](resources/startup-data-kit/revenue-analytics/) | experimental | approval-required | MRR, churn, expansion, failed payments, cash collection. Stripe, Chargebee, Paddle | +| [`marketing-analytics`](resources/startup-data-kit/marketing-analytics/) | experimental | approval-required | CAC, ROAS, attribution, campaigns, CRM pipeline. Google Ads, Meta, HubSpot, Klaviyo | +| [`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 | **[`data-engineering-skills`](resources/data-engineering-skills/)**: keeping pipelines healthy. Install Bruin's seven maintained skills, then add the diff --git a/resources/startup-data-kit/README.md b/resources/startup-data-kit/README.md index 70c0a45..f635511 100644 --- a/resources/startup-data-kit/README.md +++ b/resources/startup-data-kit/README.md @@ -3,11 +3,13 @@ > **Upstream documentation wins.** Where a skill here disagrees with the tool's > own documentation or its `--help` output, upstream is right and the file here > is stale. Each skill states the version and date it was written against. -> Checked 2026-09-30. +> Checked 2026-10-01. -Answering business questions from a startup's data. One resource per domain, -because the traps are domain-specific: what ruins a revenue number is not what -ruins an attribution number. +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. @@ -23,12 +25,27 @@ 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/` before promising one. -## Start here +## How each skill works + +Every folder holds the same three kinds of file: + +| 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 | +| `analysis.md` | How to answer questions once the pipeline exists | -Set up Bruin first with [`../bruin-agent`](../bruin-agent/): CLI, project, -template, connection, agent skills. +`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 -Then take the domain that answers the question you actually have. Most startups +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. diff --git a/resources/startup-data-kit/ai-search-visibility/SKILL.md b/resources/startup-data-kit/ai-search-visibility/SKILL.md index 83fdabd..1fb4c17 100644 --- a/resources/startup-data-kit/ai-search-visibility/SKILL.md +++ b/resources/startup-data-kit/ai-search-visibility/SKILL.md @@ -1,18 +1,22 @@ --- name: ai-search-visibility -description: Use when working on SEO, GEO or AEO, measuring whether a brand appears in AI assistant answers, tracking AI crawler traffic from GPTBot or ClaudeBot, analysing Search Console performance, or deciding what content to write for search and AI answer engines. +description: Use when a startup wants SEO, GEO or AEO measurement set up or answered. Works out with the user which question they have (Search Console performance, appearing in AI assistant answers, or AI crawlers such as GPTBot and ClaudeBot fetching the site), sets up and customises the closest Bruin template or ingestion, says plainly where Bruin has no connector, then answers visibility and content questions from it. --- # Search and AI answer visibility -**Status:** experimental · **Risk:** read-only +**Status:** experimental · **Risk:** approval-required > **Upstream documentation wins.** Where this file disagrees with the [Bruin -> docs](https://getbruin.com/docs/bruin/overview.html), Google's Search Console -> documentation, or a measurement tool's own documentation, those are right and -> this file is stale. This area moves faster than any other in this repository, -> so treat specifics here as a starting point rather than current fact. Written -> against Bruin CLI `v0.11.765`, checked 2026-09-30. +> docs](https://getbruin.com/docs/bruin/overview.html), `bruin --help`, Google's +> Search Console documentation, or a measurement tool's own documentation, those +> are right and this file is stale. This area moves faster than any other in +> this repository, so treat specifics here as a starting point rather than +> current fact. Written against Bruin CLI `v0.11.765`, checked 2026-10-01. + +Two jobs. **Set up:** work with the user to get the data for the question they +actually have, from the closest Bruin template or ingestion, customised to this +site. **Answer:** questions from what it built, in [analysis.md](analysis.md). Three overlapping things sit under this heading: @@ -22,10 +26,8 @@ Three overlapping things sit under this heading: - **AI crawler traffic**, whether assistants are fetching the site at all. Measurable from server logs today. -Be straight about which of the three a question is actually about. They need -different data and have very different evidence quality. - -Setup is in the `bruin-agent` skill. This assumes a project exists. +They need different data and have very different evidence quality. Be straight +about which one a request is actually about. ## Look it up live @@ -35,160 +37,135 @@ themselves, ask the tool, and tell the user if it disagrees with this file: - **Flags:** `bruin --help`. The docs lag the CLI. - **Docs:** the local Bruin MCP server, `bruin_get_doc_content('')`, or `https://getbruin.com/docs/bruin/.html` without it. For this skill: + `getting-started/templates-docs/google-web-analytics-README` for the template, `ingestion/gsc` and `ingestion/google_analytics` for the Google connectors, - `getting-started/templates-docs/google-web-analytics-README` for the template - that models both exports, `ingestion/s3` and `ingestion/gcs` for loading log - files, and `ingestion/g2` and `ingestion/trustpilot` for review sites. + `ingestion/s3` and `ingestion/gcs` for loading log files, and `ingestion/g2` + and `ingestion/trustpilot` for review sites. +- **A sampling tool:** its own documentation or MCP server. It is not Bruin. - **The user's environment:** Bruin Cloud MCP, or `bruin cloud ... --output json`. -**Credentials.** Never ask for one in chat or pass one as a command argument. -For a source, the user runs `bruin connections add` with no flags (the -interactive prompt; its flag mode puts the secret on the command line) or -references `${VAR}` in `.bruin.yml`. For Cloud, `bruin cloud login` or an -exported `BRUIN_CLOUD_API_KEY`, never `--api-key`. `bruin auth status` shows -which is active without printing it. - -## What Bruin can ingest directly - -- **Search Console performance:** `ingestion/gsc`. The service account has to - be added as a user on the property before anything loads. -- **GA4, for what search traffic then does:** `ingestion/google_analytics`. -- **Both, already exported to BigQuery:** the `google-web-analytics` template. -- **Server and CDN logs, for crawler traffic:** `ingestion/s3` or - `ingestion/gcs`. See below. -- **Review-site presence:** `ingestion/g2`, `ingestion/trustpilot`. - -**There is no Bruin connector for AI answer visibility.** That measurement comes -from third-party tools that sample assistant responses on a schedule. Say so -rather than implying the pipeline can produce it. - -Cloudflare Radar (`ingestion/cloudflare-radar`) is Internet-wide aggregate data, -not this site's traffic or crawler logs. Use it for context only. - -## Search Console, the honest baseline - -This is where real, verifiable data lives. - -- No sessions, no revenue. GSC clicks will not match GA4 organic sessions. -- Roughly 16 months of history. Load it into the warehouse if longer matters. -- Two to three days of lag, and past days are revised in place. Leave the most - recent days out of any comparison. -- Anonymised queries are excluded from query-level rows but counted in totals, - so breakdowns will not sum to the total. Do not try to reconcile them. -- Average position is an average across impressions, weighted oddly. Averaging - it across queries compounds the problem. Prefer distributions. - -If the user is on the `google-web-analytics` template, it already builds query -opportunities (`gsc_query_opportunities`), page decay (`gsc_page_trend`), new -and lost queries (`gsc_new_and_lost_queries`) and the landing-page join to GA4 -(`ga4_gsc_landing_page_performance`). Read its README and use those before -writing your own. Which organic pages produce paying customers still needs a -landing-page-to-signup key. - -## Measuring AI answer visibility - -There is no crawl you can run to answer "do we appear in ChatGPT". Assistant -answers vary by user, by session, by phrasing and by date. Any measurement is -sampling, not observation. - -What that means in practice: - -- **Sampling tools** run a fixed prompt set on a schedule against several - assistants and record whether a brand was mentioned and which sources were - cited. [Peec AI](https://peec.ai) is one such tool and exposes an MCP server, - so an agent can query it directly. There are others. None of them observe real - user conversations. -- **Brand mention and source citation are independent.** Being cited as a source - and being recommended are different outcomes and need separate reads. -- **Prompt sets determine the score.** Adding, removing or reweighting prompts - moves visibility without anything changing about what assistants say. Never - treat prompt-set changes as an improvement, and be suspicious of branded - prompts, which score high only because the brand is in the question. -- **Position and share of voice** are only comparable within a fixed prompt set - over time. - -When asked "how visible are we in AI search", the honest answer names the tool, -the prompt set, the assistants sampled, and the date range. Without those the -number means nothing. - -## AI crawler traffic, the measurable part - -Server and CDN logs show which AI crawlers fetch the site. This is real -observation rather than sampling, and it is underused. - -Common agents to look for: `GPTBot`, `OAI-SearchBot`, `ChatGPT-User`, -`ClaudeBot`, `Claude-User`, `PerplexityBot`, `Google-Extended`, `Bytespider`, -`Applebot-Extended`, `CCBot`. - -Worth distinguishing: training crawlers, search-index crawlers, and live -user-triggered fetches. A live fetch means a real person asked something and an -assistant went to the site to answer it, which is the closest thing to a -conversion signal this category has. - -Ingest logs from wherever the stack writes them, through `ingestion/s3` or -`ingestion/gcs`. Both read CSV, JSONL and Parquet, so a log in any other shape -needs converting before it loads. Check `robots.txt` first: if these agents are -disallowed, absence is the explanation and no amount of content work will -change it. - -## Referral traffic from assistants - -GA4 shows referrals from `chatgpt.com`, `perplexity.ai`, `claude.ai` and -similar. Volumes are usually small but the traffic often converts unusually well, -because the person arrived with intent already formed. - -Track it as its own channel rather than letting it fall into direct or generic -referral. It is the only place where AI visibility connects to revenue with -evidence rather than inference. - -## Content work: what the evidence actually supports - -Keep recommendations to things with a mechanism, not a listicle. - -Reasonable: - -- Answer a specific question directly and early on the page. Both search - features and assistants extract passages. -- Keep facts current and dated. Stale figures get cited and embarrass you. -- Structured data where it maps to a real entity or product. -- Be citable: clear claims, primary sources, a stable URL. -- Presence on the sites assistants actually cite for your category, which is - often documentation, comparison sites and communities rather than your blog. -- Allow the crawlers you want to be cited by. - -Unsupported, and worth pushing back on: - -- `llms.txt` as a ranking lever. No major assistant has committed to it. -- Keyword density, word count targets, and generated content at volume. -- Any claim of a fixed technique that "gets you into ChatGPT". - -Google's own guidance for AI search still points back to useful, original, -trustworthy content. Say that when asked for a shortcut. +## Setting it up + +Follow [workflow.md](workflow.md) from the top: install, MCP, repository, +warehouse, template, credentials, then the questions. It is the same process +for every skill in this kit. What is specific to search and AI visibility is +below. + +> **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. Workflow step 7 says how. + +Start by asking which of the three questions the user has. The answer decides +which path below applies, and whether a Bruin pipeline is needed at all. + +### Templates to consider + +There is no Bruin template for AI answer visibility. Check `bruin init --help` +for anything new, then match each question to a path: + +| Path | SEO | AI answer visibility | AI crawler traffic | +|---|---|---|---| +| `google-web-analytics` template | Yes | No | No | +| `ingestion/gsc` alone | Yes, unmodelled | No | No | +| Logs through `ingestion/s3` or `ingestion/gcs` | No | No | Yes, unmodelled | +| A third-party sampling tool, such as Peec AI | No | Yes, sampled | No | + +- **`google-web-analytics`** is BigQuery only and ingests nothing. It reads the + GA4 BigQuery export and the Search Console bulk data export, which must + already be running. Neither export backfills, so history starts the day each + was enabled. It needs the GA4 streaming export (`events_intraday_*`); without + it every GA4 model is silently empty. Read the README's scope section before + the first run. +- **`ingestion/gsc`** reads the Search Console API into any warehouse, with + roughly 16 months of history and no reports. Use it when the warehouse is not + BigQuery, the bulk export is not enabled, or history before the export + matters. The modelling is yours; agree that before starting. +- **Crawler logs** have no template. `ingestion/s3` and `ingestion/gcs` read + CSV, JSONL and Parquet, gzipped or not. A log in any other shape needs + converting before it loads. Classifying user agents is modelling you build. +- **AI answer visibility has no Bruin connector.** That measurement comes from + third-party tools that sample assistant responses on a schedule. Set it up in + the tool, following its own documentation. Say so rather than implying the + pipeline can produce it. If this is the only question, no Bruin pipeline is + needed. +- **Review sites:** `ingestion/g2` and `ingestion/trustpilot` load presence on + sites assistants may cite. Ingestion only. +- **Cloudflare Radar** (`ingestion/cloudflare-radar`) is Internet-wide aggregate + data, not this site's traffic or crawler logs. Use it for context only. Its + docs page says runs fail until Bruin's pinned ingestr version includes it. + +### What usually matters here + +A lens for reading the template, not a script. For each, find what the template +or ingestion does, then ask only where this site makes it matter. + +- **Which of the three questions:** often more than one, rarely all three. +- **Search Console properties:** Domain or URL-prefix, and whether subdomains + or a separate blog are their own properties. The service account has to be + added as a user on each property before anything loads. +- **Export state:** whether the GA4 and Search Console BigQuery exports are + enabled, and since when. +- **Brand and competitor names:** branded demand measures awareness, not SEO + work. Splitting it out changes every headline trend. +- **Site structure:** which paths are product, content, docs or support, and + whether URLs carry meaningful query parameters or locale prefixes. +- **Outcomes after the click:** which events count, and how they are valued. + Modelled value is not revenue. +- **Assistant referrals:** whether `chatgpt.com`, `perplexity.ai` and similar + should be their own channel. Check how the template classifies channels. +- **Logs:** which source exists (CDN, origin server), where it writes, and in + what format. +- **Log retention:** how long the bucket keeps logs. Once older logs expire, + the warehouse is the only copy. +- **Which crawlers to track:** start from the list in + [analysis.md](analysis.md), and check `robots.txt` before reading absence as + a signal. +- **Sampling tool setup:** the prompt set, the competitors and the assistants + sampled. A change to any of them moves the score. +- **History:** how far back it matters, and whether this path can reach it. + +### Reconcile against + +- **Search Console:** clicks and impressions in the Search Console interface + for a settled window, excluding the last three days. Compare property-level + totals, not URL or query rows, which do not sum to them. +- **Crawler logs:** row counts for one day against the CDN's or server's own + request analytics for the same window and timezone. +- **Sampling tools:** nothing in Bruin to reconcile. Read the tool's own + dashboard, and state its prompt set and date range with any number. + +Record each gap and its explanation in `decisions.md`. + +## Answering questions afterwards + +Read [analysis.md](analysis.md): what Search Console can and cannot show, how to +report sampled AI visibility, what crawler logs measure, and which content work +has evidence behind it. If the user is on a template, read its report assets +before writing any SQL. ## Never - **Ask for a credential** in chat or as a command argument. A Google service - account key is a private key. See **Credentials** above. + account key is a private key. If offered one, say not to send it and to rotate + it if already sent. Workflow step 6 has the safe path. +- **Print a credential**, including in errors, summaries and generated files. +- **Run against production** unless asked by name. Say which environment you used. +- **Pull raw log rows or session records into context** when an aggregate + answers the question. +- **Put a raw URL in output without stripping its parameters.** Query strings + carry session tokens, reset links and personal data. - **Publish content.** Drafting is fine; pushing to a CMS, a repository or a live site is a write. Propose it and let a person publish. - **Change `robots.txt` or crawler directives** without explicit approval. A wrong line here can deindex a site. -- **Put a raw URL in output without stripping its parameters.** Query strings - carry session tokens, reset links and personal data. - -## What this cannot tell you - -| Asked | Actually needed | -|---|---| -| "Are we in ChatGPT?" | A sampled prompt set with a stated date. There is no ground truth. | -| "Why did rankings drop?" | Usually an algorithm update or a site change. Check the deploy log and update timelines before theorising. | -| "How much revenue does SEO bring?" | Landing page carried through to signup and payment. Without that key, organic stops at clicks. | -| "What should we write next?" | A gap between what people ask and what the site answers. GSC impressions without clicks is the best available proxy. | - -Report what is measured, what is sampled, and what is inferred. In this category -that distinction matters more than in any other. - -## Reference - -- Traffic side: [../web-analytics/SKILL.md](../web-analytics/SKILL.md) +- **Write without asking.** Installing, initialising, editing configuration or + models, and running a pipeline all wait for the user's yes. + +Stop and ask before any write to a source system, outbound message, +publication, credential change, production access, `--full-refresh` or backfill. +`--full-refresh` drops and recreates tables. On `google-web-analytics` the first +run and any change to a classification variable need one on staging; scope it +to the earliest export date and say the expected scan. On a log table whose +bucket has expired old files, it discards history the source no longer holds. +Name that consequence. diff --git a/resources/startup-data-kit/ai-search-visibility/analysis.md b/resources/startup-data-kit/ai-search-visibility/analysis.md new file mode 100644 index 0000000..e2740d8 --- /dev/null +++ b/resources/startup-data-kit/ai-search-visibility/analysis.md @@ -0,0 +1,140 @@ +# Answering search and AI visibility questions + +> **Upstream documentation wins.** Where this file disagrees with the [Bruin +> docs](https://getbruin.com/docs/bruin/overview.html), Google's Search Console +> documentation, or a measurement tool's own documentation, those are right and +> this file is stale. This area moves faster than any other in this repository, +> so treat specifics here as a starting point rather than current fact. Written +> against Bruin CLI `v0.11.765`, checked 2026-10-01. + +Read this once data exists and the user is asking questions of it. If +`decisions.md` sits beside the pipeline's `pipeline.yml`, read it first: it +records which choices this setup follows. The `Never` rules in `SKILL.md` apply +here too. + +## Before answering + +1. **Name which of the three the question is about.** SEO, AI answer + visibility, or AI crawler traffic. They need different data and have very + different evidence quality. +2. **Read the model before querying it.** If the user is on a template, read its + report assets and their descriptions before writing any SQL. +3. **Check freshness first.** Read the last runs from Bruin Cloud MCP or + `bruin cloud runs list --output json`, then the maximum date in the raw + table. + +## Search Console, the honest baseline + +This is where real, verifiable data lives. + +- No sessions, no revenue. GSC clicks will not match GA4 organic sessions. +- Roughly 16 months of history through the API. Load it into the warehouse if + longer matters. The bulk data export starts the day it was enabled and does + not backfill. +- Two to three days of lag, and past days are revised in place. Leave the most + recent days out of any comparison. +- Anonymised queries are excluded from query-level rows but counted in totals, + so breakdowns will not sum to the total. Do not try to reconcile them. +- Average position is an average across impressions, weighted oddly. Averaging + it across queries compounds the problem. Prefer distributions. + +If the user is on the `google-web-analytics` template, it already builds query +opportunities (`gsc_query_opportunities`), page decay (`gsc_page_trend`), new +and lost queries (`gsc_new_and_lost_queries`) and the landing-page join to GA4 +(`ga4_gsc_landing_page_performance`). Read its README and use those before +writing your own. Its value columns are modelled from weights on key events, not +recognised revenue, so say so. Which organic pages produce paying customers +still needs a landing-page-to-signup key. + +## Measuring AI answer visibility + +There is no crawl you can run to answer "do we appear in ChatGPT". Assistant +answers vary by user, by session, by phrasing and by date. Any measurement is +sampling, not observation. + +What that means in practice: + +- **Sampling tools** run a fixed prompt set on a schedule against several + assistants and record whether a brand was mentioned and which sources were + cited. [Peec AI](https://peec.ai) is one such tool and exposes an MCP server, + so an agent can query it directly. There are others. None of them observe real + user conversations. +- **Brand mention and source citation are independent.** Being cited as a source + and being recommended are different outcomes and need separate reads. +- **Prompt sets determine the score.** Adding, removing or reweighting prompts + moves visibility without anything changing about what assistants say. Never + treat prompt-set changes as an improvement, and be suspicious of branded + prompts, which score high only because the brand is in the question. +- **Position and share of voice** are only comparable within a fixed prompt set + over time. + +When asked "how visible are we in AI search", the honest answer names the tool, +the prompt set, the assistants sampled, and the date range. Without those the +number means nothing. + +## AI crawler traffic, the measurable part + +Server and CDN logs show which AI crawlers fetch the site. This is real +observation rather than sampling, and it is underused. + +Common agents to look for: `GPTBot`, `OAI-SearchBot`, `ChatGPT-User`, +`ClaudeBot`, `Claude-User`, `PerplexityBot`, `Google-Extended`, `Bytespider`, +`Applebot-Extended`, `CCBot`. + +Worth distinguishing: training crawlers, search-index crawlers, and live +user-triggered fetches. A live fetch means a real person asked something and an +assistant went to the site to answer it, which is the closest thing to a +conversion signal this category has. + +Check `robots.txt` first: if these agents are disallowed, absence is the +explanation and no amount of content work will change it. + +## Referral traffic from assistants + +GA4 shows referrals from `chatgpt.com`, `perplexity.ai`, `claude.ai` and +similar. Volumes are usually small but the traffic often converts unusually well, +because the person arrived with intent already formed. + +Track it as its own channel rather than letting it fall into direct or generic +referral. It is the only place where AI visibility connects to revenue with +evidence rather than inference. + +## Content work: what the evidence actually supports + +Keep recommendations to things with a mechanism, not a listicle. + +Reasonable: + +- Answer a specific question directly and early on the page. Both search + features and assistants extract passages. +- Keep facts current and dated. Stale figures get cited and embarrass you. +- Structured data where it maps to a real entity or product. +- Be citable: clear claims, primary sources, a stable URL. +- Presence on the sites assistants actually cite for your category, which is + often documentation, comparison sites and communities rather than your blog. +- Allow the crawlers you want to be cited by. + +Unsupported, and worth pushing back on: + +- `llms.txt` as a ranking lever. No major assistant has committed to it. +- Keyword density, word count targets, and generated content at volume. +- Any claim of a fixed technique that "gets you into ChatGPT". + +Google's own guidance for AI search still points back to useful, original, +trustworthy content. Say that when asked for a shortcut. + +## What this cannot tell you + +| Asked | Actually needed | +|---|---| +| "Are we in ChatGPT?" | A sampled prompt set with a stated date. There is no ground truth. | +| "Why did rankings drop?" | Usually an algorithm update or a site change. Check the deploy log and update timelines before theorising. | +| "How much revenue does SEO bring?" | Landing page carried through to signup and payment. Without that key, organic stops at clicks. | +| "What should we write next?" | A gap between what people ask and what the site answers. GSC impressions without clicks is the best available proxy. | + +Report what is measured, what is sampled, and what is inferred. In this category +that distinction matters more than in any other. + +## Reference + +- Traffic side: [../web-analytics/SKILL.md](../web-analytics/SKILL.md) diff --git a/resources/startup-data-kit/ai-search-visibility/workflow.md b/resources/startup-data-kit/ai-search-visibility/workflow.md new file mode 100644 index 0000000..591061d --- /dev/null +++ b/resources/startup-data-kit/ai-search-visibility/workflow.md @@ -0,0 +1,232 @@ +# 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 +> --help`, upstream is right and this file is stale. Written against Bruin CLI +> `v0.11.765`, checked 2026-10-01. + +Every skill in the startup data kit carries an identical copy of this file. +The skill's own `SKILL.md` says which templates fit its domain and what tends to +matter there; this file is the process. Work through it in order. + +## Working with the user + +This is a conversation, not a script. The point of a maintained template is +that the modelling is done; the point of this process is that it ends up +modelling *this* startup, not a generic one. + +- **Check before acting.** Most users have done some of this already, and + redoing a step is how a working setup gets broken. Say what you checked and + what you found. +- **Ask before every write.** Installing, initialising, editing configuration, + changing a model, running a pipeline: say exactly what will change and wait + for a yes. Show diffs. +- **Ask a few questions at a time, each with the default.** For every choice, + say what the template does today, what the alternative would change, and why + it matters. "Keep the default" should be an easy answer. +- **Explain the term, not just the question.** Many founders are not data + people. "MRR counted at month end" means nothing until you say what it does + to a mid-month signup. +- **Do not guess an answer.** If the user does not know, propose the default + and record it as unconfirmed. A choice the user did not make should not read + as though they did. +- **When only the user can do a step**, give them the exact steps and wait + until they say it is done. +- **Write the answers down** as you go, in a `decisions.md` beside the + pipeline's `pipeline.yml`: each choice, what was picked, whether the user + confirmed it or it is still the template's default, and the date. The next + agent, and the user in six months, will need it. + +## 1. Bruin is installed + +```bash +bruin version +``` + +- **Installed and current:** move on. +- **Installed, but `Latest` is newer than `Current`:** offer `bruin upgrade`. + Do not run it unasked. +- **Not installed:** ask, then run + `curl -LsSf https://getbruin.com/install/cli | sh` and check `bruin version` + again. On Windows, or if the install fails, read + `getting-started/introduction/installation` rather than guessing. + +## 2. The Bruin MCP server is connected + +Check whether you already have the `bruin_get_docs_tree` and +`bruin_get_doc_content` tools. If you do, move on. + +If not, register it, because the rest of this skill reads Bruin's docs through +it. Until then, read the same pages at +`https://getbruin.com/docs/bruin/.html`; the setup page is +`getting-started/bruin-mcp`. + +- **If your host lets you change its MCP configuration**, show the exact + command or snippet from that page, say which file it changes and whether that + affects only this project or every project, and run it only after the user + approves. For Claude Code the page gives `claude mcp add bruin -- bruin mcp`. +- **If you cannot**, walk the user through it: the snippet for their host, where + it goes, and that the host usually needs a restart or reload before the tools + appear. + +The local server serves Bruin's documentation only. Bruin Cloud MCP is separate +(`cloud/mcp-setup`) and only worth setting up if the user runs Bruin Cloud. + +## 3. You are inside the user's own git repository + +```bash +git rev-parse --show-toplevel +``` + +- **Not a repository:** ask which folder the project should live in, then + `git init` there. Without a repository, `bruin init` creates a `bruin/` + wrapper folder and initialises git inside that instead. +- **A repository:** confirm it is the user's project. Never scaffold inside a + clone of a public catalogue such as this one, or inside another Bruin + project. A `.bruin.yml` higher up the tree gets picked up by mistake. +- **A Bruin project already exists here** (a `.bruin.yml`, a `pipeline.yml`): + ask whether to add to it or start fresh. Adding a template to an existing + pipeline uses `bruin init