BUILD SPECIFICATION · v1.0 · ENGINEERING HANDOFF
Beyond AuthorityA self-improving, multi-agent content authority platform.
This document is the developer-ready technical specification for an autonomous content operating system that researches, plans, writes, fact-checks, enriches, optimizes, scores, publishes, and refreshes content at programmatic scale, while remaining structurally compliant with Google's people-first and scaled-content-abuse policies. Human involvement is designed to converge to review + approve per article.
Anti-hallucination invariant
§ 01
Executive architecture overview
The system is organized as a one-way pipeline with three feedback loops. A demand layer generates topic opportunities; a production layer (multi-agent) converts opportunities into publish-ready drafts; a distribution layer publishes to WordPress and packages for AI extraction; a learning layer ingests GA4, Search Console, and AI-citation signals to refresh winners and prune losers.
System diagram
End-to-end data flow
- A scheduled worker pulls SERP, PAA, trends, and competitor deltas → upserts
topic_opportunities. - Opportunities scoring above threshold are enqueued as
brief_jobs. - The brief generator produces a structured
content_brief(intent, entities, outline, required claims, target schema types). - Research agent fans out searches (Perplexity Sonar, Google CSE, domain-restricted) and persists
source_documentswith extracted snippets. - Writer agent drafts the article section-by-section, citing source IDs inline as machine tokens (
[[src:42]]). - Fact-check agent extracts claims, classifies them, and rejects unsupported factual / statistical / regulated claims (publish-blocking).
- Authority + SEO packaging agents inject E-E-A-T signals, GEO blocks, JSON-LD, internal links.
- QA agent scores 0–100.
<80revise, 80–89 human review, 90+ auto-eligible for publish queue. - WordPress publisher pushes draft → human one-click approval → live → IndexNow ping.
- Performance ingester correlates
article_id ↔ GSC query ↔ GA4 session ↔ AI citation mention; winners get refresh tasks, losers get rewrite or noindex tasks.
§ 02
Module-by-module technical design
The 14 modules are listed in pipeline order. Each module has a single responsibility, a typed input contract, a typed output contract, and is independently retryable.
M1
Topic Opportunity Miner
Purpose. Continuously discover ranked topic opportunities by combining SERP data, PAA, trends, and competitor deltas.
Inputs / outputs.
// input
{ niche_id: string, run_window: "daily" | "weekly" }
// output -> topic_opportunities[]
{
id, query, intent: "informational"|"commercial"|"transactional"|"navigational",
serp_difficulty: 0-100, est_volume: number, paa: string[],
competitor_gap: { competing_urls: string[], avg_word_count: number, missing_subtopics: string[] },
opportunity_score: 0-100, source_signals: object
}External APIs / models. DataForSEO or Ahrefs/Semrush API · Google Custom Search · Google Trends (unofficial pytrends) · Reddit/Quora scrapers via official APIs
Failure modes. Vendor rate limit → exponential backoff with jitter; partial run accepted; opportunities never overwrite, only upsert with new run_id.
Integration. Writes to topic_opportunities; M2 (Brief generator) consumes top-N by opportunity_score.
M2
Brief Generator
Purpose. Convert a selected opportunity into a structured, machine-actionable brief.
Inputs / outputs.
// output -> content_briefs
{
id, opportunity_id, primary_keyword, secondary_keywords[],
search_intent, target_persona, angle, outline: [{h2, h3s[], required_entities[], required_claims[]}],
schema_types: ("Article"|"FAQPage"|"HowTo"|"QAPage")[],
word_count_target: number, internal_link_targets[], readability_target: "grade-8"
}External APIs / models. Lovable AI Gateway with google/gemini-3-flash-preview by default; google/gemini-2.5-pro for high-stakes briefs.
Failure modes. If model returns invalid JSON, retry with structured output (tool calling, see §5 prompts-as-contracts). Hard fail → flag for human.
Integration. M3 research agent reads required_claims to seed search queries.
M3
Research Agent
Purpose. Gather authoritative source material per required claim, persist with provenance.
Inputs / outputs.
// output -> source_documents
{ id, brief_id, url, domain, domain_authority, fetched_at, snippet, full_text_hash,
matched_claim_id, source_class: "primary"|"secondary"|"tertiary", confidence: 0-1 }External APIs / models. Perplexity Sonar (grounded search) · Google Programmable Search · direct fetch with respect for robots.txt · arXiv / PubMed / SEC / .gov APIs for regulated domains.
Failure modes. If <2 primary sources found for a regulated claim, mark claim as ungrounded → fact-check agent will block publish.
Integration. Writes source_documents linked to claim IDs; M4 writer agent only references stored source IDs.
M4
Writer Agent
Purpose. Compose the article section-by-section using only stored sources.
Inputs / outputs.
// output -> drafts
{ id, brief_id, version, body_markdown, sections[], inline_citations: [{anchor, source_id}],
word_count, reading_grade }External APIs / models. google/gemini-2.5-pro or openai/gpt-5 via Lovable AI Gateway; reasoning effort 'medium'.
Failure modes. If a section references a source_id not present in source_documents → hard reject, regenerate that section only.
Integration. M5 fact-check, M6 authority injection consume the draft.
M5
Fact-Check Agent
Purpose. Extract every claim, classify, validate, block publish on failure. See §6.
Inputs / outputs.
// output -> claim_validations
{ id, draft_id, claim_text, class, supporting_source_ids[], confidence, status: "pass"|"warn"|"block" }External APIs / models. Lovable AI for extraction; deterministic verifier scripts for numbers (regex + cross-source agreement).
Failure modes. Any 'block' status sets draft.publish_blocked = true at the DB level (CHECK constraint).
Integration. Sets gating flag read by M11 publisher.
M6
Authority Injection Agent
Purpose. Add E-E-A-T signals: author bio, methodology block, primary-experience markers, citations footer.
Inputs / outputs.
Mutates draft.body_markdown, populates draft.author_block, draft.methodology_block, draft.references[].External APIs / models. Internal author registry; Lovable AI for experience-narrative drafting.
Failure modes. Missing author profile → fall back to editorial team author with reviewer attribution.
Integration. Outputs feed M7 SEO packaging.
M7
SEO Packaging Agent
Purpose. Generate title tag, meta description, slug, H1, excerpt, alt text, JSON-LD payloads, internal-link plan. See §7.
Inputs / outputs.
{ title_tag (≤60), meta_description (≤155), slug (kebab), h1, excerpt (≤160),
jsonld[]: schema.org payloads, internal_links: [{anchor, target_url}], image_alts[] }External APIs / models. Lovable AI; schema.org validator (deterministic); internal-link graph query.
Failure modes. Title >60 chars → deterministic truncator; invalid JSON-LD → reject, regenerate.
Integration. Output stored on draft; M8 GEO layer adds answer-first blocks.
M8
GEO / AI Visibility Agent
Purpose. Inject answer-first paragraph, key-takeaways, FAQ block, definitions, bottom-line. See §8.
Inputs / outputs.
Mutates body to ensure every required GEO block is present and within token-extractable lengths.External APIs / models. Lovable AI; deterministic block-presence linter.
Failure modes. Linter failure → regenerate missing block only.
Integration. Feeds M9 QA + scoring.
M9
QA + Scoring Engine
Purpose. Compute weighted 0–100 score across 10 dimensions; route based on threshold. See §9.
Inputs / outputs.
// output -> quality_scores
{ draft_id, dimension_scores: {factuality, originality, depth, readability, eeat,
geo_extraction, schema_validity, internal_linking, brand_voice, intent_match},
total: 0-100, decision: "publish_ready"|"human_review"|"revise" }External APIs / models. Mix of deterministic checks + Lovable AI rubric scoring (gpt-5-mini for cost).
Failure modes. Score 50–79 → loop back to writer with diff prompt; <50 → archive + alert.
Integration. publish_ready drafts enter publish_queue.
M10
Plagiarism + Duplicate-Topic Detector
Purpose. Block near-duplicate publication; ensure originality.
Inputs / outputs.
Returns similarity score vs internal corpus (pgvector cosine) and external (Copyscape/Originality.ai).External APIs / models. Originality.ai or Copyscape API; pgvector embeddings (text-embedding-3-large equivalent).
Failure modes. Internal similarity >0.85 to existing slug → block, propose merge/refresh instead.
Integration. Gating check before publish_queue.
M11
WordPress Publisher
Purpose. Create draft post via REST, upload media, assign taxonomy, inject schema. See §10.
Inputs / outputs.
Inputs: approved draft. Outputs: wp_post_id, permalink, status='draft'.External APIs / models. WordPress REST /wp/v2/posts, /wp/v2/media; Yoast or RankMath compatible meta fields.
Failure modes. WP 5xx → retry with backoff; permanent failure → put draft back in queue, alert.
Integration. Human one-click approval flips status to 'publish'.
M12
Indexing & Distribution
Purpose. Sitemap regen, IndexNow ping, social repurposing.
Inputs / outputs.
Triggers on post status=publish.External APIs / models. IndexNow (Bing/Yandex), Google Indexing API where eligible (job postings / livestream only — otherwise rely on sitemap), buffer/zapier for social.
Failure modes. IndexNow non-200 → log; never block downstream.
Integration. Notifies Learning layer to begin tracking.
M13
Performance Ingester
Purpose. Pull GA4 + Search Console + AI-citation signals; correlate to articles.
Inputs / outputs.
Writes performance_metrics rows daily.External APIs / models. GA4 Data API, Search Console API, custom AI citation tracker (see §11).
Failure modes. API quota → spread across hours; missing data day → mark gap, do not extrapolate.
Integration. Drives Learning layer decisions.
M14
Refresh + Expansion Agent
Purpose. Identify winners (refresh) and gap clusters (expand). Generate new opportunities or refresh tasks.
Inputs / outputs.
Outputs new topic_opportunities or refresh_jobs referencing existing article_id.External APIs / models. Internal queries on performance_metrics + Lovable AI for cluster naming.
Failure modes. Insufficient data (<28 days) → defer.
Integration. Closes the loop back to M1/M2.
§ 03
Data model (Postgres / Supabase)
Schema is normalized; vector embeddings live in a sibling table to avoid bloating row width. All tables have created_at, updated_at, and tenant_id for multi-niche use. RLS is enabled on every table; access is mediated by a has_role() security-definer function (see Lovable's user-roles guidance).
Core tables
-- Topic discovery
topic_opportunities (
id uuid pk, tenant_id uuid, query text, intent text,
serp_difficulty int, est_volume int, paa jsonb,
competitor_gap jsonb, opportunity_score numeric,
source_signals jsonb, status text default 'new',
created_at timestamptz, updated_at timestamptz
)
INDEX (tenant_id, opportunity_score desc), INDEX (status);
content_briefs (
id uuid pk, opportunity_id uuid fk, primary_keyword text,
secondary_keywords text[], search_intent text, persona text,
outline jsonb, schema_types text[], word_count_target int,
required_claims jsonb, status text default 'draft'
)
source_documents (
id uuid pk, brief_id uuid fk, claim_id uuid null,
url text, domain text, domain_authority int,
source_class text check (source_class in ('primary','secondary','tertiary')),
snippet text, full_text_hash text, fetched_at timestamptz,
confidence numeric check (confidence between 0 and 1)
)
UNIQUE (brief_id, url);
drafts (
id uuid pk, brief_id uuid fk, version int, body_markdown text,
body_html text, word_count int, reading_grade numeric,
author_id uuid, methodology_block text,
seo jsonb, -- title_tag, meta_description, slug, h1, excerpt, image_alts
jsonld jsonb, -- array of schema.org payloads
internal_links jsonb,
publish_blocked boolean default true,
status text default 'in_progress'
)
claim_validations (
id uuid pk, draft_id uuid fk, claim_text text,
class text check (class in
('opinion','observation','common_knowledge','factual','statistical','regulated')),
supporting_source_ids uuid[], confidence numeric,
status text check (status in ('pass','warn','block'))
)
quality_scores (
id uuid pk, draft_id uuid fk, dimension_scores jsonb,
total numeric, decision text, scored_at timestamptz
)
publish_queue (
id uuid pk, draft_id uuid fk unique, scheduled_at timestamptz,
wp_post_id bigint null, permalink text null, state text
)
performance_metrics (
id uuid pk, article_id uuid fk, date date,
gsc_clicks int, gsc_impressions int, gsc_ctr numeric, gsc_position numeric,
ga4_sessions int, ga4_engaged_sessions int, ga4_avg_engagement_sec numeric,
ai_citations jsonb -- {chatgpt: n, perplexity: n, google_aio: n}
)
UNIQUE (article_id, date);
embeddings (
id uuid pk, owner_table text, owner_id uuid,
embedding vector(1536)
)
INDEX USING ivfflat (embedding vector_cosine_ops);
-- User roles per security guidance
app_role enum ('admin','editor','reviewer','viewer');
user_roles (id uuid pk, user_id uuid fk auth.users, role app_role,
unique(user_id, role));Publish-blocking constraint
drafts.publish_blocked defaults to true. The fact-check agent is the only writer permitted to flip it to false (enforced by an RLS policy keyed to a service role). The publish queue's check function rejects any draft with publish_blocked = true.§ 04
Orchestration layer
Recommended primary: Temporal or Inngest over n8n / Make.com for the production pipeline. Reason: durable workflows, native retries, versioning, and idempotency keys are first-class — critical when a single article traverses 9+ stateful steps. n8n / Make remain excellent for the periphery (social repurposing, Slack alerts, Sheets exports). Keep the user's preferred tools as a documented fallback.
Queue topology
q.discover— daily cron → M1 minerq.brief— opportunity_score > threshold → M2q.research— fan-out per required_claimq.write→q.factcheck→q.authority→q.seo→q.geo→q.scoreq.publish— gated onpublish_blocked = falseANDscore ≥ 90OR human approvalq.refresh— driven by performance signals
Idempotency & retries
- Every job carries a deterministic key:
{stage}:{draft_id}:{version}. - Writer/agent calls store the prompt + model + temperature hash in
agent_runs; identical hash returns cached result within 24h. - Retries: 3 attempts with jitter (1s, 8s, 60s); on permanent failure → dead-letter queue + Slack alert + dashboard surface.
- Each external API call (OpenAI, Perplexity, WP REST) wrapped in a circuit breaker (50% error rate over 1 min trips for 5 min).
§ 05
Multi-agent design
Agents are not autonomous loops; they are typed function calls against the Lovable AI Gateway with rigid input/output JSON schemas (tool calling). The orchestration layer — not the model — decides the next step. This eliminates the unbounded token consumption and reasoning drift typical of agent frameworks.
Roles
| Agent | Default model | Hand-off contract |
|---|---|---|
| Research | Perplexity Sonar + gemini-3-flash-preview | Returns source_documents[] linked to claim IDs. |
| Writer | gpt-5 or gemini-2.5-pro | Returns {sections[], inline_citations[]}; every citation must be a known source_id. |
| Fact-check | gemini-2.5-pro | Returns claim_validations[]; deterministic verifier double-checks numbers. |
| Authority injection | gemini-3-flash-preview | Returns {author_block, methodology_block, references[]}. |
| SEO packaging | gemini-3-flash-preview | Returns {seo, jsonld, internal_links} validated by deterministic linter. |
| QA scoring | gpt-5-mini | Returns dimension scores + decision. |
Prompts as contracts
Each agent has a versioned prompt file plus a Zod/JSON-schema for its output, enforced via tool-calling. Example for the writer:
tools: [{
type: "function",
function: {
name: "submit_section",
parameters: {
type: "object", required: ["heading","markdown","citations"],
properties: {
heading: { type: "string" },
markdown: { type: "string", maxLength: 8000 },
citations: {
type: "array",
items: { type: "object", required: ["anchor","source_id"],
properties: {
anchor: { type: "string" },
source_id: { type: "string", format: "uuid" }
}}
}
}
}
}
}],
tool_choice: { type: "function", function: { name: "submit_section" } }Shared memory
Agents do not pass freeform context. Memory is the database. Each agent receives a query handle (brief_id / draft_id) and reads only the rows it needs. This makes runs reproducible and debuggable.
§ 06
Factual validation pipeline
Classification rules
- Opinion — first-person stance, hedged language → no source required.
- Observation — descriptive, non-numeric, non-controversial → no source required.
- Common knowledge — verifiable in any general encyclopedia → no source required, but flagged for review on first occurrence per topic.
- Factual — specific non-numeric claim → ≥1 secondary source.
- Statistical — any number, percentage, rank, year → ≥2 independent sources, numeric agreement within tolerance, deterministic regex check.
- Regulated (YMYL) — health, legal, financial, safety → ≥2 primary sources from a domain allowlist (e.g.
nih.gov,cdc.gov,sec.gov,who.int, peer-reviewed journals).
Anti-hallucination guarantees
- The writer agent cannot emit a citation that isn't already in
source_documentsfor that brief — schema rejects unknown source_ids. - The fact-checker re-fetches each source URL and confirms the snippet still appears (catches hallucinated URLs and drift).
- For statistics, the verifier extracts the number from the cited snippet and compares it to the number in the draft. Mismatch →
block. - Expert quotes require a verifiable URL of the original utterance (interview, paper, press release). No fabricated experts.
- Database constraint: a draft cannot enter
publish_queuewhile anyclaim_validations.status = 'block'exists for it.
This aligns with Google's guidance that scaled content is acceptable only when it is original, accurate, and people-first; mass-produced unverified content falls under scaled content abuse.
§ 07
SEO + AI extraction packaging
Generation rules (deterministic where possible)
| Field | Rule |
|---|---|
| title_tag | ≤60 chars, primary keyword in first 50 chars, brand suffix optional. Truncated deterministically if model overruns. |
| meta_description | ≤155 chars, includes primary keyword + value-prop verb, no clickbait. Note: Google may rewrite descriptions; this is acceptable. |
| slug | kebab-case, ≤60 chars, stop-words removed, ASCII only. |
| h1 | Distinct from title_tag where useful; one H1 per page (enforced by linter). |
| excerpt | ≤160 chars; doubles as og:description when not overridden. |
| image_alts | Descriptive, no keyword stuffing; required for every non-decorative image. |
| internal_links | 3–8 contextual links to existing articles in the same cluster; anchor text varied (no exact-match repetition). |
| canonical | Self-referential by default; cross-canonical only on intentional duplicate variants. |
| author block | Real author with bio, photo, credentials, social links — supports E-E-A-T. |
JSON-LD schema selection
- Article on every post (with
author,datePublished,dateModified,publisher). - BreadcrumbList on every post.
- FAQPage when the article contains a FAQ block of distinct Q→A pairs that are visible on the page. Note: as of August 2023 Google restricts FAQ rich results to authoritative government and health sites; structured data remains valuable for AI extraction even when rich results are not shown (source).
- QAPage for single-question pages.
- Organization on the homepage / about page only (publisher reference inside Article handles the rest).
- HowTo only where genuinely procedural; same eligibility caveat as FAQ.
Meta keywords tag — explicitly excluded
<meta name="keywords"> tag. Google has stated publicly that it does not use the meta keywords tag for ranking (official post), and including it leaks the keyword strategy to competitors with zero ranking benefit.§ 08
AI visibility / GEO layer
Google AI Overviews, ChatGPT search, Perplexity, and Bing Copilot extract short, attributable spans of text. The GEO layer guarantees every article exposes those spans in a stable, predictable place. Note: exact inclusion factors for AI Overviews are not publicly documented and evolve frequently — the rules below are the empirically-supported best practices, not a guarantee of citation.
Required blocks (linter-enforced)
- Answer-first paragraph — 40–60 words immediately after H1, directly answering the primary query.
- Key takeaways — 3–5 bullets, each ≤20 words, fact-dense.
- Concise definition block — for any defined entity, provide a one-sentence dictionary-style definition.
- FAQ block — 4–8 Q&A pairs phrased exactly as users ask, mirrored in
FAQPageJSON-LD. - Bottom-line block — at end of article, restates the answer with the strongest supporting fact.
Entity consistency rules
- Entity names use a canonical spelling registered in an internal entity table; the writer agent receives the canonical form.
- Author, publisher, organization names match across JSON-LD, on-page byline, and sameAs links to Wikipedia / Wikidata / LinkedIn.
sameAslinks are populated for the Organization and Person schema where verifiable URLs exist.
§ 09
Quality scoring engine
| Dimension | Weight | How measured |
|---|---|---|
| Factuality | 20 | % of factual/statistical/regulated claims with status='pass'. |
| E-E-A-T signals | 12 | Author bio + credentials + methodology + citation density. |
| Originality | 12 | 1 − max similarity (internal pgvector + Originality.ai). |
| Depth | 10 | Coverage of brief.required_entities & required_claims. |
| Intent match | 10 | Rubric scoring vs SERP intent of primary keyword. |
| GEO extraction readiness | 10 | Linter pass on all 5 required blocks. |
| Schema validity | 8 | schema.org validator + Google rich-results test (where applicable). |
| Internal linking | 6 | 3–8 contextual links, varied anchors, all 200 OK. |
| Readability | 6 | Flesch-Kincaid grade vs target (default grade 8). |
| Brand voice | 6 | Embedding-similarity to brand-voice corpus > threshold. |
Total = sum (max 100). Routing: <80 → revise loop (max 3); 80–89 → human review queue; ≥90 → publish-ready.
Learning loop: performance_metrics joined to quality_scores monthly; weights re-fit via linear regression against composite outcome (clicks × engaged-session-rate × AI-citation count). Weight changes require human approval.
§ 10
WordPress integration
REST endpoints
POST /wp-json/wp/v2/media— upload featured + inline images (Cloudinary-hosted source, downloaded server-side then re-uploaded to host on WP for SEO ownership).POST /wp-json/wp/v2/posts— create post withstatus: 'draft'.POST /wp-json/wp/v2/categories,/tags— upsert taxonomy.
Field mapping
{
title: draft.seo.h1,
content: draft.body_html, // includes injected JSON-LD <script type="application/ld+json">
excerpt: draft.seo.excerpt,
slug: draft.seo.slug,
status: "draft",
author: wp_author_id,
featured_media: wp_media_id,
meta: {
// Yoast
_yoast_wpseo_title: draft.seo.title_tag,
_yoast_wpseo_metadesc: draft.seo.meta_description,
_yoast_wpseo_canonical: draft.seo.canonical,
// RankMath equivalents (set both — only one will be active)
rank_math_title: draft.seo.title_tag,
rank_math_description: draft.seo.meta_description,
rank_math_canonical_url: draft.seo.canonical
}
}One-click approval UX
Dashboard shows a side-by-side: rendered preview + diff vs last version + claim-validation summary. Single button posts {status:'publish'} to WP and emits an event into the indexing queue.
§ 11
Indexing & performance loop
- Sitemap regenerated on publish; submitted via Search Console API.
- IndexNow ping to Bing/Yandex on publish + on substantive update.
- Google Indexing API only for eligible types (JobPosting, BroadcastEvent). Otherwise rely on sitemap + crawl.
- GA4 + GSC ingested daily into
performance_metrics. - AI citation tracker: a worker runs the article's primary query against ChatGPT (web), Perplexity, and (where accessible) Google AI Overviews via headless browser; parses cited URLs; increments counters. Caveat: this is a best-effort signal — AI surfaces are non-deterministic and detection methodology must be re-validated quarterly.
- Winner refresh: articles with rising impressions but flat/falling CTR → meta + intro rewrite. Articles with rising AI citations → expand cluster.
- Loser handling: <28-day data is held; after 90 days with bottom-quartile performance → rewrite or noindex (decision routed to reviewer).
§ 12
Dashboard + control panel
Screens
- Pipeline — kanban: Discovered → Briefed → Drafting → Fact-check → Scoring → Review → Published. Each card shows score, blockers, ETA.
- Topic Bank — sortable table of
topic_opportunitieswith manual promote/demote. - Draft Queue — review UI with side-by-side preview, claim-validation drawer, one-click approve.
- Performance — per-article: GSC clicks/impressions, GA4 engagement, AI-citation counts; cluster rollups.
- Controls — global throttles: max articles/day, niche on/off, agent model overrides, tone slider (informative ↔ persuasive), authority intensity (light ↔ heavy citation), emotional intensity (neutral ↔ strong stance).
- Audit log — every agent run, prompt hash, model, cost, decision.
§ 13
Tech stack specification
| Layer | Recommended | Rationale / fallback |
|---|---|---|
| Frontend dashboard | Next.js 15 (App Router) or TanStack Start | SSR for auth-gated review UI. TanStack Start is the Lovable default and works well here. |
| Backend / agents | Python (FastAPI) for agent workers; Node.js for WP REST + dashboard API | Python ecosystem (instructor, pydantic, pgvector clients) is stronger for typed LLM I/O. Node is fine as fallback. |
| Orchestration | Temporal or Inngest | Durable workflows. n8n / Make.com retained for peripheral automations. |
| LLM access | Lovable AI Gateway (Gemini + GPT-5 family) | Single key, no direct provider integration; default google/gemini-3-flash-preview, escalate to gpt-5 / gemini-2.5-pro for writing & fact-check. |
| Grounded search | Perplexity Sonar API | Citations included; falls back to Google Programmable Search. |
| Database | Supabase Postgres + pgvector | RLS, auth, storage, edge functions in one. User roles enforced via has_role() security definer per Lovable guidance. |
| CMS | WordPress REST | As specified. |
| Media | Cloudinary | Transformations + AVIF/WebP delivery; copy to WP for canonical hosting. |
| Analytics | GA4 + Search Console APIs | Daily ingest into performance_metrics. |
| Plagiarism | Originality.ai (paid) + pgvector internal | Internal-first, external on shortlist. |
| Observability | Sentry + OpenTelemetry → Grafana | Per-agent traces; cost dashboards. |
§ 14
Compliance + guardrails
- People-first content: every brief must articulate a target persona and a unique angle. Self-assessment per Google's helpful-content guidance is run as a rubric inside the QA scoring agent.
- Scaled content abuse: every article carries verified authorship, original research or original synthesis, and passes the factuality gate. Pure aggregation/summarization without added value is rejected at brief stage.
- Mobile-first indexing: WP theme audited for mobile parity; no content hidden from mobile.
- Plagiarism + duplicate-topic detection: internal pgvector cosine + Originality.ai; threshold 0.85 internal, 15% external match.
- Brand-voice enforcement: voice corpus embedded; QA dimension scores semantic similarity vs corpus.
- Disclosure: AI-assisted content is allowed by Google when it meets E-E-A-T and helpful-content criteria; we additionally surface human reviewer name on every published post.
§ 15
Phased build roadmap
Phase 1 — MVP (weeks 0–8)
- Single niche, single tenant.
- Modules M1 (lite), M2, M3, M4, M5, M7, M9, M11, M12.
- No social repurposing, no AI citation tracking, no multi-agent escalation (single writer model).
- Success: 20 publish-ready articles/week, ≥80 mean QA score, <10 min mean human review per article, zero blocked-claim escapes to publish.
Phase 2 — Authority scale (weeks 8–20)
- Add M6 authority injection, M8 GEO layer, M10 plagiarism, M13 + M14 learning loop.
- Competitor gap analyzer, social repurposer, local SEO expansion, AI citation tracker.
- Multi-tenant niches; per-niche tone/authority controls.
- Success: 60–100 articles/week, ≥85 mean QA, <5 min mean review, measurable cluster topical authority growth (impressions and average position trending up across the cluster, not single posts), AI-citation count rising month-over-month.
Phase 3 — Self-tuning (weeks 20+)
- Weight re-fitting from performance_metrics; automated cluster expansion; experimentation framework (A/B titles, intros, schema).
§ 16
Output KPIs
| KPI | Target | Mechanism |
|---|---|---|
| High-quality articles / week | 20 (P1) → 100 (P2) | Throughput governed by orchestration concurrency + agent cost budget. |
| Mean human review time / article | <5 min | Side-by-side review UI + claim-validation drawer; only ≥90-score drafts in queue. |
| Blocked-claim escape rate | 0 | DB-level publish-block constraint + reverifier on publish. |
| Topical authority growth | + cluster impressions, − avg position monthly | GSC ingest + cluster rollups in dashboard. |
| AI visibility | Citation count up MoM in ChatGPT + Perplexity + AIO (where measurable) | AI citation tracker; quarterly methodology revalidation. |
| Cost / publish-ready article | Tracked, decreasing trend | Cost dashboard from agent_runs. |
Closing note for the engineering team