fix-seo
Fix the SEO problem Loomaly ranks first on a site, in this repository: get the fix-first queue, read the evidence and fix prompt, change the code on a branch, mark it fixed with the PR link, and re-ch
SKILL.mdplugins/loomaly/loomaly/skills/fix-seo/SKILL.md
GitHubFix what Loomaly ranks first
Use this when the user wants to fix their site's SEO, work through Loomaly issues, or asks "what should I fix first". Run it from inside the site's repository.
Tools (Loomaly MCP)
get_started(optionaldomain): call this first. If the account has no site and you passdomain, it adds the site and starts the first scan. IfneedsSiteis true and there is no domain yet, find one and calladd_site.sites_list: the sites this account can see, withid,domain,healthScoreandscan.phase. Every other tool needs a siteid. An empty account returnsneedsSite.add_site(domain, optionalpath,language): adds a site and starts its first scan. The homepage must resolve and answer first; otherwise the error issite_unreachableand no site is created. Returnspollso you can watchsites_listuntilscan.phaseisdoneorfailed. A failed scan whose homepage could not be fetched has no health score (scan.failureiserrored).fix_first(siteId,limit): this week'sweeklyPlan, thenmore(the rest of the queue). There is noissuesfield.weeklyPlanis the week's snapshot: 1 item on Free (the rest isupgrade_required), 5 on Starter and up. On Pro and Agency up to two of those five can be Search Console opportunities. Each item haswhy,status(todo,marked_fixed,verified) andnextStep. An item withopportunityis not a finding to patch first: ask the owner, thenset_focus_pagefor that page, then change the title, description or a section so it earns the clicks it is already shown for. A finding item'snextStepisfix_prompt, thenmark_fixedwith the PR URL, thenverifyafter deploy.moreentries arekind: "finding"(one per rule by default), withaffectedPages,templates,templatePages(pages per pattern, the same count asfix_prompt),sampleUrl(the page ofsampleFindingId),lastSeenAt,reasonandnextStep.limitapplies tomore(default 10). A shared version across languages is one template such as/*/2.0.0.opportunities(eachkind: "opportunity") andopportunityCountare Search Console opportunities on Pro and Agency (almost page one, low click-through, or falling clicks). Other plans getopportunityCountandopportunitiesUpgrade, not the rows. Set one as the focus page only after the owner agrees. A free plan shows one GEO finding (llms.txt and AI crawler rules). When more are open,geocounts them and includes the upgrade sentence.by: "template"returnsgroupsinstead ofmore.findings_list(siteId,severity,state,ruleId,pathTemplate,url,cursor): findings (one per page) with IDs, forfix_promptandverify. The result includestotal,findingsTotal(the same count) andnextCursor. Passcursor: nextCursoruntilnextCursoris null; the first page is not the whole list. Problems (one per rule) aresites_list'sproblemCount, not this total.fix_prompt(findingId): the rule, the evidence anddevPrompt, an instruction written for the site's framework.templatesays how many pages of the same template have the problem.mark_fixed(siteIdplusfindingId, orsiteIdplusruleIdandpathTemplateorallPages: true;ref,note): moves the problem to pending verification. It does not use a fix check and does not re-read the page.verify(findingId, orsiteId+ruleId+pathTemplatewith alimit), thenverify_status(auditRunId+findingId, orruns): re-checks live pages. Each page uses one fix check; a group call re-checks up tolimitpages (default 1 when fix checks reset monthly, otherwise 5). The result includesquota.usedandcostNote. Only after the fix is deployed. It does not use a monthly in-depth page. A re-check that cannot start is not counted. At most 5 scans or re-checks start in any rolling 60 seconds;rate_limitedincludesretryAfterseconds.still-openincludesevidenceandnextStep.rescan_siteis not blocked by those re-checks; its success includesquota. A full site slot returnsupgrade_required; a domain that does not resolve issite_unreachableeven then.ignore_finding(siteId, a target as formark_fixed,reason): for a finding the user says is not a problem for their site.precheck(siteId,url): Pro and Agency. Read a preview or temporary deploy URL and compare it with the same path on the live site. Returns what that page would add and which open issues it would clear. It does not change the site's findings. A previewnoindexis normal. HTTP 401 or 403 means the preview is password protected, not a list of issues. Each call uses one fix check (the same allowance asverify); the result includesquotaandcostNote. Free getsupgrade_required. A paid plan without the feature gets a sentence and no billing link.
If the tools aren't available, tell the user to connect Loomaly (claude mcp add --transport http loomaly https://loomaly.com/mcp) and stop.
Steps
get_started. IfneedsSiteis true, find the domain in this repository before asking the user:package.jsonhomepage, the README, a canonical URL, the production URL in config, or a URL the user already gave you. IfsuggestedDomainis set, use that. Calladd_site(orget_startedagain withdomain) in this turn. Only ask when you cannot find a domain. The call starts the first scan. Pollsites_listuntilscan.phaseisdoneorfailed(5–20 minutes). While it isfinding_pagesorchecking_pages, say the scan is running, not that the site is clean. If more than one site matches the repository, ask which one; don't guess.fix_first. IfneedsBriefis true, ask the owner once about the audience, the goal and the keywords, thenset_brief. Do not invent the brief. IfgscSetupis present, callgsc_verify_site. The owner authorizes Google in Loomaly and does not open Search Console. Ifstatusisnot_connectedorreconsent_required, send them toconnectUrl(reconsent only adds site verification). Ifstatusisneeds_tag, addmetaTagto the homepage<head>in server-rendered HTML, leave the tag in place, open a pull request, and after deploy callgsc_verify_sitewithdeployedtrue. That verifies the site and submits the sitemap. WorkweeklyPlan.itemswhosestatusistodo, in order. Foundation items (sitemap, robots, Search Console, homepage, server rendering) come before ordinary findings. A sitemap fix generates the file from the route or content source. After that fix is verified and Search Console is connected, callsubmit_sitemap. Tell the user the first item in one sentence: what it is, andwhy. For a finding, say how many pages. For anopportunity, ask beforeset_focus_page. Say what you'll change before you change it.moreis the rest of the queue, after this week's items.fix_promptwith the finding'ssampleFindingId(frommore) or the weekly item'sfindingId. IflastSeenAtis older than the last deploy, check the live page first: it may already be fixed. Readevidencebefore the prompt: fix what the evidence shows, not what the rule's name suggests. Skipfix_promptwhen the weekly item is only an opportunity and the page has no open finding.- Find where the problem comes from in this repository. Prefer the shared layout, template or component over editing pages one by one:
affectedPagestells you whether it's a template-wide fix. - Make the change on a new branch, run the project's own checks and tests, and open a PR. Don't push to the main branch. On Pro or Agency, once the PR has a preview URL,
precheckthat URL before merge and tell the user what it would add or clear. A password-protected preview is not a failed fix. mark_fixedwithsiteId,ruleIdand thepathTemplateyou fixed (orallPages: truefor a layout-wide change),refset to the PR URL and a one-sentencenote. This does not use a fix check. An opportunity is not marked fixed this way:set_focus_pageafter the owner agrees, thenlog_changeonce the change is deployed.- Tell the user the problem stays pending until a re-check. An unverified site has no weekly re-scan, so do not wait for one. Once they say it's deployed,
verifyone finding, or the group (ruleId+pathTemplate) with alimitthe owner is willing to spend (each page is one fix check; monthly plans default to 1). Pollverify_statusevery 20–30 seconds untilfinished. RelaycostNote. Report the verdict:fixed,still-open(readevidencefor what was still measured, then follownextStep), orcheck-failed(the page couldn't be loaded; not a verdict on the fix). Oncheck-failed, sayfailure(page_quota_exhausted,fetch_failedwithstatus,fetch_timeout,fetch_network,start_failed). FollownextStepfor pages the call did not re-check: it only mentionsrescan_sitewhen a manual rescan is left.
Don't
- Don't mark something fixed before the change is merged.
- Don't call
verifyon a branch that isn't deployed: it reads the live page. - Don't fix a problem the evidence doesn't support. If the evidence contradicts the rule (the page already has the tag it says is missing), say so instead of editing, and offer to
ignore_findingit with that reason. - Don't ignore a finding without the user's say-so.