# SeoWatcher — Content Pipeline (workflow for review)

A single end-to-end description of how SeoWatcher turns a request into a fact-grounded SEO/GEO
article draft. Share this page with the team for review; the canonical source is
`mcp/src/docs_dist/pipeline.md` in the repo, served at `https://seowatcher.org/docs/pipeline`.

## The idea

Every article is **grounded in real data** (search demand, SERP gaps, live events, maps, web) so it
survives Google's "scaled content abuse" filters. Nothing is invented — each fact traces to a
grounding corpus, and a draft is stored only after it passes automated gates.

The paid-API keys (Ahrefs, SearchApi, Ticketmaster) live **server-side** in Google Secret Manager.
A client just authorizes over MCP and gets the functionality — no keys of their own, no local setup
beyond the `/write` skill. Generation of the prose is done by the agent (Claude Code); the
deterministic stages (discover, ground, fact-check, score, store) are tools.

## Flows

| Flow | Trigger | What happens |
|---|---|---|
| **1 — Auto / multi-variant** | "write for {site}" / no topic | Asks **how many** (default 1). N>1 → picks N topics spanning content types (events/news-timely · evergreen · commercial), or the operator names them; writes + gates **each** |
| **2 — Site-targeted** | "write for {site} about {theme}" | GSC winnable queries + market-intel within the theme → pick → write |
| **3 — Topic** | "write about {keyword}" | straight to GROUND on the keyword → write |
| **Review** | open `/drafts` | article + QA panel + status lifecycle + download |

## Stages (the chain every article runs)

1. **DISCOVER** — `content_discover` (server-side; SearchApi autocomplete + Ahrefs volume/KD + SERP
   content-gap → topics scored by Opportunity and **diversified** across content types). Site mode
   also crosses GSC winnable queries (positions 11–30).
2. **GROUND** — gather the fact corpus: SearchApi (organic + People-Also-Ask), **Ticketmaster** for
   events (scoped to **big concerts, exhibitions and business events** — Sports/Film/kids excluded),
   Google Maps for local businesses, web for geography. Saved as the grounding corpus.
3. **GENERATE + HUMANIZE** — the agent writes the article grounded **only** in the corpus, in the
   category's outline (events / destination / local / commercial), removing AI-tells.
4. **GATES** — must reach PUBLISH-READY:
   - **FACT-CHECK**: every named entity attested against the corpus; every link live; glued-link lint.
   - **SCORE**: SEO/GEO/AI checks — title/meta length, keyword in H1, ≥3 H2, length, required
     schema.org (e.g. Event + FAQPage), FAQ count, freshness date, AI-tell + overclaim + mixed-currency lints.
   - On FIX, loop back and revise; nothing proceeds until both PASS.
5. **STORE** — `content_store_draft`: **rejects** unless fact-check = PASS and score ≠ FIX, **and**
   the user is within their daily quota; the draft is joined to the site by `site_id`, status `draft`.
6. **REVIEW** — `/drafts` (Google sign-in): rendered article + a separate pipeline/checks panel
   (category rationale, fact-check verdict, SEO/GEO/AI scores, which checks passed), unique shareable
   link, created/updated dates, copy/download, and the status lifecycle (draft → review → approved → published).

## Invariants (never broken)

- No draft is stored unless **both gates PASS** — no hallucinated facts, dead links, or failing checks.
- Every fact traces to the grounding corpus; **reader copy never mentions the toolchain** ("Ahrefs says…").
- Topic choice is **data-backed** (volume/KD + content-gap), never a guess.
- With N variants, that's **N independent gate passes** — each article is verified on its own.

## Access & quota

- Roles: `reader` (read), `editor` (write drafts for owned sites), `admin` (all). Per-site ownership
  via email → `inventory_people` → `inventory_site_owners` → `inventory_sites.site_id`.
- **Daily quota: 20 new posts/day per user** (default). An admin overrides it per user via
  `content_set_quota`. Editing/re-storing an existing draft is free; only new posts consume quota.

## Where the code lives (for reviewers)

| Area | Path |
|---|---|
| Skill front-door / modes | `mcp/src/skills_dist/write/SKILL.md`, `WRITE.md` |
| Pipeline architecture, humanize, market-intel | `…/write/PIPELINE.md`, `humanize.md`, `market-intel.md` |
| Category config (schema/outline/freshness) | `…/write/categories.ts` |
| Local pipeline tools | `…/write/{intel,ground,events,maps,factcheck,score,run}.ts` |
| Server discovery | `mcp/src/tools/pipeline.ts` (`content_discover`) |
| Store / quota / status | `mcp/src/tools/content.ts` (`content_store_draft`, `content_set_quota`, `content_set_status`) |
| Drafts web review | `mcp/src/drafts_page.ts`, `lib/{drafts_web,markdown,seo_checks}.ts` |
| Design / master docs | `CONTENT_DRAFTS.md`, `CLAUDE.md` (§3 collector, §4 MCP tools) |

## How to review

The whole pipeline is version-controlled in `github.com/KeyGroupGlobal/seowatcher`. Review changes as
**pull requests** (diff over the files above). For a non-GitHub read, the served skill files are
human-readable: `https://seowatcher.org/skills/write/{SKILL.md,WRITE.md,PIPELINE.md}` and `/install`.
