Pipeline Position
Step 4 of 4 — measurement + flywheel.
- Input: Build Output (JSON) from morphiq-build + MORPHIQ-TRACKER.md (persistent state).
- Output: Delta Report (JSON) → loops back to morphiq-rank.
- Owns: MORPHIQ-TRACKER.md — generates on first run, updates every run.
- Owns:
morphiq-track/state directory — JSON state layer for prompts, results, citations. - Drives: 3 ongoing workflows (Content Optimization, Content Creation, Query Fanout Expansion).
- Data contract: See
PIPELINE.md§4 for the Delta Report, §5 for MORPHIQ-TRACKER.md, §6 for the JSON State Layer.
Purpose
Morphiq Track is the measurement and flywheel skill. It queries AI providers to measure brand visibility, computes GEO scores and Share of Voice, tracks deltas over time, and drives three ongoing workflows that feed back into the pipeline.
Workflow
Step 0: Initialize or Load State
Check if morphiq-track/manifest.json exists in the project root.
- Missing (first run): Proceed to Step 1. The state directory will be created.
- Present (subsequent run): Load
morphiq-track/prompts.jsondirectly — this contains the full prompt set with config, metadata, and tracking state. Skip to Step 2. Ifrecommendations.cooldown_dayshas elapsed sincerecommendations.last_generated, generate 20 new recommendations viacreate-prompts.py --state-dir morphiq-track/ --refresh. - Migration (tracker exists but no state dir): Parse MORPHIQ-TRACKER.md §8 to bootstrap
prompts.json, parse §7 to bootstrapcitations.json. Seereferences/state-layer.mdMigration section.
For state layer specification, read references/state-layer.md.
Step 1: Generate Prompts
First run only. Generate 50 prompts across 5 GEO categories:
| Category | Share | Brand Name? |
|---|---|---|
| Organic | 45% | No |
| Competitor | 11% | Mixed |
| How-to | 14% | No |
| Brand-Specific | 13% | Yes |
| FAQ | 17% | No |
Apply quality rules per category. Add temporal markers to 70%+ prompts. Include entities in comparison/technical prompts.
Run scripts/create-prompts.py --state-dir morphiq-track/ --brand {brand} --category {category} --competitors {competitors}. This writes morphiq-track/prompts.json and initializes morphiq-track/manifest.json.
For taxonomy, fanout profiles, and generation rules, read references/prompt-taxonomy.md.
Step 2: Query AI Providers
Distribute prompts evenly across 4 providers. Execute using scripts/run-queries.py --state-dir morphiq-track/ --mode execute. This reads prompts from morphiq-track/prompts.json, writes versioned results to morphiq-track/results/track-{date}.json, and updates morphiq-track/manifest.json.
| Provider | Model | Concurrency |
|---|---|---|
| OpenAI | gpt-4o | Full |
| Perplexity | sonar-pro | 2 concurrent |
| Anthropic | claude-sonnet-4-5-20250514 → claude-sonnet-4-20250514 | Serialized |
| Gemini | gemini-2.5-flash | 3 concurrent |
Mandatory requirements for every query:
- Full response text. Store the complete response — never truncate. morphiq-build's content creation workflow requires the full text for analysis.
- Sub-query extraction. For each provider that exposes tool calls, extract the search queries the model issued. These feed Workflow C (Query Fanout Expansion) and invisible SoV.
- Citation deduplication. After collecting citations per response, strip UTM/tracking params from URLs and deduplicate. Track
citation_weight(number of times each URL was cited). - Retry on transient failure. Retry once with 2-second delay before marking as error. This handles rate limits.
Provider-specific requirements:
- OpenAI: Iterate
response.outputfor items withtype == "web_search_call"— extract thequeryfield intosub_queries[]. This reveals GPT'ssite:operator searches and two-phase research pattern. - Perplexity: Citations are a Perplexity-specific field. Check
response.citations, thenresponse.model_extra["citations"], thenresponse.__dict__["citations"], thenresponse.choices[0].message.model_extra["citations"]. The OpenAI-compatible client puts unknown API fields inmodel_extra. - Anthropic: Tool config must be
{"type": "web_search_20250305", "name": "web_search", "max_uses": 5}. Try modelclaude-sonnet-4-5-20250514first, fall back toclaude-sonnet-4-20250514. Response content blocks includetext(final answer),web_search_tool_result(search results with URLs), andserver_tool_use(the search call). Extract text only fromtextblocks; extract citations from bothtextblock inline citations andweb_search_tool_resultblock content. - Gemini: Grounding metadata returns
vertexaisearch.cloud.google.comredirect URLs. Follow the redirect to get the real URL. If redirect fails, use thegrounding_chunk.web.titleas fallback domain:{url: proxy_url, title: title, resolved_domain: title}.
For full provider config and response pipeline, read references/provider-strategies.md. For selection rules and distribution, read references/query-targets.md.
Step 3: Analyze Responses
5-step pipeline: extract raw response/citations/sub-queries → structured analysis (using the agent's reasoning capabilities) → brand mention validation (exact → TLD → LLM judge) → competitor filtering → entity normalization.
Input requirements for analysis: Each response must include the full response text, deduplicated citations with citation_weight, and extracted sub-queries. The analysis uses the config block from the prompts file for brand, domain, and competitors — never hardcoded values.
Step 4: Compute GEO Score
GEO = mean(provider_scores)
Weighted GEO = (Organic × 0.45) + (Competitor × 0.22) + (How-to × 0.22) + (Brand × 0.11)Thresholds: ≥60 Excellent, ≥40 Good, ≥20 Fair, ≥10 Poor, <10 Very Poor.
For GEO methodology, read references/query-targets.md.
Step 5: Compute Share of Voice
Three SoV tiers:
| Metric | What It Measures |
|---|---|
| Mention SoV | Brand name in final responses |
| Fanout-Weighted SoV | Weighted by prompt type fan-out depth |
| Influence SoV | Brand presence in sub-queries (invisible influence) |
Track Conversion Gap = Influence SoV − Citation SoV.
For SoV methodology, read references/share-of-voice.md.
Step 6: Compute Deltas
Compare against previous snapshot using scripts/diff-results.py --state-dir morphiq-track/. The script reads manifest.json to auto-resolve the current (runs[0]) and previous (runs[1]) results paths, and reads morphiq-track/citations.json for previous citation state. Flag changes >5 points. Generate flagged actions for regressions, losses, displacement, and conversion gaps.
For delta methodology, read references/delta-scoring.md.
Step 7: Update State Layer and MORPHIQ-TRACKER.md
State layer updates (JSON — source of truth for track-owned data):
- Rebuild
morphiq-track/citations.jsonfrom current results + previous citation state (gained/lost/stable) - Update
morphiq-track/prompts.jsontracking fields (mentioned, cited, best_provider, runs_tracked, last_run) - Update
morphiq-track/manifest.jsonupdated_at
Tracker updates (markdown — user-facing dashboard): Project state layer data into MORPHIQ-TRACKER.md sections 5-9 and 14 (SoV, SoV Trend, Citations, Prompts, Competitors, Run History). Update remaining sections (1-4, 10-13) per tracker-spec.md rules.
For tracker specification, read references/tracker-spec.md. For state layer specification, read references/state-layer.md.
Step 8: Produce Delta Report
Assemble JSON (PIPELINE.md §4): SoV metrics, citations, per-provider data, competitors, flagged actions, content queue. Loops back to morphiq-rank.
Three Ongoing Workflows
Workflow A: Content Optimization
- Identify pages with declining SoV or lost citations
- Feed to morphiq-build (existing content path)
- Re-track to measure impact
Workflow B: Content Creation
- Collect prompts where brand is absent
- Identify competitor citation sources
- Generate content briefs for missing coverage
- Feed to morphiq-build (new content path)
Workflow C: Query Fanout Expansion
- Run
scripts/analyze-fanout.py --state-dir morphiq-track/with optional--scan-reportfor page inventory and simulated queries - Script extracts sub-queries from latest track results, merges with scan simulated queries (fills Perplexity/Gemini gap)
- Compares against site page inventory to identify unanswered sub-queries
- Extracts competitor citation sources for each unanswered sub-query
- Generates content briefs prioritized by citation weight (
site:2x, citation-producing 1.5x, silent 0.5x) - Output feeds Delta Report
content_creation_queuevia--fanoutflag on generate-report.py - Update MORPHIQ-TRACKER.md §12 (Query Fanout Coverage) and §13 (Content Creation Queue) with new entries
Reference Files
| File | Purpose |
|---|---|
references/prompt-taxonomy.md | Prompt types, GEO categories, fanout depth, generation rules |
references/share-of-voice.md | SoV formulas, mention types, invisible SoV, competitive tracking |
references/provider-strategies.md | Provider config, models, response analysis pipeline |
references/query-targets.md | Provider selection, distribution, citation categories, GEO score |
references/delta-scoring.md | Delta calculation, significance thresholds, flagged actions |
references/tracker-spec.md | Full MORPHIQ-TRACKER.md specification (14 sections) |
references/state-layer.md | JSON state layer: directory structure, file schemas, read/write rules, sync rules |