Back
Reference · Full walkthroughs

The full walkthroughs

The complete step-by-step reference for every workflow - what each one actually runs, in order, including the tools it calls, the decisions at each fork, and the traps it avoids. Tap any skill to open it.

Not prompts. A system.

These aren't prompts that produce a nicer answer. Each is a step in a pipeline with explicit evidence gates, fixed sequencing, handoffs between skills, failure handling, and QA. Outputs become inputs - the keyword map becomes the source of truth that metadata, H-tags, on-page SEO, and the content calendar all read from. I don't use AI to outsource SEO judgment; I use it to make my SEO judgment repeatable - and to make SEO more rigorous, not more speculative. Everything below is the system; the individual skills are the proof it's real.

Measure Diagnose Decide Execute Verify

The rules the system refuses to break

  1. Never invent the number. If the source doesn't have it, the system writes "no data" - never a fabricated estimate or a silent zero.
  2. Never diagnose before proving the symptom. A traffic decline isn't automatically an SEO problem; diagnosis is gated behind measurement validation - comparison windows, tracking, config, and data quality get cleared first.
  3. Never confuse a business rival with a ranking competitor. It pulls the actual SERP competitors for a query, not whoever the client happens to name.
  4. Never optimize a page without knowing what it should own. On-page work stops when there's no keyword map, because every element would target an unverified query.
  5. Never bury the recommendation inside the analysis. Every map ships both the analytical source of truth and a simple execution sheet - because a correct-but-unusable workbook fails at handoff.

The system, drawn

The whole library mapped to the five stages of the loop. Every skill is a step in this pipeline - click any one to jump to its full walkthrough.

01MeasureEstablish the ground truth.
02DiagnoseFigure out what's wrong, and why.
03DecideTurn findings into targets and a plan.
04ExecuteDo the work, in the right order.
05VerifyProve what shipped, and whether it worked.
+Support & assetsAssembly, delivery, and asset ops.

Five that show how I think

root-cause-analysis

Don't ask AI why traffic dropped. Make it prove the drop is real, then trace it to an actionable root.

ranking-analysis

Decompose why one result outranks another across eight factors - not generic "improve your content" advice.

keyword-map

Turn search demand into an architecture for the site - the source of truth every on-page skill reads from.

technical-seo-audit

Turn a crawl into evidenced, prioritized problems with an SEO consequence - not 900 crawler warnings.

ai-visibility-audit

Extend SEO beyond blue links into whether brands appear - and get cited - in AI answers.

01

Audits & Diagnostics

15 skills
auditWhole-site or single-page audit, scoped from the URL itself.

Phase 0 - scope and resolve.

First it decides whether this is a whole-site audit or a single-page audit, and it decides that from the URL itself. A root domain means the holistic site pass. A deep URL - a specific community, floor plan, or blog post - means a focused page audit. It states which one it's doing so you're not surprised later.

Then it matches the domain to a client in the portfolio. If the URL doesn't clearly map to a known account, it asks you once using tappable options rather than guessing, because everything downstream keys off that answer: which Supermetrics account, which ClickUp space, which prior docs to look for.

Phase 1 - assemble the context pack.

This is the part people skip and the skill explicitly forbids skipping. It gathers context before forming a single finding, and it sequences heavy pulls one at a time so a bad pull is easy to spot. If a source isn't connected or comes back empty, it says so plainly and keeps going rather than inventing a number. Five things go into the pack:

Performance. GA4 for sessions, key events, and top landing pages. GSC for clicks, impressions, CTR, average position, top queries and pages, filtered to web search only. GBP for community and local pages: calls, direction requests, profile views. Every total gets pulled unsegmented. The skill names the two errors that most often poison a builder audit: summing a breakdown to get a total, and forgetting the web-only filter on GSC.

The site itself. It fetches the URL. Builder sites are JS-heavy, so a plain text fetch often returns thin or actively misleading content - hidden blocks that look live, prices and years injected by JavaScript, CTAs that only exist in the DOM. So it works from what the page actually renders. Crawl signals come from a Screaming Frog or Sitebulb export if you have one, otherwise from a live Semrush or DataForSEO site audit.

Keyword and competitive. Ranking distribution, striking-distance queries, share versus competitors, SERP features present, backlink profile. Used to size the opportunity, not to pad the finding count.

Prior work. It checks ClickUp for open and recently closed tickets so it doesn't recommend work already in flight, and checks Drive, Microsoft 365, and SharePoint for an existing audit, keyword map, content calendar, or quarterly report. Re-flagging something the team already handled is the fastest way to lose trust in the audit.

The KPI reality. It identifies the actual primary conversion for this client and page type, because 9 in 10 builder purchases close offline. That might be a tour scheduled, a click-to-call, a directions click, an interest-list join, or a brochure download. Impact gets judged against that, not raw form fills.

Phase 2 - run the lenses.

Six passes, each producing findings that name their evidence from the context pack:

  1. Technical. Indexation, status codes, JS rendering and crawler accessibility, Core Web Vitals and LCP (heavy heroes and render-blocking JS are the usual culprits), canonicals, sitemaps, schema coverage. These gate everything, so they run first.
  2. On-page and keyword. Titles and metas, heading structure, keyword-to-page mapping and cannibalization. It names the problem and points at the specialist skill rather than writing the fix here.
  3. Content and AEO. Topical coverage gaps against demand, whether pages are formatted to be cited, freshness, and whether pages answer what buyers actually ask: price, location, availability, move-in timing, schools, builder. It ties AEO findings to real prompt or citation signals where available rather than assuming more content helps.
  4. UX and CRO. Conversion paths, friction, CTA hierarchy, mobile, and whether the page captures the not-ready buyer. Deep work routes to page-cro; only the highest-leverage gaps surface here.
  5. Local and GBP. For community and location pages: profile completeness and activity, NAP consistency, local pack presence, review velocity, and the link between on-site local signals and GBP actions.
  6. Data-driven opportunity detection. Flagged as the highest-yield lens and marked "do this every time." Reading the data for what the page alone won't show: striking-distance queries at position 5–15, strong impressions with weak CTR, high-traffic pages that don't convert, pages declining QoQ, orphan or thin pages with latent demand, and queries the site ranks for with no dedicated page to own them.

Phase 3 - prioritize.

Everything sorts into Quick wins (high impact, low effort, ship first), Bigger bets (high impact, more effort, dev work or new pages), and Strategic (compounding or speculative). Anything failing the "so what" test for the client gets cut.

Output.

A tiered register, not prose. One line of state-of-play at the top, then each opportunity with its lens, evidence, impact, effort, and next step. Two closing sections that matter: "To verify" for findings still pending data or dev feasibility, and "Context gaps" naming any source that wasn't connected, so the reader knows what the audit couldn't see.

baseline-auditThe frozen "before" workbook - one dated Excel snapshot.

Stage 0.

Confirms the client, the primary domain as a full URL including protocol, and every GBP listing in scope. Then it locks three windows and uses them everywhere: the last complete quarter as primary, the same quarter one year prior as comparison, and trailing 12 months for trend context only. It records the pull date, and every tab in the final workbook carries it.

Stage 1 - validate the measurement layer.

This runs before any numbers get pulled, because everything downstream is only as good as the tracking.

For GA4 it checks the property ID, data streams, key event list and definitions, internal traffic filters, referral exclusions, and cross-domain config. It looks specifically for two things: duplicate or double-counted key events (a recurring finding across this portfolio), and form events firing on page load rather than on submit.

For GSC it enumerates every verified property variant (https/http, www/non-www, domain property) and notes which is authoritative, then checks sitemap submission status. For GBP it counts listings, finds duplicates, checks for suspensions and pending appeals, notes access level, and checks whether website links carry UTMs. Then Bing Webmaster, the Semrush project, call tracking, and CRM lead-source mapping.

All of this lands in a Measurement Layer tab listing each check, its state, and whether it compromises the baseline. Anything broken gets flagged as a caveat on the metrics it affects rather than quietly averaged into them.

Stage 2 - organic performance.

GSC via the GW connector for clicks, impressions, average position, and CTR, split brand vs non-brand, broken out by query and by landing page, for both windows. GA4 via GAWA for organic sessions, engaged sessions, key events, and leads (form submissions plus click-to-call) by landing page. GBP via GMB for impressions, actions, the search terms surfacing the profile, review count and rating, and post cadence. Totals get pulled as their own queries so they reconcile against the platform dashboards.

Stage 3 - rankings.

Pulls the target keyword set from keyword-list, or builds one if none exists. Captures position, monthly volume, and difficulty per term via DataForSEO, non-brand first, plus local map-pack presence for priority local terms. It also stands up ongoing tracking through keyword-tracking so the same set reads consistently every period afterward.

Stage 4 - AI visibility.

Routes to ai-visibility-audit but requires a minimum: brand mentions and citations across the tracked LLMs for the target prompt set, AI Overview presence and citation on priority queries, and which domains get cited instead of the client.

Stage 5 - technical.

Routes to technical-seo-audit if a crawl export exists, otherwise notes the gap and schedules the crawl rather than skipping it silently. Captures indexable URL count, status-code distribution, canonical config, redirect chains, orphans, click depth, schema coverage by page type, Core Web Vitals, and the GSC Pages report showing indexed vs not indexed with reasons.

Stage 6 - competitive.

Identifies 3–5 actual SERP competitors for the priority non-brand terms - explicitly not the client's stated business rivals, and noting that these are frequently different and the difference is worth stating out loud. For each: organic visibility, ranked keyword count, referring domains, content footprint. Plus the map-pack incumbents on the priority local terms.

Stage 7.

Page and funnel inventory.

Output.

One dated Excel workbook that becomes the frozen "before" state.

property-forensic-auditDeep single-property diagnosis: is it a brand, SEO, or occupancy problem?

Phase 0.

Before pulling anything, it establishes four things: the client and property name plus its website domain, the GBP location ID in Supermetrics format, the local market with approximate coordinates for the competitive pull, and the 3–6 non-brand head terms the property should win. Those head terms anchor everything in Phase 2. It resolves accounts with accounts_discovery rather than guessing, filtering by name, and passes the returned account string verbatim.

Phase 1 - first-party performance.

Two windows, current quarter and same quarter last year. Every total unsegmented. The skill carries four standing caveats it requires you to repeat in every output:

  • GBP history in this connector begins 2025-01-16. An earlier start date errors, and any window touching early January 2025 is partial.
  • GA4 conversions and key events are not like-for-like YoY because definitions changed. Report organic conversions with a hard caveat, or QoQ only.
  • GBP total views and search views are inflated by Google's 2024 view-count method change. Use Maps views and actions as the reliable signals, and never headline "views up."
  • Supermetrics async sometimes returns "Query stalled, transient." Just resubmit and poll again.

GA4. Filtered to Organic Search, pulling sessions and conversions for each window. GA4 is coarse here because property-level GA4 shares leasing sites across some communities, so it leans on GSC for per-property truth.

GSC. Property totals per window, then query-level data at up to 45 rows for both windows - the core diagnostic. It splits brand from non-brand by hand and compares YoY to classify the decline:

  • Impressions down on brand terms with CTR flat = a brand-demand decline. An awareness or occupancy problem, not SEO.
  • Position up, impressions up, clicks flat = CTR compression or zero-click. Fix metadata and AEO.
  • Position down on specific non-brand terms = genuinely lost rankings. Fix on-page, content, or links.

Then page-level data to find the striking-distance page (high impressions, position ~5–15) and to expose indexed UTM-parameter duplicates.

GBP. Monthly actions broken into phone, driving directions, and website, plus views split into total, Maps, and search. It computes the YoY actions story and the Maps-views trend, then a separate pull for review velocity via the Reviews report type, bucketed by quarter, noting the connector returns a partial recent sample so velocity is directional.

Phase 2 - live competitive and technical.

All DataForSEO.

Live SERP for each head term at depth 20 with an explicit location. Reads whether the property is in the local pack or page-1 organic at all, and who's there instead, distinguishing aggregators from direct competitors. Captures competitor names, ratings, and review counts from the local-pack items, and notes whether an AI Overview is present so impression loss gets attributed correctly (competitive displacement vs AIO absorption).

Ranked keyword distribution filtered to rank 30 or better, ordered by search volume. Parsing gotcha: the tool returns a list whose first element's text is itself a JSON string, so you parse twice before walking to the items array. The classification it's after: is this domain brand-only - ranking 1–3 on its own name and address but weak or absent on non-brand head terms? That's the signature of a property built to win its name rather than its market.

Technical. Lighthouse with JavaScript enabled. A performance score near 100 with low LCP and CLS rules speed out as a cause. A low SEO score (the skill uses 45/100 as the example) points at on-page basics, itemized next.

On-page. on_page_instant_pages with JavaScript enabled, reading the checks and meta: missing H1, missing image alts, low content rate with plain-text word count, irrelevant meta keywords, canonical, resource errors, title and description length. These explain a weak Lighthouse SEO score and cap non-brand ranking.

Local competitive set. A business-listings search across apartment categories within a 3km radius of the coordinates, ordered by review count, limit 25. Builds a ranked table of nearby competitors by rating and review count and places the subject in it. The threshold, stated plainly: a profile in the bottom quartile on reviews or below the pack's rating band (typically 4.6–4.8) cannot enter the 3-pack. Then it confirms the causal chain: rating and review gap → Maps views down → directions and website actions down.

Phase 3.

Root causes ranked by contribution, each tied to evidence, explicitly ruling things out (speed, indexation, rendering) when the data clears them.

Phase 4.

Prioritized plan and a branded Word doc.

technical-seo-auditCrawl in, prioritized dev-ready findings out - deterministic and scripted.

Phase 0.

Scope and resolve the client.

Phase 1 - parse the crawl.

Deterministic and scripted, not eyeballed, so the same export always produces the same findings.

Phase 2 - turn faults into findings.

It walks a checklist of roughly 90 items across five pillars, marking each Pass, Fail, Partial-Investigate, or Not-in-scope with a note:

  1. Crawlability and indexation. robots.txt, XML sitemaps, status codes, canonicals, noindex, crawl waste and faceted URLs, parameter handling.
  2. Architecture and internal linking. URL hierarchy, crawl depth, orphans, followed-link equity flow, breadcrumbs, navigation.
  3. On-page mechanical. Duplicate, missing, and truncated titles and metas; H1 presence and uniqueness; heading order. It detects at scale here and routes the actual writing to metadata and h-tag.
  4. Performance and Core Web Vitals. LCP, INP, CLS, TTFB, page weight against a 2 MB HTML limit, render-blocking resources, image optimization.
  5. Structured data and rendering. Schema coverage and validation by page type, JS rendering and crawler accessibility, semantic HTML, and head integrity.

Cross-cutting checks that always get a line: HTTPS and protocol consistency, security headers, hreflang if multi-region, mobile usability, and a light local pointer. The filter that matters: a finding is a real, evidenced problem with an SEO consequence, not every flag the crawler raised. Each surviving finding gets an ID (F1, F2, …), a priority, the affected URL set, and a plain statement of what it costs the site.

The skill also names five builder-specific patterns it expects to find: blog posts canonicalizing to competing brand or community domains; JS-injected prices, years, and availability that crawlers miss; faceted home-search crawl waste; oversized blog HTML; and head-integrity breaks where a GTM iframe or noscript injected into <head> breaks parsing of the JSON-LD that follows.

Phase 3 - prioritize.

  • P1 critical (red). Blocks indexing or rendering, or corrupts canonical and redirect signals at scale. Canonical pointing to a 404 or a noindex, cross-domain canonicals, sitewide nofollow, JS render failure, head breakage.
  • P2 high (orange). Meaningful drag. Duplicate or missing metadata at scale, redirect volume, crawl waste, missing security headers.
  • P3 moderate (green). Hygiene and long tail. Slow TTFB on a subset, short titles on lower-value pages, semantic HTML.

The dev list gets ordered by impact-to-effort so cheap server or template changes that clear hundreds of URLs at once sit at the top.

Phase 4.

The multi-tab Excel workbook plus the dev handoff.

Separate mode: implementation verification.

You give it prior dev tickets and a fresh crawl, and it cross-references them to confirm what actually shipped.

Work-sequencing framework.

Distinct from report priority. When the question is what order to do the work: first a full-site stress test of the foundations (robots, sitemap, crawlability, indexability); then segment pages into priority and non-priority groups; then per group in order, resolve technical flags, run the technical and on-page checklist, build and implement the internal-linking map, then schema. Steps two and three run in close succession because optimizing on-page without internal linking leaves pages with no equity flow.

technical-seo-checklistSame territory, opposite approach - a fixed 13-section pass, nothing missed by omission.

Same territory as technical-seo-audit, opposite approach. Instead of reacting to what the crawl surfaced, it walks a fixed 13-section list end to end: crawlability, indexability, architecture, status codes and redirects, sitemaps, internal linking, JavaScript SEO, Core Web Vitals, mobile, structured data, hreflang, security, and Search Console.

Every item gets marked Pass, Fail, Partial, or Not-in-scope, and every mark carries evidence. The skill calls this the one rule that keeps the audit trustworthy, because an unsupported "Pass" is an assumption wearing a checkmark.

Then fails and partials get promoted into findings, prioritized P1/P2/P3, and built into the deliverable. Use this when you need confidence nothing was missed by omission rather than a deep dive on what the crawler happened to catch.

organic-performance-auditTotals first, breakdowns second - the order of operations is the whole point.

Before anything.

Resolve the exact account. Which GA4 property, which GSC site.

The order of operations, which is the whole point:

  1. Call field_discovery before data_query. Don't guess field names.
  2. Pull the headline totals unsegmented. GSC clicks and impressions, GA4 organic sessions and users, each as its own query scoped to the one property.
  3. Pull the breakdowns separately, and use them only to explain the why.
  4. Optional ranking layer if Semrush, DataForSEO, or SE Ranking is connected.
  5. Diagnose rather than report.

The rules it enforces while doing this:

Never sum a breakdown to get a total. A query split by page, query, month, or source/medium does not add back to the scorecard number. GSC filters to searchType = web: image, video, news, and Discover rows inflate clicks and impressions and are not what the client checks when they log in - a standing requirement, not a per-audit judgment call.

GA4 organic uses the Organic Search default channel grouping, and then verifies the source and medium rows underneath it. A paid campaign with a mistagged medium leaks into Organic Search and fakes a lift. If organic jumped, confirm it isn't mislabeled paid before reporting it. Anything built by adding rows gets re-pulled unsegmented, and the unsegmented pull wins.

The homebuilder YoY caution.

Before comparing year over year it checks what the community was actually doing in each period, because community lifecycle dominates these numbers: a community in active sales generates far more search interest than the same community at 80% sold, phase launches create step changes, and a sold-out community's traffic decline is a commercial success being reported as an SEO failure.

campaign-diagnosisClassify the problem type first - lost, present-but-clickless, or never ranked.

Stage 1 - identify the problem type.

It pulls dataforseo_labs_google_domain_rank_overview first, getting organic keyword count, estimated traffic, and rank distribution, comparing against historical if available. That orients everything after it. Then it classifies into one of three problems, because each has a different diagnostic path:

TypeSignal
Rankings lostKeywords that used to rank are gone or moved back significantly
Rankings present, clicks missingImpressions and rank intact but CTR or traffic isn't materializing
Never rankedTargeting terms the site has no foothold on

More than one can be active at once.

Stage 2 - localize.

Path A for rankings lost: pull dataforseo_labs_google_ranked_keywords and filter to terms that moved back significantly or dropped out of the top 20. Then dataforseo_labs_google_historical_rank_overview to pin down when the drop started, tying it to an algorithm update, a site change, or a competitor move. Then backlinks_timeseries_summary to check whether referring-domain or backlink count dropped around the same time - a co-occurring link loss and ranking drop points at authority erosion rather than on-page problems. Then backlinks_bulk_spam_score to flag any toxic link spike.

The stated localization goal: narrow the drop to specific pages or keyword clusters, not "the site dropped." A drop concentrated on two or three pages is a fundamentally different problem than a sitewide decline. Paths B and C handle the other two problem types.

Stage 3 & 4.

Name the cause, then build the fix brief. Optional correlation with the traffic layer.

root-cause-analysisFive gated stages - prove the drop is real before hunting a cause.

Five stages, worked in order, each gating the next. The skill is explicit that Stage 0 doesn't get skipped even under time pressure, because naming a cause for a drop that isn't real is the most common way an RCA misleads a client.

Stage 0 - the artifact gate.

Before hunting for any cause, prove the metric moved for a real-world reason rather than because of how it was measured or compared. It runs the checks relevant to the affected metric:

  • Comparison-window error. Unequal day counts, a partial current period, a month with more weekends, a window containing an outlier day. Normalize before concluding anything.
  • Seasonality. Is this the expected seasonal shape? Check YoY, not just MoM.
  • Tracking break. Did a tag or event stop firing, did a form endpoint or thank-you URL change, did a redeploy drop the GA4 snippet or GTM container, did a consent-mode or cookie-banner change reduce captured events? The worked example: a "leads drop" that's really a broken form-submit event is a dev and tracking root cause, not a demand or SEO problem.
  • Definition or config change. GA4 key-event definition changed, a filter or channel grouping changed, a new property, data retention or thresholding, sampling on large ranges.
  • Data quality. Bot or spam traffic inflating a prior period, self-referrals, internal traffic, a referral-exclusion change.
  • GSC-specific. searchType not restricted to web, property mismatch between domain and URL-prefix properties, the standard 2–3 day data lag read as a drop, an anonymized-query shift.
  • GBP-specific. Google's reporting lag and periodic metric-definition changes, or a listing merge, move, or suspension resetting baselines.

The gate produces one of two outcomes: "symptom confirmed real, magnitude X," or "symptom is a measurement artifact, specifically this one." Only a confirmed-real symptom proceeds. If it fails, the artifact is the root cause. Report it and stop.

Stage 1 - localize the layer.

It deliberately doesn't commit to a layer yet. It runs quick cheap reads across the plausible ones to see where the movement actually lives:

LayerFirst read
Rankings / SERPDataForSEO ranked keywords, historical rank overview, live SERP
Site and web devon_page_instant_pages, on_page_lighthouse, GSC coverage, web_fetch
ContentCrawl or web_fetch, GSC page-level
Off-site authorityDataForSEO backlinks timeseries, Semrush backlinks research
Local / GBPSupermetrics GMB, DataForSEO business listings
AnalyticsAlready gated in Stage 0, reconfirm if it resurfaces
Demand / marketDataForSEO or Semrush volume trend, Google Trends

The point is elimination as much as selection. A ranking drop with no correlated traffic drop, or a traffic drop with rankings intact, immediately rules layers in or out. The standard it holds: "the site is down" is not localized, "three community pages lost position on non-brand terms the week of the deploy" is. Once movement is localized to organic search, it calls decline-detail to render the page-by-page and query-by-query breakdown inline, so the localization is shown rather than asserted.

Stage 2 - differential diagnosis.

For the localized layer it lists candidate causes, then for each runs the pull that would falsify it. Three tests every candidate has to survive:

  • Timeline. Does the cause precede the effect, and does its timing align with the anchor date? A cause that started after the drop isn't the cause.
  • Specificity. Does the cause predict the shape of what's observed - which pages, clusters, device, geo? A cause that predicts a sitewide drop cannot explain a drop concentrated on three pages.
  • Confounder control. Could the same statistic support the opposite conclusion? Fixed confounders get separated from addressable drivers: local proximity, entrenched domain authority, portals like Zillow and Realtor, seasonality, an algorithm update. Those get quarantined as constraints, not action items.

Anything failing timeline or specificity gets killed. Survivors continue.

Stage 3 - trace to root.

It doesn't stop at the proximate cause. It runs the why-chain until the next "why" is either a fixed constraint or an actionable origin, with evidence at each link. The worked example:

  • Symptom: organic clicks to the community page fell.
  • Proximate: the page dropped from position 4 to 12 for its non-brand head term.
  • Deeper: the page lost its H1 and internal links in the June template change.
  • Root: the relaunch template shipped without the SEO elements the prior template had, and no post-deploy QA caught it.

Restoring the H1 fixes this instance. The missing post-deploy QA is the root, and it's what actually needs to change. If two chains are equally supported, it presents both rather than forcing a single verdict.

Stage 4 - verdict.

States the most probable root cause with a confidence level and the evidence behind it, separating what the data establishes from what's inferred. It names the alternatives it considered and why it ruled them out, on the reasoning that an RCA showing its rejected hypotheses is more trustworthy than one showing only the winner. If evidence is thin, it drops confidence a level and labels the affected links inference-limited. It closes by naming the one cheapest test that would confirm the verdict - a five-minute check beats a longer report you have to take on faith.

decline-detailThe page- and query-level "where," with hardcoded, battle-tested parameters.

This one has hardcoded parameters it tells you not to rediscover. They were established for The Grove Frisco and are the defaults; you confirm the client and the two date windows, and reuse everything else verbatim.

The fixed parameters:

GSC. Supermetrics ds_id: "GW", and ds_accounts is the site URL with a trailing slash. The page dimension field is page, the full URL. It is explicitly not landingPagePath, which is a GA4-style name and silently errors on GSC rather than failing loudly. The query dimension is query. Metrics are clicks and impressions.

The history floor is 2025-03-01. GSC pulls through this connector error out before that date. Don't request a comparison window starting earlier.

GA4. ds_id: "GAWA", ds_accounts is the GA4 property ID. Fields are landingPagePath (which is the correct name on this side) or sessionDefaultChannelGrouping, plus sessions. The organic filter is sessionDefaultChannelGrouping == "Organic Search".

Brand regex. Defaults to /(grove|newland)/i. You swap the tokens per client, typically the community-name stem plus the developer name. It stays a simple case-insensitive contains test against the query string.

Pulling.

data_query is asynchronous: submit, then poll get_async_query_results until status is completed. If data_query isn't in the loaded tool set, call tool_search("data_query") first. Map columns by requested_field_ids, never by the row-0 display labels. Six queries total, or four if you only want one comparison window:

  1. GSC by page, current period
  2. GSC by page, comparison period
  3. GSC by query, current period
  4. GSC by query, comparison period
  5. GA4 organic sessions by landing path, current period
  6. GA4 organic sessions by landing path, comparison period

Merging.

Join on the key, which is the page URL or query text. Compute loss = prev_clicks - cur_clicks. Join GA4 sessions onto the page rows by normalized path - stripping the domain off the GSC full URL so it matches the GA4 landingPagePath.

The read it's built to enable.

All three metrics sit side by side so you can separate three problems that look identical in a clicks number:

  • Impressions down and clicks down proportionally = demand or visibility loss.
  • Impressions flat and clicks down = CTR compression, so something changed on the SERP.
  • Clicks flat and sessions down = something broke between the SERP and analytics.

Output.

An inline HTML artifact in the chat, ranked by biggest click loss, split brand vs non-brand, with a toggle between YoY and QoQ. It computes both windows when the data supports it even if you named one. It shows the where, not the why. The why goes back to root-cause-analysis.

ranking-analysisWhy the winners win - like-for-like factor gapping, organic and local.

Step 0 - lock the surface.

Before any comparison happens:

  1. Pull the live SERP for the exact keyword at the correct location and language via DataForSEO:serp_organic_live_advanced.
  2. Record whether a local pack renders, whether there's an AI Overview, featured snippet, or PAA, and what page type dominates the organic top 10: community, floor plan, blog/listicle, builder aggregate, or third-party portal.
  3. Classify intent as informational, commercial, transactional, or local.
  4. Decide which factor model applies: ORGANIC, LOCAL, or BOTH. Run each that applies.
  5. Confirm the client's current position (or absence) in each surface, and identify the exact client URL or listing being compared.

The hard rule at this step: only compare like page types. A client community page against a competitor listicle is not a valid comparison. And if that mismatch is what's happening, that's a finding in itself and often the leading driver, because it means the query intent is informational and the client has the wrong page type in the race.

Step 1 - identify the real competitors.

The set is the top 3–5 URLs organically, and the top 3 listings locally, that are actually ranking for this query. Business rivals who don't appear get discarded. Three to five rather than one, because they're the controls and using several guards against a single outlier driving the read.

Step 2 - the organic factor model.

Eight factors measured for the client page and each competitor page, then gapped:

#FactorHow it's measured
1Intent & page-type matchDoes the ranking page type match the dominant intent; is the client page even the right type
2On-page targetingExact and variant keyword in title, H1, meta, headings, body, URL, alt, via on_page_instant_pages + web_fetch
3Content depth & entity coverageSubtopics, entities, questions answered, media, freshness. Flag real coverage gaps, not mere length
4Page-level authorityBacklinks to the exact URL, referring domains, anchor relevance via backlinks_backlinks and backlinks_anchors, cross-checked against Semrush. Often the strong differentiator on competitive terms
5Domain authority & topical relevanceDomain rank and referring domains, plus whether the domain is topically known, via domain_rank_overview and Semrush
6Internal link supportInlinks to the ranking page, anchor text, click depth, from a crawl if on file, otherwise noted inference-limited
7Technical & page experienceCore Web Vitals via on_page_lighthouse, indexability, mobile, HTTPS, canonical correctness, freshness
8SERP feature captureWho owns the AI Overview citation, the snippet, the PAA answers, and why: schema, answer formatting

Step 3 - the local map-pack model.

Different algorithm, three pillars. Relevance: primary GBP category against competitors' (heavily weighted, and a mismatch is often the leading driver); business name (an exact-match keyword in the name is a known if gameable signal, to be noted rather than endorsed); services, description, attributes, and whether query terms appear anywhere in the profile. Proximity, the dominant confounder: distance of each listing from the search centroid - this gets quarantined; if the winners are simply closer, say so and label the gap proximity-driven and not fully addressable, re-pulling from the client's actual location to separate proximity from prominence where useful. Prominence: review count, velocity, average rating, whether reviews mention the query terms; citation volume and NAP consistency; profile completeness across hours, photos, post cadence, products and services; inbound links and brand signals.

Step 4 - separate signal from confounder.

Every candidate driver runs the three tests: does it plausibly cause the delta or could the same stat support the opposite read; cite the pull and label inferences; would acting on it plausibly move position. Then the unfixable ones get quarantined: locally, proximity and an established review moat built over years; organically, domain age, entrenched authority, and portals a builder site won't out-authority. Stated as fixed constraints, not action items.

Step 5 - rank the drivers.

Each diagnosed driver ranked by gap size × causal plausibility × confidence. Output is a short ranked list of the most probable reasons the winners win - explicitly not an exhaustive dump. Fewer solid drivers beat a long padded list.

serp-analysisThe lightweight one - a structured read of a single SERP.

The lightweight version. You give it one keyword. It pulls the live SERP and returns a structured read of the organic results, which SERP features are present, People Also Ask, the local map pack if one renders, and whether there's an AI Overview. Output defaults to in-chat. It diagnoses the SERP landscape only. The client-specific "why are we losing to these people" question is ranking-analysis.

entity-auditProminence vs conflation - the query-intent test that tells them apart.

Step 1 - establish the symptom precisely.

What exactly is showing for the brand query, and what should be.

Step 2 - the query-intent test.

The core diagnostic. It separates two conditions that look identical on a SERP but need opposite fixes. Claude can't see your localized, personalized SERP, so it writes out the exact query set and you run the searches logged in and report back. It then interprets the pattern. The standard set for an MPC or homebuilder:

QueryWhat it's for
<brand> bareThe failing query itself
<brand> <developer>Does the community resolve when disambiguated by builder
<brand> <city>Does adding the city flip it to the community
<brand> homesA community-intent query
<brand> retirement community (or the client's category)The decisive test
<brand> golf (or the competing sibling's category)Control. The sibling should win this one

Interpretation:

  • Community wins every qualified community-intent query and only loses the bare term: prominence. Google understands both entities fine and is making a ranking judgment. Strengthen the entity; no merges or removals needed for the core issue.
  • The wrong entity (the golf club or amenity) wins a clearly community-intent query, especially the category query: conflation. Google has the association wrong. Hard-separate the entities before anything else, because strengthening a merged record makes it worse.
  • They're not mutually exclusive. Even in a prominence scenario, duplicates and NAP splits found in Step 3 still get cleaned up, because they weaken the community entity.

The control query matters because it validates the test. If the community wins <brand> golf too, the query set isn't discriminating and the read is unreliable.

Steps 3–5.

Build the entity inventory (every entity carrying this name or a near variant: listings, sites, aggregator profiles, duplicates), the action plan, and fill the canonical NAP reference.

Output.

A multi-tab Excel with the inventory, the query-intent test results, the prioritized actions, and the canonical NAP.

content-gap-analysisTwo different gaps, two different competitor sets - never conflated.

The core idea it opens with: there are two different gaps, they answer different questions, and they use different competitor sets. Do not conflate them.

Non-negotiable rules it states up front:

  • Show the full data. Pull every gap term, classify each, and put all rows in a Full Data tab. Curation belongs in the priority view, never by deleting rows the user can't see. If you catch yourself writing "and the rest is noise," stop and show the rest anyway, labeled.
  • Full absolute URLs everywhere, in every cell and every chat table. Never relative paths, never truncated.
  • Never fabricate metrics. If DataForSEO returns no difficulty or volume, write n/a. Flag directional numbers as directional.

Steps.

1. Resolve the client and set up. 2 - find the real competitors: this gets pulled, not guessed.

3 - the content-format gap (benchmark lens). Which informational and answer-style topics does a comparable builder who actually publishes content rank for that the client doesn't? This is where the real opportunity lives: cost-to-build, financing, build-on-your-land explainers, buyer education. The benchmark is a builder of similar size with a real content operation, even in a different metro, because informational topics are geo-agnostic and the client can rebuild the same content framed for their own market. The selection rule: mega-national builders flood the gap with unwinnable terms. Ryan/NVR, K. Hovnanian, Lennar, D.R. Horton, and Pulte get noted in the local scorecard but are never used as the content benchmark.

4 - the local competitor scorecard (market lens). Where do builders in the client's actual footprint outrank the client, and do any publish content the client lacks? Usually local builders compete on their own community, floor plan, and brand names rather than content, so the finding is often "the content lane is uncontested locally" - and that is itself the insight, not a failed analysis. Occasionally one local builder has a real topic hub, and that has to be surfaced in full.

5. Local content gap with full data, classified. 6. Synthesize the priority read. 7. Build the multi-tab workbook.

ai-visibility-auditFive lenses on AI-answer presence - reproducible, honest, cited.

Step 0.

Resolve inputs.

Step 1 - pull the data

on a fixed sequence and a fixed budget, so the pull is reproducible and doesn't sprawl.

Step 2 - reconciliation and honesty rules

applied before any analysis, because this data is noisy and easy to overclaim on.

Step 3 - five lenses,

each banded Strong, Solid, Watch, or Weak with evidence strength noted:

  1. Brand presence. Is the brand mentioned at all in AI answers, and at what volume relative to AI search demand in its market? The common homebuilder failure mode, named explicitly: branded-only presence with zero intent-topic presence. It looks fine on a mention count and represents no discovery value, because someone who already knows your name isn't who you needed AI to reach. Name it when you see it.
  2. Citation footprint. Which client URLs actually get cited, and in what contexts - blog vs money pages - and whether community and floor plan pages are structurally invisible to retrieval because they're thin, JS-rendered, or carry no schema.
  3. Competitive gap. From the top-domains data, who owns the intent topics. Split into three citation classes because each needs a different fix:
    • Direct competitors (other communities or builders). A content and entity gap. Close it with owned content.
    • Aggregators and directories (Zillow, NewHomeSource, 55places, realtor sites). A presence gap. Get listed and optimized there. You won't displace them, but you can control what they say.
    • Editorial and listicles ("best neighborhoods in X" articles, local news). An earned-media gap. A PR target list, not an SEO task.
  4. Topic coverage. Map the 5–8 intent topics against client content. For each: does a page exist that could plausibly be retrieved, is it cited, and who's cited instead. This produces the content gap list.
  5. Retrievability foundations. A quick qualitative check on schema presence across key templates, entity consistency across site/GBP/schema, crawlable text on money pages, and llms.txt if relevant. Diagnosis only; fixes route to schema, metadata, and on-page-seo.

Step 4 - the deliverable.

Executive summary, scorecard, where you stand, who AI trusts in your market and why, the topic gap map, a prioritized action plan, how it'll be measured, and data notes.

on-page-spreadsheetDocuments what's live across eight tabs - evidence, not recommendations.

Step 1.

Fetch the page.

Step 2.

Extract everything into eight tabs:

  1. Metadata. Title, meta description, canonicals, robots.
  2. H-Tags. Full heading hierarchy, H1 through H6.
  3. Internal Links. Anchor text, href, surrounding context.
  4. External Links. Anchor text, href, rel attributes.
  5. Image Alt Tags. Src, alt text, dimensions.
  6. Schema. Type, the JSON-LD content itself, validation notes.
  7. UX & CRO. CTAs, whether a form is present, trust signals, above-fold content.
  8. On-Page Summary. A scorecard across the above.

Steps 3–4.

Build the workbook and deliver. No recommendations anywhere - this documents what's live so you have an evidence artifact and an input for other skills.

02

Keyword Research & Mapping

7 skills
keyword-listBuilds the SEO universe + a buyer-intent AI prompt set, per vertical.

Step 0 - resolve inputs.

It infers as much as it can from prior client work, memory, and the live site, and asks at most one pointed question if genuinely blocked. Five things it needs:

  1. Client, domain, and vertical. The exact target domain written in full including the protocol. And the vertical flavor: MPC, single builder, builder aggregate, age-qualified 55+/active adult, build-on-your-land. The flavor changes the seed set.
  2. Market. Metro, county, and named submarkets or nearby towns. Local geo modifiers drive most non-brand demand in this vertical.
  3. Brand terms. Brand name plus variants, community names, and the parent builder if commonly co-searched. These become the brand set, listed for completeness but de-prioritized.
  4. Competitors, optional. 3–5 named communities or builders, to sanity-check the non-brand universe and seed comparison prompts.
  5. Annotation sources, optional. GSC via Supermetrics or a Semrush organic-positions export, used only to annotate current rank. If neither is available it leaves current rank blank rather than guessing.

It reads a per-vertical seeds reference before building, which holds the seed terms, the buyer-stage model, and the AI prompt templates.

Step 1 - build the SEO keyword universe.

Start from the non-brand seeds for the matching vertical with the client's geo modifiers applied: county, town, school district, metro. Expand with dataforseo_labs_google_keyword_suggestions, which is full-text and stays on topic. Specific warning here: do not use dataforseo_labs_google_keyword_ideas for seeds containing ambiguous words like "land," "lot," or "yard," because its category algorithm returns junk (the examples given are "parking lot" and "land surveyor").

Pull volume with kw_data_google_ads_search_volume, setting location_name to the client's state or metro rather than United States, for local accuracy. Pull difficulty with dataforseo_labs_bulk_keyword_difficulty in one call, up to 1000 keywords, location_name set to United States. If Semrush or GSC is available, annotate current rank from there. Add the brand set last, flagged Brand.

Step 2 - build the AI prompt target set.

Generate 15–30 buyer-intent prompts across the three stages, phrased the way a real buyer types into an LLM (full questions, not keyword fragments). Spread them across Awareness, Consideration, and Decision. Where it adds signal, size the underlying topics with ai_optimization_keyword_data_search_volume to show which prompt themes carry real AI query demand. Where nothing returns, mark "no data," not 0.

Steps 3–4.

Group, assign buyer stage, prioritize; then build the workbook and read out.

keyword-researchExpansion path chosen by seed type - topic, own domain, or competitor.

Step 0.

Resolve inputs.

Step 1 - build the raw universe.

It picks the expansion path based on what kind of seed you gave it:

From a topic or seed keyword. dataforseo_labs_google_keyword_suggestions as the preferred default (full-text, stays on topic), plus dataforseo_labs_google_related_keywords for the "searches related to" set. keyword_ideas only for clean seeds, with the same ambiguous-word warning as above.

From the client domain. dataforseo_labs_google_ranked_keywords for what the domain already ranks for, capturing position so striking distance (positions 4–20) can be flagged. Plus dataforseo_labs_google_keywords_for_site for relevant terms it could target.

From a competitor domain. ranked_keywords on the competitor, plus dataforseo_labs_google_domain_intersection comparing client against competitor to isolate terms the competitor ranks for and the client doesn't. That's the gap set. Then de-duplicate across all calls into one list, keeping position data wherever an endpoint returned it.

Step 2 - enrich.

Volume via kw_data_google_ads_search_volume with location_name set to the client's state or metro, explicitly not United States for geo-modified terms. Difficulty via dataforseo_labs_bulk_keyword_difficulty, one call, up to 1000, United States. Intent via dataforseo_labs_search_intent (informational, navigational, commercial, transactional), supporting stage assignment. SERP features only if you specifically want to know which terms trigger an AI Overview, local pack, or featured snippet - more expensive, so it runs on a short shortlist via the live SERP endpoint. Where a source returns nothing, "no data." Never 0, never fabricated.

Steps 3–5.

Cluster into topical groups by shared head term and intent, flag brand vs non-brand on every row, assign buyer stage to every row (Awareness: relocation, area, schools, "what is"; Consideration: community, builder, floor-plan comparison; Decision: homes for sale, quick move-in, pricing, tour). Then a competitor gap pass if provided, then build the workbook and read out.

keyword-research-deliverableClient-ready two-tab file: keyword research + rolled-up topic clusters.

Steps.

0. Resolve inputs. 1. Assemble and enrich the keyword set. Accepts a raw list or a Semrush/DataForSEO export as the starting point. 2. Cluster into topics, assign audience segment, and band each keyword by current position into Top 3, Page 1, or Striking Distance.

Step 3 - build the file.

Two tabs. The Keyword Research tab carries Keyword, Topic Cluster, Monthly Search Volume, Current Position, Opportunity, Audience Segment, and KD. The Topic Clusters tab is derived from it, rolling up count, total volume, average KD, the Top 3 / Page 1 / Striking Distance counts, and a sample keyword per cluster. 4. Read out.

keyword-mapThe largest skill - two deliverables, and the simple one is not optional.

The largest skill in the library. It produces two deliverables and the second is not optional.

Deliverable 1 - the working map.

A multi-tab workbook: Keyword Map, Target Coverage, Opportunity Map, Excluded, Query Raw, Competitive Raw, Methodology. This is the internal source of truth that metadata, h-tag, on-page-seo, and content-calendar read from.

Deliverable 2 - the simple sheet.

One tab, three columns, nothing else:

ColumnContents
URLEvery indexable URL, plus each recommended new page suffixed [NEW PAGE]
Target KeywordThe one keyword that page should be aimed at
Monthly Search VolumeThe number, or the literal string no data

Sorted by volume descending so actionable rows sit at the top. New-page rows shaded and bolded. Rows with no volume greyed rather than deleted. The reasoning, stated directly: deliverable 1 answers "why," deliverable 2 answers "what do we do," and the second is the version that survives contact with a client meeting, a dev ticket, or a writer's queue. Building only the workbook is called out as a common failure, because a 30-column workbook is correct and unusable and the work stalls at handoff.

Phases A / B / C.

A - the Own lane. What the site already holds, built from the crawl plus Search Console. Empirical: not what someone intended a page to rank for, but what Google has actually decided the page is about, evidenced by the impressions it earns. B - the Target lane. What the site should capture, from competitive data. C - the Opportunity Map. Terms competitors hold that no existing page can plausibly claim. This is where new-page decisions come from.

Primary-query assignment by page type.

Each page owns one lane. The recurring failure it guards against is pages lower in the hierarchy poaching the term a higher page should own - most often the homepage's brand terms.

Page typeOwns
HomepageBrand and brand-plus-city. No other page targets bare brand
Contact / general infoNavigational service queries: [brand] phone number, [brand] contact, [brand] sales office
Community overview, neighborhoods indexNon-branded discovery, not bare brand: [community] neighborhoods, master-planned community [city], new homes [city]
Neighborhood page[neighborhood] [community], [neighborhood] homes [city]
Inventoryhomes for sale in [community], [community] quick move-in homes
Floor plan[plan] floor plan, [plan] by [builder]
Builder page in an MPC[builder] [community]
Builder aggregate[community] builders, new construction builders [city]
Lifestyle[topic] [community] - amenities, schools, trails
Relocationmoving to [city], living in [community]
Blog postThe specific question or topic the post answers
Past-event / expiredNo primary. Set status = noindex_recommended and leave the lane empty

The three rules that keep the Target lane honest:

A declared target still has to survive the evidence. The client's list gets first claim on pages, not automatic approval. If a declared target has no measurable volume, wrong intent, or a SERP the client can't enter, it gets mapped anyway and marked contested or no_target with the reason stated plainly. Quietly dropping a term the client asked for is worse than telling them it won't work.

A sold-out or expiring page never receives a capture target. If a sold-out community page is currently the site's best ranker for a live commercial term, that's a finding, not a lane. Record the current position in the Own lane, mark the status, route the target elsewhere, and flag it in the readout, because the redirect-or-refresh decision usually needs client sign-off.

A page only gets a target it could plausibly reach. Attaching new homes [metro] to a single community page because nothing better exists is how maps produce work that cannot succeed. Ambition belongs on the Opportunity Map, not smuggled into a row that gets handed to a copywriter.

It also runs an entity-conflation check, and carries a worked example plus an explicit spec for how metadata and h-tag consume the output.

keyword-target-urlOne page in, one primary + up to four secondaries out, from GSC ground truth.

Step 1 - pull the page footprint.

Call field_discovery for the Search Console source before data_query, because field IDs differ per source. Then pull, scoped to the exact URL, last 90 days, searchType = web: every query the page earns, with clicks, impressions, CTR, and average position. The skill calls this the ground truth.

Step 2 - add volume and difficulty.

Run dataforseo_labs_google_ranked_keywords for the URL to attach volume and difficulty and to surface ranking terms outside the click-earning set. If DataForSEO isn't connected it skips cleanly, keeps the GSC read, and notes that volume and difficulty are unavailable.

Step 3 - pick the primary keyword.

One primary, chosen in this priority order:

  1. Intent fit to what the page actually is. A floor plan page doesn't get pointed at a community-discovery term just because that term has volume.
  2. Winnability. Prefer a query the page already ranks in striking distance for (roughly avg position 5–20 with real impressions) over a higher-volume term it has no foothold on. Cite the current position as the evidence.
  3. Demand. Among the intent-fit, winnable options, prefer higher volume and lower difficulty. If DataForSEO is absent, use GSC impressions as the demand proxy and say so.

Steps 4–5.

Pick 1–4 secondaries - the closest supporting variants and sub-intents that reinforce the primary rather than competing with it or drifting to a different page type; the skill is explicit: do not pad to reach four. Then a cannibalization check: if the GSC data shows another URL on the same property also ranking for the recommended primary, it flags it and routes resolution to keyword-map, because a single-page view cannot settle which page should win.

keyword-trackingStand up consistent tracking in whatever home the client already uses.

Step 1 - assemble the tracked set.

Load target keywords from keyword-list or keyword-map. Dedupe. Split brand vs non-brand using the client's brand tokens. Sanity-check the count - a focused non-brand core plus priority brand terms beats a bloated list. Attach the mapped landing URL per keyword from keyword-map where available, so tracking ties to the page that's supposed to win.

Step 2 - choose the tracking home.

Pick what the client already uses. Do not create a duplicate.

  • Semrush Position Tracking. Check projects_research for an existing project on this domain first. If one exists, add the set to it. If not, note that a project needs creating and use tracking_research for the read. Best fit when the client is already in Semrush and competitor comparison or visibility trend matters.
  • SE Ranking. If the client already tracks there, add the set there instead. Verify before creating.
  • VPS cron plus SQLite. The lightweight tool-agnostic option. Record the tracked set as the reference the scheduled DataForSEO pull reads on cadence. Use when there's no external tracking project or the goal is the closed-loop pipeline.

It states which home it chose and why in one line.

Steps 3–5.

Capture the baseline at the confirmed location and language (dataforseo_labs_google_ranked_keywords for the domain; serp_organic_live_advanced per priority keyword for not-yet-ranking terms; dataforseo_labs_google_keyword_overview to enrich volume and difficulty). Every row stamped with position (or "not in top 100"), volume, KD, mapped URL, brand/non-brand, capture date, and location. Persist the set and baseline to whatever downstream reports read - the tracking project, the VPS SQLite registry, or both - noting cadence (weekly for dme-notes, quarterly for the quarterly report). Report positions as point-in-time reads; flag anything projected as inference; avoid absolutist language unless a figure verifies it.

Output.

A tight chat summary in four parts: the tracked set with counts, market, and chosen home; the baseline snapshot as a short table (non-brand first, stamped with capture date and location); what's live automatically vs what still needs a human; and the cadence with which downstream deliverable consumes it.

site-url-intent-mapGroups the site by subfolder and maps a keyword cluster to each group.

Inputs.

A crawl export from Sitebulb or Screaming Frog, plus a Semrush organic-positions export.

Workflow.

It groups the site by subfolder page-group rather than per URL, then attaches the cluster of keywords each group should rank for, annotated with search volume and keyword difficulty. DataForSEO fills volume and KD for the opportunity terms that aren't in the Semrush export.

Output.

A client-ready spreadsheet in AdsIntelligence house style, built by script. It answers "what should /neighborhoods/ rank for," where keyword-map answers "what should this specific page rank for."

03

On-Page Execution

8 skills
on-page-seoSix elements in a fixed order, each constraining the next - with a keyword-map gate.

Steps 1–2.

Scope and resolve - is this one page, a templated page type, or the whole site. Then the prerequisite gate: it checks for a keyword map and stops if there isn't one, because every later element would target an unverified or contested query.

Step 3 - the sequence.

Six steps in a fixed order, because each one constrains the next.

3.1 Set the lane.

From the keyword-map row: the primary query as the one query this page owns, secondaries for support, the canonical entity name to use everywhere, and the page status. If the page is flagged as a collision, write toward its reassigned lane rather than the contested term. The instruction is blunt: never write any element in isolation.

3.2 Title tag, then meta description.

Lead the title with the primary query. Write a description that adds the specifics the title couldn't fit and earns both the click and the AI citation. Routes to metadata for length, structure, intent match, and page-type templates. Title first, then description, and they don't repeat each other.

3.3 H1 and heading hierarchy.

The H1 confirms what the title promised. The H2/H3 outline structures the page for scanning, AI extraction, and accessibility. One H1, no pipes, sentence case, answer-first under question headings. Routes to h-tag. This step comes before links and schema specifically because the heading outline determines where internal links and FAQ/schema blocks will sit.

3.4 Internal links.

Owned by this skill, no separate specialist. Done after headings because the body sections the links live in now exist, and done with the keyword map open so anchor text uses each target's canonical entity and doesn't cannibalize. The structure it works to is hub and spoke:

  • The community/MPC homepage is the hub, linking down to the neighborhoods index, inventory, floor plans, builders, and key lifestyle/relocation pages.
  • Neighborhood pages link up to the community, across to the floor plans and inventory in that neighborhood, and to relevant builder pages.
  • Floor plan pages link up to their neighborhood and community, and across to matching inventory (quick move-in homes of that plan).
  • Inventory and home-detail pages link up to the neighborhood, floor plan, and builder.
  • Blog, lifestyle, and relocation pages link to the money pages they support, not just to each other.

Anchor text rules: descriptive anchors matching the target page's primary query or canonical entity from the keyword map - new homes in Elyson or Elyson floor plans, not "click here." Keep anchors consistent with the target's canonical name. Never use an anchor targeting a query a different page owns, because the anchor is a relevance signal and pointing the wrong query at a page is a cannibalization vector exactly like a title is. Vary anchors naturally where the same target is linked many times, but stay inside the target's lane. Contextual in-body links beat nav and footer links; every indexable page should be reachable from at least one other relevant page; link from high-authority pages to the priority pages that need a lift. Breadcrumbs get handled here too, as the human-readable twin of BreadcrumbList schema - every page deeper than the homepage gets a breadcrumb trail using canonical entity names, and the trail must match the markup.

3.5 Schema.

Mark up the entities the page now expresses, using the same canonical name as the title, H1, breadcrumbs, and internal anchors. Comes last because schema must match what's visible, so the content and headings have to be settled first. Routes to schema.

3.6 The on-page AEO pass.

A cross-cutting final sweep. Confirm question-format headings are answered in the first sentence below them. Confirm prices, square footage, schools, distances, and amenity counts appear as concrete facts rather than brand copy. Confirm each section is self-contained enough to be lifted into an AI answer.

Cross-cutting invariants, checked on the finished page:

  • One canonical entity name, everywhere. Title, meta, H1, headings, breadcrumbs, internal anchors, schema name, and GBP all use the exact same string. Flagged as the single most violated invariant.
  • One query lane. Title, H1, first H2, and inbound internal anchors all point at the primary query. Secondaries support, they don't compete.
  • Intent match and deliver. A "Schools" H2 names real schools. A "Pricing" H2 shows real prices.
  • Uniqueness. No templated page ships with a duplicated title, description, or H1. Templated metadata is acceptable only when populated with unique per-page data.
  • Status honesty. No "now selling" on a sold-out phase, no stale prices, no expired promos, in any element or in schema.
  • Citation-ready. Declarative and factually dense beats clever and brand-y, because the specificity that earns the click earns the AI citation.
  • Mobile-first. The first sentence of the description carries value, geography, and entity before mobile truncation. H1 prominent above the fold.
on-page-specA build-ready per-page spec doc - from the live HTML, by page-type recipe.

Step 1 - set the keyword lane.

Pull the page's primary and secondary keywords from the keyword map, or the subfolder cluster map if one exists. If neither does, derive a provisional lane from the crawl plus Semrush or GSC and say so in chat, not in the doc. One primary per page, and never a term another page already owns.

Step 2 - fetch the LIVE page and read it.

Always work from live HTML rather than the crawl alone, because crawls go stale and titles, H1s, and copy may already have been updated. Grounding every recommendation in what's actually on the page is called mandatory. For sites behind a network allowlist, web_search for the URL first, then web_fetch from the result. From the HTML it captures: the current <title>, meta description, full heading hierarchy in document order, real content blocks, JSON-LD present, visible inventory and status, and any obvious bugs.

Step 3 - identify the page type.

The sections and heading tree depend on it. It picks from a set of recipes: listing hub, community, floor plan, blog/editorial, geo landing, builder, company/trust. The distinction it calls out: a listing hub (a page whose body is a dynamic directory of communities or models) gets specced very differently from an editorial page - you mirror the listing's real structure rather than inventing prose sections.

Step 4 - reconcile status and apply brand rules.

  • Lead with active inventory. Group sold-out and closed items under a clearly labeled "Past…" section rather than interleaving them.
  • Apply the client's voice and messaging constraints. Examples: a 55+ client may require "55 or better" and forbid "senior," "retirement," or "elderly"; a market may be heritage-only and has to be dropped from titles and metas.
  • Verbatim copy only, no placeholders. If a live number is uncertain, use the durable form such as "from the $800,000s" and flag verification in chat, not in the doc.

Step 5 - build the doc.

Write a spec.json, run the build script against it to produce <Client>_OnPage_Spec_<page-slug>.docx, then validate the output with the docx validator before presenting it. The output contains only what to implement: the exact title, the exact meta, a literal heading tree, the schema, the internal links, the FAQ copy. No commentary, no rationale.

metadataTitles and metas - pixel-aware, intent-matched, per page type.

Gates on the keyword map first.

Title tags.

  • Length: 50–60 characters, roughly 600 pixels. Google truncates past that and rewrites a large share of titles, most often when they're too long, keyword-stuffed, or mismatched to page intent.
  • Structure: lead with the primary keyword. The reliable pattern is Primary Keyword | Secondary Modifier | Brand. Strong: New Homes in Frisco TX | The Grove Frisco. Weak: The Grove Frisco - A Master-Planned Community in Frisco TX.
  • Brand placement: end of the title on most pages, front on the homepage and high-authority brand-search pages.
  • Avoid: keyword stuffing, ALL CAPS, stacked separators, clickbait that doesn't match the page, and dates unless the page is genuinely time-sensitive and maintained.

Meta descriptions.

  • Length: optimize for pixel width. Most effective land between 140–160 on desktop, 120–130 on mobile. Front-load so the first sentence stands alone if everything after is cut.
  • Structure: [Value proposition with primary keyword]. [Specific differentiator]. [CTA or invitation].
  • Specifics: concrete details beat abstract language for both CTR and AI citation. Price ranges like "from the $400s," square footage, number of floor plans or homesites, school district, distance to a known city or employer, named amenities.
  • CTAs that fit this vertical: Tour today, Schedule a visit, Explore floor plans, View available homes, Request information, Download the community guide, See pricing and availability. Avoid generic, transactional, and pressure language.
  • Avoid: keyword stuffing, generic filler, ALL CAPS, more than one exclamation point, quotation marks (Google often truncates at the first quote), outdated info, and duplicating the title tag.

Then across both: intent matching, uniqueness, entity consistency, mobile-first prioritization, an AEO section, SERP differentiation, an explicit division of labor between title and description, and per-page-type templates. For an audit it reads a Screaming Frog or Sitebulb export and finds duplicates, missing, and truncated at scale.

h-tagHeadings as a document outline - query-mirroring and answer-first for AEO.

Also gates on the keyword map.

H1 specs.

  • 20–70 characters. No truncation limit, but oversized H1s read as keyword stuffing.
  • Front-load the topic. Strong: New homes in Frisco TX from the $400s. Weak: Welcome to The Grove Frisco.
  • No pipes in H1s. Pipes belong in title tags as SERP separators. In an H1 they read as templated and machine-generated. The Magnolia | 4 Beds | 3 Baths | 2,847 Sqft is the example of what not to do; the specs go in a separate styled element below the H1.

Hierarchy.

Headings form a document outline, not a styling tool. H1 sets the topic, one per page. H2s are the major sections, H3s break those into subsections. Never skip levels (H1 → H3 with no H2 breaks the outline even when it looks fine visually). Never use H2/H3 as visual emphasis on non-heading content, and never use a styled <p> or <div> where a real heading element belongs.

The outline test.

Copy every heading on the page into a list. Does it read like a coherent table of contents that explains what the page is about, where it is, what topics are covered, and what questions get answered? If not, restructure.

AEO handling.

LLMs use headings to chunk content for retrieval, and clean descriptive headings get pulled into AI answers far more than clever ones. Query-mirroring headings outperform branded ones: What is it like living in Nocatee? beats The Nocatee experience. Answer-first structure: a question-format heading is only half the work - the first sentence below it must answer the question directly so it can be lifted. Good is H2: How much do new homes cost in Elyson? followed by "New homes in Elyson start in the $300s and range up to the $700s, depending on builder and floor plan." Bad is H2: Pricing followed by a vague paragraph about value and lifestyle. Then sections on sentence case, keyword and geography use, the heading-to-schema relationship, entity consistency, H1 vs hero text, per-page-type outlines, and a two-test QA run on every page.

schemaJSON-LD built for the entity graph - consistency is the spine.

Entity consistency

is the spine. Use the exact same canonical name in the title tag, H1, schema name, breadcrumbs, internal anchor text, navigation, and GBP. If the title says "Rancho Mission Viejo," the schema name says "Rancho Mission Viejo," not "RMV" and not "Rancho Mission Viejo Community." Inconsistency weakens entity association and creates retrieval ambiguity for both Google and AI. It matters most on community, builder, neighborhood, and floor plan names.

Page type to schema type.

A mapping table, with a specific caveat around FAQPage. Required on almost every page: a baseline set that goes everywhere. Aggregate rating and reviews: its own section, because incorrect markup here carries penalty risk.

Schema for AI retrieval.

What AI systems actually care about: a clear @type and name, relationships (containedInPlace, brand, parentOrganization), factual properties (price, address, beds, baths, sqft), canonical URLs (url, mainEntityOfPage), and sameAs pointing to GBP, Wikipedia, and social. Standing instructions: always include sameAs and geo plus a full address on Place entities, always include factual properties on listings and floor plans, use additionalProperty for spec data that doesn't fit core fields, and reference parent entities to build the entity graph. Then an audit workflow for existing markup, common failure modes, notes specific to the BBH WordPress schema plugin, and a quick-reference table of common type combinations.

schema-mapCrawl in, per-URL schema gap-and-priority table out.

Inputs.

A Screaming Frog or Sitebulb crawl, either uploaded or already on file.

Workflow.

Infer each URL's page type. Detect what schema is currently present by reading the crawl's structured-data extraction. Apply the target schema for that page type. Show the gap with a priority.

Output.

One row per indexable URL: page type, current schema types, target schema types, the gap, and a priority. Writing the actual JSON-LD hands off to schema.

internal-linkingHierarchy first, then priority-weighted contextual links with clean anchors.

Hierarchy first.

Internal linking only works on top of a clear hierarchy: parents link down to children, children link back up, siblings link laterally. If the architecture itself is broken - floor plans reachable only from one orphaned index - no amount of link work fixes it. So structure gets audited before anchors.

The core operating rules:

  • Link by priority, not evenly. Decide the priority pages (community homepage, inventory, top-converting neighborhoods, top-traffic blog posts, builder aggregate) and link to them more. Priority pages should sit 1–2 clicks from the homepage and earn contextual links from blog, lifestyle, and relocation content.
  • Contextual links beat navigation links. Nav, footer, and breadcrumb links get treated as structural and discounted for anchor purposes. In-body editorial links carry the equity. Target 2–5 contextual links from every blog, lifestyle, and relocation page into priority pages with descriptive anchors.
  • First link wins, and earlier is stronger. Google weights the first link to a given target on a page for anchor text, and earlier links carry more weight. Put priority links high in the body - the hero CTA or intro paragraph, not only the footer.
  • Volume has a floor and a ceiling. Every indexable page should link out to at least 2–3 relevant pages. But equity divides across out-links, so pages stuffed with hundreds dilute each. Avoid mega-menus repeated site-wide, footer link farms, and auto-generated "related content" with no topical relevance.
  • Cluster tightly, bridge sparingly. Group related content into topical clusters (community, schools, lifestyle, relocation, floor plans) with a hub page each. Link aggressively within a cluster; cross-cluster linking dilutes topical authority, so only where genuinely relevant.
  • Point at final URLs. Internal links hitting a 301/302, or pointing at noindexed or canonicalized pages, waste equity and crawl budget and confuse Google about the canonical.
  • AI retrieval reads the same signals. A page with many relevant inlinks and descriptive anchors reads as the authoritative answer for its topic and gets cited. Orphans get ignored even when the content is high quality.

It pulls inlinks, orphans, click depth, and internal redirects from Screaming Frog or Sitebulb. Per-page-type link recipes and an Avoid list of high-signal failures round it out. Anchor text always comes from the keyword map, named as the source of truth for anchors.

page-croOptimizes for the 90% who never fill out a form - micro-conversions first.

The conversion reality it reads first,

because it changes how everything after it gets judged. Most home purchases close offline after sales-office visits, calls, and in-person tours. Roughly 9 in 10 buyers never fill out a form. Two consequences:

  1. Judging a page only on form fills undercounts it. A page that drove 40 model-home visits and 0 form fills did its job. So it instruments and values micro-conversions (tour scheduled, brochure/floor-plan downloaded, click-to-call, directions clicked, interest list joined, home saved) and treats the relevant one as that page's KPI.
  2. Don't gate browsing behind a form. The 90% who want to look will leave. Gate sparingly - maybe for a detailed pricing sheet - never for basic content.

It treats conversion as a hierarchy rather than one event, and requires the page to offer the highest-intent action prominently while always giving a lower-friction path:

  • High intent: schedule a visit or book an appointment, call the sales counselor, get directions to the model.
  • Mid intent: request info or talk to a counselor, join the VIP or interest list, download a brochure or floor plan.
  • Low intent: save a home or plan, view photos/video/3D tour, check model hours, read FAQs.

The single highest-leverage and most underused move it identifies on MPC sites: capturing the not-ready buyer with a low-commitment interest or VIP list, because the journey runs months and email nurture is what bridges it.

Then three lenses, run separately

so friction problems don't get mistaken for copy problems: Lens 1 UX (friction and clarity), Lens 2 Copy (clarity and persuasion), Lens 3 CRO (the conversion mechanics themselves).

Prioritization.

Ranked by impact on the primary conversion, then effort, grouped as Quick wins (lead with these), Bigger bets (dev work, redesign, new form logic), and Nice-to-have. Closes with a QA pass and a list of common failure modes specific to builder and MPC pages.

04

Local / Google Business Profile

6 skills
gbp-auditFull profile + performance + review audit, connector as source of truth.

Step 1 - identify the listing.

Resolve the GMB account through Supermetrics, where the connector calls each profile a "Location." It loads the Supermetrics tools, then runs accounts_discovery(ds_id="GMB", filter="<name>"). The returned account_id gets copied verbatim, because it's a long compound ID like 106007263321979917632_12455125884141902260. If zero results come back it widens or drops the filter and lists locations. If several plausibly match it asks rather than guessing. It states the resolved listing name in the output so you can catch a wrong match. If you also gave it a dashboard screenshot, it uses that to corroborate things like Profile Strength and review count, but the connector is treated as the source of truth for data.

Step 2 - pull the current configuration.

No screenshot needed. GMB requires a date range even for attribute pulls, so it passes a short recent range and uses the Default report type. Dimensions: location name, primary category, additional categories, regular hours, special hours, website URL, description, primary phone, address lines, locality, region code, status, opening year, Maps URL, and place ID.

Step 3 - pull the performance baseline.

Performance report type, custom range covering the trailing 12 full months. The specific trap it avoids: use the yearMonth dimension, not month. The month dimension returns month-of-year as 01–12 and silently collapses a cross-year range into jumbled order. yearMonth, formatted like 2025-06, sorts cleanly. Core fields: yearMonth, views_search, views_maps, actions_total, actions_website, actions_phone, actions_driving_directions, actions_food_menu_clicks. Notes it carries: total views = search + maps, so don't also pull views_total; menu clicks and food orders only matter for dining listings; negligible phone actions on retail and community listings is normal, not a finding.

Step 4 - pull the search terms.

searchKeyword report type, fields search_keywords and search_impressions, filtered to impressions > 15, max 40 rows, over the last three full months. Often the single most useful pull, because it shows the real intent surfacing the listing, which you then check against the chosen primary category.

Step 5 - pull the reviews.

Reviews get their own audit section rather than a one-line note, because they're the strongest prominence lever after relevance. Lifetime totals via ReviewsTotals (total_review_count, total_review_star_rating) - the only place to get the full lifetime count and average. Per-review detail via the Reviews report type (review_create_date, review_star_rating, review_comment, review_reply_comment, max 200 rows). GMB history only goes back ~18 months (earliest around 2024-12-26), so this captures the recent window and gets paired with the lifetime totals. From it it computes three things: velocity (reviews/month, trailing 12-month total, rising or flat), sentiment (star distribution 5→1 plus the themes in comment text; sparse text gets flagged as a missed relevance signal), and response rate (share with a non-empty reply; zero or low is a finding). Plus posting activity via the Post report type (yearMonth, post_count) and an optional media count.

The competitor benchmark,

which needs an external source because the GMB connector only sees listings you own. It uses DataForSEO business_data_business_listings_search to pull comparable listings near the client in the same submarket, ordered by review count descending. It matches the comparable set to the listing type (shopping centers for a town-center listing, nearby builders and communities for a model-home listing) and prefers same-submarket peers over large regional anchors, because anchors inflate the bar. For a rigorous target it pulls the local-pack rankers for the actual target terms and sets the target to beat the lowest review count in the top 3, then aims for the median. Where a newer or smaller listing can't reach anchor parity near term, it gives a velocity-based interim milestone instead, labeled a planning target rather than a ranking guarantee.

Steps 6–7.

Diagnose, then build the Word doc to a fixed structure that explicitly cannot be reordered. Then QA.

gbp-gap-analysisLive map-pack analysis + winner dissection, with a geo-grid for proximity.

Step 1.

Identify and profile the client listing.

Step 2 - define the target term set.

Treated as a keyword research step, not a guess. It builds a ranked list of the most relevant and most lucrative local terms: start from the listing's own GBP search-terms report (proven demand); expand with DataForSEO local keyword research (category-driven terms like "townhomes [city]," "new homes [county]," localized "home builders near me," plus the client's product mix crossed with geography); pull local search volume at state level (e.g. "Virginia,United States") plus KD, so terms rank by lucrativeness not just relevance; prioritize terms that are commercial and high intent, have real local volume, and that the client has a credible shot at. Non-brand first. Output is a shortlist, typically 8–15 terms.

Step 3 - live map-pack rank analysis.

Called the heart of the skill. For each target term it pulls the live local and Maps results and records who actually ranks. Default: a single live pull centered on the listing's coordinates (or the city centroid for a broad term), capturing the top ~10 map results per term with name, category, rating, review count, and distance. Geo-grid when proximity is suspected: if a term's winner appears to rank purely because it sits closer to one point, it runs a multi-point grid across the service area (e.g. a 3×3 or 5×5), recording the client's rank at each point. This separates "we lose everywhere" (a relevance or prominence problem, fixable) from "we only lose where we're far" (a distance problem, largely fixed). It records the client's own rank per term, or "not in top 20 / not found."

Step 4 - dissect the winners.

For the actual live 3-pack and top-map winners of each term - explicitly not the client's assumed rivals - it reverse-engineers the ranking. For each winner it pulls the full GBP profile and compares against the client across: primary and secondary category match; review count, rating, recency; distance from the search point (the confounder); business-name relevance signals; listing completeness (services, products, description keyword coverage, attributes, hours, photos, posts); off-site prominence proxies. The output per winner: the specific reason(s) they beat the client, evidenced with the numbers, each tagged relevance, distance, or prominence.

Step 5 - synthesize and rank the fixes.

Ranked by impact × controllability × speed, split three ways: Fixable now (category correction, services and description coverage, photos, post cadence); Fixable but slower (review velocity and rating gap, off-site citations - the usual builder bottleneck); Fixed, not winnable (pure distance losses confirmed by the grid, stated plainly so the client doesn't spend on an unwinnable term). Then a concrete action plan: the exact category to set, the terms to build services and description around, the review-velocity target against each winner, and which target terms are realistic near-term wins vs long plays.

Step 6 - output.

A Word doc in house style (navy #1B2A4A title bar, teal #2E7D7A headers, no em dashes), leading with the competitive verdict and ranked fixes rather than the methodology.

gbp-optimizationEvery lever mapped to relevance, distance, or prominence - kept separate.

Organized around the local ranking model: relevance, distance, prominence. Every lever maps to one of them, and they stay separate because the fix differs.

The levers, grouped by risk and effect:

  • A. Foundations. These move ranking, and getting them wrong risks suspension. Business name, primary category, address and service area, hours. High impact paired with high risk is why they're grouped separately - you want to know before you edit that this is the category of change that can take a listing down.
  • B. Completeness and relevance. Secondary categories, services and products, description, attributes, photos.
  • C. Prominence and engagement. Reviews, Q&A, posts, engagement signals, citations, NAP consistency.
  • D. Multi-listing and MPC specifics. Which entity gets a listing, how model homes and sales centers relate to the community, handling duplicates.

Then a measurement spine tying changes back to observable metrics, an output format, a QA pass, and a list of failure modes that recur specifically on builder and MPC profiles.

gbp-performance-auditReconcile the GBP numbers, then score five lenses.

Steps.

0. Resolve inputs before pulling anything. 1. Pull impressions, actions (website clicks, calls, direction requests, messages), search terms, reviews, and posts. 2. Apply reconciliation rules before interpreting anything - the same discipline as the organic skills: get the numbers straight before you tell a story about them. 3. Score five lenses. 4. Output: a scorecard, top findings, prioritized recommendations, and data notes. It also lists optional additional data sources you can layer in.

gbp-postsStrategy-first post production - pillar rotation, per-community variants.

Strategy first.

It sets a pillar rotation and maps the quarter before writing any copy, so posts ladder to something rather than being invented month to month.

The rest.

  • Post types. What's New, Event, and Offer, each with different required fields and use cases.
  • Copy constraints and voice. Character limits and tone, plus the CTA button actionType values available on a LocalPost and which fits which post.
  • Images. A dedicated section on getting a Google-fetchable URL, because the API needs a publicly reachable image and this is a recurring practical blocker.
  • Multi-community handling. For one builder with many communities it works out which listing gets which post, and writes per-community variants of a builder-wide message rather than posting identical copy across twenty profiles.
  • Cadence and batching. How many, how often, and how to produce them in batches.
  • Scheduling. Called out as an important nuance, because GBP scheduling behavior trips people up.

Deliverable. A workbook plus a QA and review packet. Closes with common failure modes.

gbp-utm-trackingAligns new UTMs to existing GA4 history so YoY doesn't fracture.

Steps.

1. Resolve the client and destination domain. 2 - check what UTMs already exist: marked "do not skip." It pulls live GA4 data through Supermetrics to see what source, medium, campaign, and content values are already flowing in for this client. The point is that new links have to align with existing history rather than fragmenting it - a "correct" new convention that differs from the old one splits local traffic across two source/medium pairs and breaks YoY comparison. It never assumes the source value from memory. 3. Diagnose what's wrong against the agency UTM convention. 4. Output the corrected links, with a multi-location note and a set of hard rules.

05

Reporting & Data

13 skills
report-data-pullStage 3 of the quarterly pipeline - the raw workbook, described as a contract.

Inputs to resolve first.

Client, the reporting quarter, the accounts.

Data-integrity rules

applied throughout - the same unsegmented-total and web-filter discipline as everywhere else.

The workbook schema, described as a contract

so downstream skills can rely on its shape. One tab each: GA4, GSC, GMB, AI, Keywords, Pull log, Work & Roadmap. It covers the last complete quarter year over year. Sources: Supermetrics for GA4 (GAWA), GSC (GW), and GBP (GMB); DataForSEO for rankings, AI Overview citations, and LLM mentions; ClickUp for completed work and the roadmap. Then build and verify, then QA, with a list of common failure modes to check against before handing off.

reporting-prereqStage 4 - fills the pre-report template and leaves the gaps visible.

Inputs.

The stage-3 raw workbook plus the campaign strategy roadmap.

The fill mapping.

An explicit table of which source feeds which tab of the Pre-Reporting template. It populates Goals, Local & Maps, Strategic Roadmap, Wins & Highlights, KPIs, Pull Manually, Analysis & Commentary, and Work & Client Needs.

The rule that defines it:

anything it cannot source gets left as a "pull manually" or "confirm" flag rather than guessed at. The output is deliberately a partially-filled worksheet with the gaps visible, not a complete-looking document with invented content in it. Then QA and a list of common failure modes.

q2-updatedStage 5 - the eight-tab client report, where copy is interpretation not recitation.

Section 1 - what stays fixed.

Elements that never get edited per client.

Section 2 - the eight tabs,

each with its data sources and structure: Summary, Analysis, Website Traffic, Keywords, Local & Maps, AI/AEO, What's Next, Glossary. Data comes from Supermetrics (GSC, GA4, GBP), DataForSEO, Bing Webmaster, and Semrush position tracking, pulling the quarter year over year.

Section 3 - the copy principles.

Called the heart of the refinement.

A. Section intros are interpretation, not recitation. Named the single most important rule. The one or two sentence intro above each tab's cards and tables must give the meaning and the implication, because the reader can already see the numbers in the cards below. Bad, because it restates the numbers: "Organic search drove 6,390 visits, up 18% year over year, with new visitors up 16%. Organic is now 27.6% of all traffic." Good, because it gives the so-what: "Organic is becoming the primary way buyers reach the site, and its share keeps rising as paid spend pulls back, so this growth is increasingly earned rather than bought." Every tab intro has to tell the reader something they can't get from scanning the numbers.

B. The Analysis tab is an executive narrative. Exactly five sections, in order, all in the client's own verified data: 1. Market context (housing-market backdrop - builder confidence, rates, incentives - refreshed each quarter from a quick web pull); 2. Summary (the executive takeaway - what the quarter proved and where focus shifts, usually awareness to conversion); 3. What worked (bold-lead bullets, one per real win, "**Bold claim.** One sentence of supporting evidence and why it matters," pulled from the client's own tables); 4. Where additional opportunity exists (bold-lead bullets each flagged addressable or mixed - for MPCs entity fragmentation is usually the biggest lever); 5. Bottom line (the strategic read - usually that visibility is no longer the constraint and converting it is the next phase). The skill explicitly instructs not to carry the old "search landscape is evolving" zero-click section or any third-party research citations (Seer, SparkToro): they set up a decline narrative that often contradicts the client's own growth, and they present another report's research as this engagement's.

C. One consolidated table per section. Where a tab would carry two or more tables covering the same idea, merge them. Website Traffic merges the traffic and converting-page tables into a single Landing Pages table with each metric paired to its own vs-LY delta column. Keywords merges the headline rankings table and the position-tracking table. D. Entity emphasis for MPCs.

Sections 4–5.

House style and QA, then the build workflow.

dme-notesTwo sentences per client, weekly - pull everything first, then diagnose.

The two-phase pattern,

stated up front as not skippable: pull everything first, then diagnose, then write.

Phase 0.

Set the window.

Phase 1 - pull.

Load and verify Supermetrics first. Connector IDs: GW is Search Console, GAWA is GA4, GMB is Google Business Profile. All queries return async, so it polls get_async_query_results with the schedule_id. It calls field_discovery to confirm exact field IDs before data_query. Then it batches across all clients, one source at a time:

  1. GSC core. Clicks, impressions, CTR, position, broken out by site. Filter searchType == web on every GSC query - image, video, and news rows inflate the numbers. Marked mandatory.
  2. Non-brand keyword rankings. Pull GSC query data and split brand from non-brand. Non-brand is the SEO signal; brand gets called out only when significant. Highest-leverage: non-brand geo terms landing on already-high-converting community pages.
  3. GA4 conversions and key events. Organic sessions and key events per property. There's a 10-metric cap per GA4 query, so if more than 10 are needed it splits into two sequential queries with a shared control metric to reconcile them.
  4. GBP performance. Impressions and views plus actions (calls, direction requests, website clicks) per listing.

Then ClickUp for production status - active and unstarted production tasks per client list using the list IDs in the reference table. Pagination caps at 100, so it cycles pages. To capture completed milestones it passes include_closed=True, because custom "completed" statuses are not excluded by include_closed: False alone.

Phase 2 - diagnose then compose.

Only after everything is in. The note-writing rules:

  • Maximum two sentences per client.
  • Qualitative and directional, no specific numbers. "Non-brand clicks up nicely WoW with impressions also growing," not "clicks up 12%."
  • Lead with week over week. Layer MoM, YTD, or YoY only when it changes the read.
  • Scan all four families and weave in only what moved or matters. A flat metric doesn't need a sentence.
  • Every sentence passes "so what." If a number could support the opposite conclusion, it isn't a finding.
  • Be explicit about inference vs fact: "suggests" and "likely," not asserted causes the data only hints at.
  • Flag missing data plainly rather than guessing.

Carries a reference table of the 14 active clients with their list IDs.

weekly-emailWhat actually shipped + this week's numbers, in a five-section client email.

Phase 0.

Scope it.

Phase 1 - pull what actually happened.

Completed work from ClickUp. Run tool_search for ClickUp, pull the client's list by ID, get tasks closed or moved to a completed status during the reporting week plus tasks due or in progress for the coming week. Pagination caps at 100; custom completed statuses aren't excluded by include_closed: False alone, so it passes include_closed=True when hunting for finished work. If ClickUp returns nothing for the week, it tells you and asks what shipped rather than writing generic filler - an email claiming work that did not happen is worse than a late email.

Performance data from Windsor.ai. It reads the windsor-authoritative-metrics skill first. Confirm the Windsor tools are present and stop and tell the user if not; never estimate. Resolve the exact GA4 property and GSC site rather than guessing an account ID. Call get_fields before get_data for each connector. Pull every headline total unsegmented. Connector slugs are googleanalytics4 and searchconsole. Then, one query at a time, for both weeks: (1) GA4 organic sessions, property-scoped, organic filter in its own query; (2) GA4 leads - it breaks the mix down before calling anything a lead, because Maps direction clicks and phone taps inflate the count, and reports form submissions and calls as leads; (3) GSC clicks, impressions, average position, site-scoped.

Phase 2 - write it.

Five sections with specific rules:

  • Completed. Three to five bullets, one line each, phrased as outcomes not task names. "Rewrote titles and metas across 24 floor plan pages" beats "Metadata workbook."
  • Performance Snapshot. One line per metric: the number, the direction, and the comparison window. For keyword rankings, name specific terms and positions rather than an average that moves invisibly. If a metric is flat or down, say so plainly. Don't report a metric you couldn't pull.
  • Why This Matters. Two to four sentences, no jargon, tied to qualified traffic, tours, and sales. Connect one specific movement to one business consequence. Don't claim causation the data only hints at. If the honest read is "too early to tell," say that.
  • Next Week. Three bullets max, concrete and verifiable, matching what's actually queued in ClickUp.
  • Action Needed. Only when something is genuinely blocked. Omit the whole section when there's nothing, because a standing empty ask trains the client to ignore it.

Phase 3.

Deliver. Includes a client reference table and a worked example of the snapshot section.

seo-liftThe YoY lift workbook - eight pulls, then artifact-flag before you build.

Phase 0.

Resolve client and windows.

Phase 1 - pull everything, then build.

Explicitly: do not write the workbook before the data is in. Eight pulls:

  1. GA4 organic totals YoY. Sessions, newUsers, conversions, channel filtered to Organic Search, with compare_type prev_year and compare_show value.
  2. GSC totals YoY, no dimension: clicks, impressions, position, searchType == web. Then GSC brand-only YoY with a query =@ <brandtoken> filter. Non-brand derived by subtraction.
  3. GSC query-level, both windows separately, feeding the Query Lift and Keyword Rankings tabs.
  4. GBP YoY. views_total, views_search, views_maps, actions_total, actions_website, actions_phone, actions_driving_directions, Performance report type, compare_type prev_year.
  5. GBP daily for the trend, ~13 months back, same fields plus date.
  6. GA4 organic by landingPage, both windows separately, for the Content and Select Pages tabs.
  7. DataForSEO enrichment for the non-brand keyword set: bulk_keyword_difficulty for KD and kw_data_google_ads_search_volume for volume.
  8. Wins scouting for the Wins tab: three DataForSEO calls against the client domain - organic + AI Overview and local map pack via dataforseo_labs_google_ranked_keywords, and AI-answer mentions via ai_opt_llm_ment_search. Candidates, not confirmed wins.

All Supermetrics queries return async, so it polls with the schedule_id. If data_query returns "No approval received," it retries once, and if that persists the user has to reconnect Supermetrics in settings.

Phase 2 - diagnose and flag artifacts.

Marked "do not skip." Before building anything it classifies each metric as real movement or artifact. Two named traps: GA4 key events YoY - definition changes between years are common and produce fake collapses or spikes (the example given is a page reading 1,162 key events one year and 119 the next), so key events get shown as current-period only with a KE rate, never as a YoY comparison unless the event definitions are confirmed identical; and blended GSC average position - a large change is often a shift in the deep long tail rather than real movement on terms that matter.

Phases 3 & 3.5.

Build the workbook, then the wins shot list - a scouting layer for the reel. Plus house style enforced in all cells and prose, and an optional control-cohort attribution upgrade.

highlight-reelA scored candidate list of real wins - never fabricates or recreates screenshots.

What it produces and what it doesn't, stated first: a candidate list. It does not verify wins, and it never fabricates or recreates screenshots.

Steps 0–1.

Resolve inputs, then pull candidates from organic rankings, the local map pack, AI Overview citations, and LLM mentions.

Step 2 - score and group.

Each candidate gets a promise flag:

  • High. Non-brand, buyer or local intent, strong position (organic 5 or better, map pack 1–3, or an AI Overview / AI answer citation present), with meaningful volume.
  • Medium. Relevant but weaker (organic 6–10, map pack position 3, or sitting low on the visible page), or a strong position at low volume.
  • Low. Informational-only relevance, page 2, or an odd ranking such as ranking for another builder's brand name.

Grouped by win type, non-brand first. Brand wins (the client's own name and close variants) get compressed into a single filler line, since the client already knows their name.

The relevance filter.

It drops rankings with no home-shopping value even when volume is high, and names what it dropped so the cut reads as deliberate. Real examples cited: a cluster ranking for highway and parkway terms, "which direction should a house face," "what are loquats good for," "color of the year," and "companies in downtown Houston."

Step 3.

Deliver the candidate list. You go confirm the High ones live and screenshot them. Captions only get written after you confirm which wins are real.

funnel-stage-reportMaps pages to funnel stages (first match wins) and reports leads per stage.

Phases 0–2.

Resolve client, window, and key events. Batch pull page-level data, then build. Normalize and join GSC to GA4 at page level.

Phase 3 - map pages to funnel stages.

It applies an ordered rule set where first match wins, so more specific folders (events, venues, builders) get tested before the Consideration and Awareness fallbacks. The defaults:

  • Decision. Transactional and high intent: homes, inventory, builders, rentals, contact, pricing, floor plans.
  • Consideration. Shortlisting: homepage, community, neighborhood, amenities, FAQ, about, virtual tours.
  • Awareness. Informational and editorial: blog, lifestyle, food, relocation, event recaps. The catch-all for bare-slug editorial posts.
  • Local/Events. Local intent: event calendar, individual events, venues.

Before finalizing it scans the assignments and reclassifies anything the rules got wrong for this specific client, and notes judgment calls in the method block. It surfaces a short "pages I was unsure about" list rather than silently bucketing them.

Phase 4.

Assemble the joined, staged page table into input JSON and run the build script (styling, per-stage tabs, the Summary rollup, method notes). The output includes leads per 1,000 sessions per stage, so you can see whether a stage has a traffic problem or a conversion problem.

kpi-frameworkNot a file - the scoping rule: evaluate against the client's declared focus set.

Not a file producer. It sets the scoping rules everything else reads.

The core rule.

Rankings and performance get evaluated against the client's declared focus set (target keywords, AI prompts, target URLs), grouped by funnel stage. A generic site-wide ranking or traffic pull is not a KPI. The focus set is the intelligence that scopes the evaluation. It lives in a per-client focus file; keywords and prompts come from keyword-list, target URLs from keyword-map.

Workflow.

Resolve which client. Load the focus file. If none exists, build one from keyword-list and keyword-map output, or proceed unscoped and flag it. For each funnel stage, pull only the in-scope keywords, prompts, and URLs. Score each stage. Report Top → Middle → Bottom. Report any KPI with no focus entries as "not currently tracked" rather than substituting a site-wide number.

The KPIs and their sources.

Bottom (primary business outcomes): GA4 key events and conversions from GAWA using the client's defined key events; phone calls from GA4 click-to-call plus GBP calls from GMB; conversion volume as a rollup; rankings for high-intent keywords from DataForSEO/GSC scoped to focus keywords staged bottom; map-pack visibility for local-eligible clients scoped to high-intent local terms. Middle (consideration): traffic to key mid-funnel pages from GA4+GSC scoped to focus target URLs; rankings for branded + consideration keywords, split brand vs non-brand; performance of pages flagged conversion_support. Top (visibility and awareness): organic visibility for informational content from GSC with searchType == web; AI visibility from the DataForSEO AI Optimization endpoints (ai_opt_llm_ment_agg_metrics, ai_opt_llm_ment_search, ai_opt_llm_ment_top_domains) scoped to focus prompts and reported as a current-state snapshot rather than a trend; blog and content performance; rankings for informational keywords; content distribution from GSC + GBP impressions.

Scoring, per stage per period.

Ranking metrics are average position and top-10 count across the in-scope focus keywords only (lower average position better). Movement is QoQ and YoY against the same in-scope set so periods stay comparable. Performance metrics sum GA4 and GSC values for the in-scope target URLs, but site or page totals get pulled directly rather than summed from a broken-down query. AI visibility is mention rate, share of voice by engine, and prompt-by-prompt result.

kpi-trackerThe four-tab KPI workbook, scored per funnel stage.

Phases.

0. Resolve the client and load the focus set. 1. Pull live data scoped per funnel stage from Supermetrics (GA4 GAWA, GSC GW, GBP GMB) and DataForSEO. 2. Score each stage: average position, top-10 count, QoQ and YoY movement. 3. Build a four-tab workbook: README, Focus Set, KPI Master, Quarterly Tracker. It carries an input JSON schema and house style rules.

raw-dataPreserves query results exactly - one tab per result, plus a pull log.

What it does and doesn't do, stated first. It preserves data exactly as returned. No reshaping, aggregation, reconciliation, or interpretation.

Getting the data.

It takes the result of a Supermetrics or Windsor query already run in the conversation.

Workbook structure.

One tab per query result, plus a Pull log tab recording source, connector, date range, filters, and pull timestamp. The Pull log is what makes the snapshot reproducible later. Then house conventions and delivery.

analysisOpen-ended investigation in four beats: pull, flag, hypothesize, propose.

Before you start.

Scope the question.

Metrics-integrity rules,

marked non-negotiable - the same unsegmented and web-filter discipline.

The method, four beats:

  1. Pull. Establish the ground truth.
  2. Flag. Find what actually moved, and confirm it is real. Same artifact instinct as root-cause-analysis, applied to open-ended investigation.
  3. Hypothesize. Decompose to the driver.
  4. Propose. Turn the finding into a decision, not a description.

Then a claim-discipline section, an output format, and a "hands off to" list so it doesn't duplicate the scoped audit skills.

windsor-authoritative-metricsA guardrail - report every total unsegmented, never sum a breakdown.

A guardrail rather than a deliverable.

Before you start.

Confirm the connector is present.

The core rule.

Report every total from an unsegmented query. Never sum a breakdown to get a total. A platform's headline number (the GA4 Sessions scorecard, the Search Console clicks total, ad account spend) is computed differently from the same metric split by a dimension. Break it down by source/medium, month, query, or page and the per-row values do not add back up. Sum them and present that as the account total and you report a number the client can't reconcile against their own dashboard. The skill notes this isn't sampling noise you can hand-wave - it's structural, and it cuts both ways: a segmented sum can come out higher or lower than the true total depending on the platform and dimension. It includes the explanation of why they diverge so you can defend it to a client. Channel labels are not ground truth, especially Paid vs Organic Social; a mistagged campaign lands in the wrong bucket.

The workflow.

  1. Resolve the exact account, property, or site ID first.
  2. Pull the headline total unsegmented.
  3. Pull breakdowns separately, for the "why" only.
  4. Reconcile before you publish.
  5. Report cleanly.

Then sections on turning the numbers into a deliverable, tool mechanics that bite people, things to watch for, and a worked example of the exact mistake the skill exists to prevent.

06

Strategy & Planning

7 skills
seo-strategistDestination before diagnosis - a five-phase roadmap with a moat per phase.

Phases 0–3.

0. Scope the campaign. 1 - define what winning looks like at each stage and load the client's focus set. Destination before diagnosis, the inversion that separates this from an audit. 2. Diagnose current state and locate the client on the arc. 3. Competitive gap analysis bounded to the service area.

Phase 4 - build the roadmap.

This is the deliverable. It uses a reusable phase model adapted to the client rather than forced from a template. The arc for a builder or MPC generally runs:

  1. Foundation. Make the site able to compete and capture. Technical health, crawl/render/index, tracking and attribution truth, entity consolidation, and capture infrastructure (tour, VIP, and call paths present and measured). Stops leaks and makes existing demand convert.
  2. Capture in-market demand. Win the money terms winnable now. Localized high-intent non-brand (segment + geo), community, neighborhood, floor plan and inventory pages, and the local pack via GBP + reviews. Organic starts producing measurable sales-center appointments.
  3. Topical and answer authority. Expand the funnel and own the category conversation. A buyer-journey content program (relocation, lifestyle, comparisons, buyer-question hubs), plus the AEO and citation build, schema and entity depth, and internal-link architecture into clusters. Fills the top and middle that compound into future capture.
  4. Market leadership. Become the definitive answer and build the moat. Share-of-voice leadership against local rivals, local and vertical authority building, a review moat, comprehensive coverage, and defense and expansion of the local pack and AI citations. Organic becomes a primary, cost-advantaged pipeline source.
  5. Defend and compound. Protect and scale. Maintain freshness, defend rankings, pack, and citations, absorb new communities/phases/inventory as they release, keep improving capture conversion, and run the proof-of-ROI loop back to sales outcomes.

For every phase it specifies six things: the strategic objective; the key workstreams across all disciplines, each routed to the specialist skill that executes it; the moat it builds (the durable advantage that makes the wins compound); the milestone or exit criteria showing the phase is done; the expected business effect on capture and pipeline (directional and evidence-anchored, never a promised number); and a realistic duration with pace tied to the authority gap and client resourcing. Every workstream has to be written specifically enough to decompose into concrete tasks - naming actual pages, terms, entities, schema types, and rivals - because each rolls up into the master action-item register.

Then five pieces of connective strategy:

  • The strategic thesis. The core bet on how this specific client wins organic in their market. Every phase serves this.
  • The growth model. The flywheel turning visibility into capture into appointments into closes into more authority, and how each phase raises its rate.
  • The KPI ladder to ROI. Leading indicators (rankings, share of voice, citations, impressions), intermediate (non-brand sessions, engagement, capture events, GBP actions), and lagging/ROI (sales-center appointments, offline closes, organic share of pipeline, CAC vs paid), laddered so early-phase progress visibly builds toward the pipeline outcome. It names the north-star capture metric.
  • The partnership operating model. The cadence of quarterly strategy reviews and monthly performance, the decision gates between phases, and what the client has to resource: dev capacity, review generation, and sales/CRM data to close the ROI loop.
  • Risks and dependencies. What could derail the arc - authority-gap pace, dev bottlenecks, review generation depending on the sales team, algorithm and AI-answer volatility, seasonality, the offline-attribution blind spot - and how the plan stays resilient.
initiativesCoherent bets, not tasks - ranked by impact on capture, never by ease.

The distinction it opens with: what an initiative is, and what it isn't. Initiatives are coherent bets, not tasks.

The impact-first discipline.

Impact means line of sight to capture and pipeline, not traffic for its own sake. Because roughly 9 in 10 purchases close offline with no form fill, impact gets judged by how much an initiative grows high-intent capture events (tours or appointments scheduled, click-to-call, direction requests, VIP or interest-list joins, floor plan or brochure inquiries) that feed sales-center appointments and closes. An initiative that would add traffic with no path to capture ranks low regardless of the traffic number. Two rules keep the list honest:

  • Every initiative traces to evidence or is labeled a hypothesis. Name the data point behind it: a ranking drop, a decayed cluster, a competitor gap, a tracking blind spot, an AI-citation absence. If it rests on a hunch, say so and mark confidence low. Never invent a finding or promise a number.
  • Rank by impact, not by ease or novelty. A hard, high-impact initiative outranks an easy, low-impact one. Effort and confidence break ties and inform sequencing; they do not set the rank.

Phases.

0. Scope the client. 1 - assemble the evidence: reuse first, then fill only real gaps. It looks at everything already on file (crawl, Supermetrics data, DataForSEO, internal docs, prior audits) before pulling anything new. 2. Synthesize into initiatives. 3. Prioritize by impact. Each initiative carries a thesis, the evidence, the expected pipeline effect, and impact, effort, and confidence scores. Closes with QA and common failure modes.

goalsGrounded, observable, pipeline-facing goals - reframe, don't sugarcoat.

What a goal is and isn't, stated first.

The discipline, four rules:

  • Ground every goal in the client's reality. Name the actual pages, terms, prompts, listings, or entities. "Improve visibility" is not a goal. "The community is the named, recommended result on the priority non-brand commercial prompts, cited from home-buying pages rather than only lifestyle blog content" is.
  • Line of sight to the pipeline. Bottom-of-funnel goals get stated against high-intent capture (tours or appointments, click-to-call, direction requests, interest-list joins, brochure or floor plan inquiries), not raw form fills or traffic.
  • Signals must be observable later. Write each signal so that a quarter or a year on, anyone can look at the data and say plainly whether it was met.
  • Reframe, do not sugarcoat. If the input is a list of challenges, each goal should honestly correspond to a real gap, stated as the outcome that closes it. Don't hide the weakness; point at the win on the other side of it.

Phases.

0. Scope the client, kept light. 1. Gather the baseline, reusing what exists first. 2. Write the goals structured by funnel stage, each paired with its proving signal. 3. Close with the through-line connecting them. Includes a mini worked example for a single community.

30-60-90Creates the ~55-task ClickUp onboarding plan - confirms before writing.

Steps.

1. Resolve the client, the ClickUp list ID, and the kickoff date. 2. Compute each task's due date as kickoff plus an offset in days, formatted YYYY-MM-DD. 3 - confirm before writing: it shows you the resolved list, the kickoff date, and the task count (~55), and notes every task will carry the seo tag. It gets a go-ahead. It does not create tasks silently. 4 - verify the seo tag exists in the space, via a task filter or a trial read. ClickUp rejects clickup_create_task outright if the tag doesn't exist; if it's missing, it either tells you to create it once or creates the tasks untagged and adds the tag afterward with clickup_add_tag_to_task. 5. Create each task with clickup_create_task, passing list_id, a phase-prefixed name, the due date, and the seo tag. The phase prefix goes in the name itself, formatted [Phase] Task, e.g. [Technical] Crawl + technical SEO audit (P1/P2/P3). 6. Report back the count created, the list, the date range, and flag any failures.

Notes it carries.

Phases run parallel in places - Local and Technical overlap by design - and the dates reflect that rather than being strictly sequential. If you want owners assigned it runs clickup_resolve_assignees first; the default is unassigned. If you want a different anchor like "start next Monday," it recomputes every date from that Day 0.

client-briefA researched company snapshot tied to the SEO/AEO angles that matter.

Steps.

0. Resolve the client. 1. Research the open web plus any internal sources on file. 2. Assemble the brief: company snapshot, markets, product mix, active and recent communities, leadership, positioning and differentiators. 3. SEO and AEO angles that matter for the engagement, so the research connects to the work rather than sitting as background. 4. Close. Carries guardrails against padding the brief with unverified detail.

premortem"It's six months from now and this failed" - parallel deep-dives per risk.

Context gathering, the minimum bar.

Three steps before it will run: scan for existing context, evaluate whether that context is sufficient, and fill gaps conversationally if it isn't.

The session, six steps:

  1. Set the frame. It is six months from now and this failed.
  2. Generate failure reasons. The raw premortem, listing every way it went wrong.
  3. Deep-dive agents. One per failure reason, all running in parallel, so each reason gets developed independently rather than the most obvious risk crowding out the rest.
  4. Synthesis. Pull the deep dives together.
  5. Generate the premortem report.
  6. Save the transcript.

Includes a worked example of premortem-ing a product launch.

breakdownTurns a vague ask into genuinely actionable steps - defines "actionable" first.

What "actionable" means, defined first, because the failure mode is restating the input at a slightly lower altitude. Then how to break it down, the output format as bullets, style rules, and examples.

07

Content & Writing

3 skills
content-calendarA script that resolves the assigned monthly topic - and never fabricates one.

How to look it up.

It runs a script. Client and period both accept loose input, so aliases like M&S, ATL, or jbgs resolve, months work as Aug, August, or 2026-08, and weeks work as week 5.

python3 lookup.py "<client>" "<period>"   # e.g. "Atlantic Builders" "August"
python3 lookup.py "<client>"              # full calendar for that client
python3 lookup.py --list                  # all clients plus coverage

The script resolves the alias, normalizes the period, and prints the matching title. That exact title is the post topic.

Reading the result, four cases:

  • One match. That's the topic. Hand off to the content skill.
  • NO CALENDAR ON FILE. Currently Nexton, The Grove Frisco, and Ponder. No assigned topic. It does not fabricate one; it tells you the client has no calendar and asks what topic you want, or offers to propose options.
  • Multiple matches. Some clients run several posts in one month (Grenadier especially), and a bare month name can hit two different years. The script flags the most likely row with >> (the soonest entry on or after today). If you named a year that disambiguates; otherwise it confirms which one you mean rather than assuming.
  • No match for that period. The script prints the client's full calendar so you can see what's actually scheduled, and surfaces that rather than guessing.

Notes it carries.

"This month" and "next month" resolve against today's date. Miller & Smith rows include a planned publish date, surfaced when relevant. JBGS Living is sequenced by week 1–12 rather than by calendar month. If a requested client isn't in the list at all it says so rather than silently treating them as a no-calendar client. Topics get added or changed by editing calendar.tsv, which the script reads live.

client-blog-voiceDrafts in the client's authentic voice, then audits against 15 AI-cadence tells.

Step 1 - find the voice profile.

It looks in clients/ for a <client-name>.md profile and reads it if one exists.

Step 2 - build the profile if it's missing.

It needs 2–3 pieces of the client's own published writing as reference. It prefers posts the client wrote themselves over agency-written ones, because the point is matching the authentic voice rather than copying prior AI output. If it isn't sure which posts are client-authored, it asks. Then it fetches the posts, fills out the voice-profile template, and saves the result to clients/<client-name>.md so the profile accumulates for next time.

Steps 3–4.

Read the brief (topic, target length, required links or facts, SEO targets, and the CTA). Then draft in the profiled voice - matching the profile's cadence, point of view, formality, list habits, opening style, and closing/CTA style.

Step 5 - run the self-audit and revise.

Marked as the step where most of the AI cadence actually gets removed, and explicitly not skippable. The 15 cadence rules it audits against:

  1. Vary sentence length hard. The single biggest tell. At least one genuinely long (25+ word) subordinated or cumulative sentence every few paragraphs, allowed to flow with embedded clauses. Never three short sentences stacked unless the client's own profile does that.
  2. Kill the rhetorical-question-then-payoff beat. "And the best part? You don't have to go far." Convert to declarative or fold into a longer sentence.
  3. No fragments for punch. "As in, you can walk." reads as manufactured rhythm.
  4. Ration the rule of three. Triads feel natural once and robotic by the fourth time. Vary list length and fold most lists into running prose.
  5. No em dashes.
  6. Vary how sections open. If every section starts with a one-sentence thesis, the shape itself signals AI.
  7. Cut AI vocabulary and promotional inflation. Vibrant, bustling, nestled, boasts, elevate, a testament to, in the heart of, look no further, when it comes to, in today's world, whether you're X or Y. Plus quasi-spiritual inflation: ritual, sanctuary, sacred, tapestry, symphony, journey, magic, soul, embrace. "Ritual" in particular reads as cultish applied to everyday things like a walk or a coffee run - call the thing what it is: a habit, a routine, a tradition, a favorite spot. Also intention-attribution (thoughtful, intentional, curated, seamless, elevated, designed to) and stacked intensifiers (really, very, truly, incredibly, absolutely, simply).
  8. Avoid negative parallelism. "It's not just a house, it's a home."
  9. Ground claims in specifics. Real numbers, names, places instead of "renowned" or "world-class."
  10. End on something concrete, not a recap. No "In short," "All in all," "At the end of the day."
  11. Show significance, don't assert it. Cut "that's the whole point," "that's the beauty of it," "that's exactly why it matters." Also cut audience-widening hedges like "for anyone who travels, or simply wishes they could."
  12. Cut hedge-stacking. Within what's true and legally safe, commit: "the math favors the townhome owner," not "the math tends to often favor."
  13. Use concrete verbs, not abstract noun phrases. The offers / provides / delivers / features / boasts / ensures pattern is core AI texture. "Someone else mows the lawn, so your Saturdays are yours," not "offers a low-maintenance lifestyle."
  14. Vary paragraph length. A one-line paragraph next to a longer one is one of the strongest human signals.
  15. Give the piece a spine. Concede a real tradeoff and then make the case anyway: "a townhome won't give you a sprawling backyard; what it gives you instead is your weekends."

Step 6 - deliver.

If the brief forced a deviation from the client's normal voice (a legally required disclaimer or a mandated phrase), it notes that briefly so a human can decide. Carries a standing warning not to overcorrect into blandness.

humanizerA taxonomy of named AI tells, each with before/after - leads with soul.

Works through a taxonomy of named AI tells, each with before and after examples.

It leads with personality and soul

rather than mechanics, on the argument that writing can be technically clean and still lifeless. That section covers the signs of soulless writing even when it's clean, how to add voice, and a worked before/after.

Content patterns.

(1) Undue emphasis on significance, legacy, and broader trends. (2) Undue emphasis on notability and media coverage. (3) Superficial analyses with -ing endings. (4) Promotional and advertisement-like language. (5) Vague attributions and weasel words. (6) Outline-like "challenges and future prospects" sections.

Language and grammar patterns.

(7) Overused AI vocabulary words. (8) Copula avoidance (avoiding "is" and "are"). (9) Negative parallelisms. (10) Rule of three overuse. (11) Elegant variation (synonym cycling). (12) False ranges.

Style patterns.

(13) Em dash overuse.

08

Ops, Assets & Utilities

7 skills
internal-logAssembles the 17-tab client log from the skills that own each tab.

Steps.

1. Resolve the client and confirm scope - which tabs you actually want filled. 2. Fill the Client Overview tab from client records automatically. 3. For each requested analytical tab, go get that content from the skill that owns it. The 17 tabs are Client Overview, Audit, Keyword Research, Strategy Checklist, KWM, Internal Linking, Robots.txt, Canonicals, Redirects, Schema, H-Tag Restructuring, Image Optimization, Blog Ideation, Content Tracker, GBP Optimization, GMB Posts, and Entity Mapping. 4. Write the workbook. 5. Recalculate and verify. 6. Present. It owns assembly, not analysis, and supports a targeted single-tab fill since most real requests are "put the keyword research in the log" rather than a full build.

sendWrites a finished deliverable onto the right ClickUp task - asks before creating.

Steps.

1. Identify the deliverable in the conversation. 2. Resolve the client to a ClickUp list. 3 - find the target task or subtask: it searches the resolved list for a task whose name matches the deliverable's purpose and period, e.g. "June Belmont Bay blog," "Q1 SEO report," "GBP optimization," respecting an explicit name if you gave one. Exact/clear match → uses it. Multiple plausible → lists them and asks. No match → step 4. 4 - if no task exists, ask before creating: it does not auto-create. It proposes a concrete task name (plus whether it should be a subtask and under which parent, inferred from client, deliverable, and period), then asks for a yes or a correction - e.g. "No matching task in Miller & Smith. Create subtask 'June Belmont Bay Blog' under 'Content – 2026'? Or point me at the right one." It creates only after confirmation. 5 - write the deliverable into the description: set the task description to the deliverable in clean markdown. If the task already has real content, it appends under a dated divider rather than overwriting, and confirms overwrite vs append only if the existing body looks like content that matters. Rich files get attached in the same step. 6 - confirm: one line back with the task name, the list, and the ClickUp link. No recap of the deliverable itself.

summaryCondenses the previous response to five bullets or fewer.

Condenses the immediately preceding response to 5 bullets or fewer. Covers what to summarize, output rules, format, and an example.

open-harvest-job-chatOpens a Harvest job (which assigns the number), then the matching ClickUp task.

First, check the not-to-run conditions.

A plain ClickUp task with no Harvest project is a different workflow entirely. The word "job" triggers this skill; "task" does not.

Then decide the mode:

opening a new job or editing an existing one.

The intake, which the skill calls the crux.

A terse sectioned chat, never a form and never a widget. It asks in small batches: job name, client, and job type first, then Content, then Details, then Review & Target Dates, then Budget & Billing. Job types come from closed lists it will not invent or rename: eBlast, Print Ad, Signage, Digital Ads, Printed Collateral, Web Project, Video, Sales Center, SEO, Other. All data comes live from Outlook, Harvest, and ClickUp, never from memory. Client matching is forgiving, and it dedupes before writing anything.

The ordering constraint.

It opens the job in Harvest first, because Harvest is what assigns the job number. Then it creates the matching ClickUp task itself, with the same number and name. There is no Zapier in the loop. Editing a job changes both systems. Carries per-user client preferences and a fixed output format.

box-asset-taggerTags Box assets from the folder path (source of truth), then the pixels.

Resolve the file ID from whatever you gave it, a URL or an ID.

Step 1 - read file details and derive client context.

It calls get_file_details with fields including path_collection. The path is the source of truth for client attribution, not the image content. The convention:

All Files / PRODUCTION / {CLIENT} / {PROJECT} / assets / {community} / file

It maps that as: Client is the folder directly under PRODUCTION (e.g. ATLANTIC BUILDERS). Project is the next folder down (e.g. ATL 144 - 2025 Parade of Main Level Living Carousels). Community is a community-named folder deeper in the path when present (e.g. whitehall reserve), which for MPC clients often matches a recognizable community. It normalizes casing for readability - title-casing the client and community, but keeping project codes and names verbatim. If the path doesn't match the convention it does not force-fit: it states which folder it's treating as the client, flags that as an inference, and either proceeds or asks if genuinely ambiguous.

Step 2 - describe the asset's content.

It tries get_preview_page(fileId, 1) first so it's looking at the actual pixels. If that returns a processing error (common for some image types), it falls back to ai_qa_single_file with a prompt asking for a detailed description of everything visible: subjects, text, colors, layout, notable elements. It produces a short content descriptor as a phrase.

Steps 3–5.

Build the metadata (description, tags, and a structured metadata template instance if one exists for that scope), write it back to the file, and report back. Batch mode does the same across a folder.

box-image-selectorSlots-first image selection from the canonical approved set, rendered in chat.

Read first: what the Box connector can and cannot do.

The skill opens with the connector's actual capabilities and limits, which is what prevents the common failure of assuming search returns everything.

Steps.

1 - list the image slots the deliverable needs. Enumerate the requirement before searching, so selection is driven by what the piece needs rather than by whatever the search happened to surface. 2. Search Box for candidates. 3 - find the canonical approved set, then enumerate it. Rather than trusting search recall, it locates the approved folder and lists what's actually in it. 4. Select the right file per slot, applying any client-specific rules. 5. Render each chosen image in chat so you can see it before it goes anywhere. 6. Report the selection so it's reusable next time. Separate path for embedding the bytes into a docx, pptx, pdf, or build when the deliverable is a file rather than chat.

brand-negative-keyword-auditFinds competitor-brand search terms and classifies each before excluding.

Steps.

1. Pull search term data from Windsor.ai. 2. Extract brand and company-name terms from the search terms. 3 - classify each brand: the step that makes it more than a string match. For each extracted brand it checks: is this actually a home builder, does it compete in the client's markets, and for out-of-area builders, how far is it from the client's nearest community. 4. Deduplicate for phrase match, so the list is paste-ready rather than full of overlapping variants. 5 - produce three outputs: (A) the analysis, in conversation; (B) a paste-ready phrase match list, in conversation; (C) an Excel export. Closes with a summary of the key decision rules, the Windsor.ai mechanics, and notes on scope.