SwarmSystem Playbook
Search Console problems, fixed and proven
Google already tells you when something on your site is broken. Most teams hear about it from a forwarded email, fix it by feel, and never find out whether the fix worked.
This is how we let an AI agent find the problem, fix it, and prove it fixed, with one person saying yes before anything goes live. The skill and the script are free to download at the end.
The email tells you late, secondhand, and never tells you it worked.
The usual setup: Search Console sends an email, a Zap forwards it into a Slack channel, and somebody on the team eventually looks at it.
We ran it that way for months. Reading back through 200 of those Slack messages, three things stood out.
- The email arrives days after Google noticed. It's a summary of a report, not the report.
- It names a problem type, not the page. "Review snippets issue detected" sends you digging in Search Console to find which URLs.
- "Some fixes failed" showed up 12 times. Somebody clicked "Validate fix," Google checked, and the fix hadn't held. Nobody had checked the live page first.
About half the real alerts were structured data (the hidden code that tells Google about your reviews, services and business). About a third were pages Google wasn't indexing. The rest was noise.
The rule
Ask Google directly at both ends. Google is the only one who can say a problem exists, and the only one who can say it's gone.
Everything in the middle, finding the cause, fixing it, checking the live page, is work an agent can do. The alarm and the proof both come from Google, never from an email about Google.
A skill and one scheduled script. Not an agent that runs all day.
This was the first question we had to answer, and the answer is smaller than most people expect.
| Job | Who does it | How |
|---|---|---|
| Notice a problem | A script, once a day | Asks Google about every page in the sitemap and keeps a list of problems |
| Find and fix the cause | An AI agent | Follows the skill: reads the live page, finds the template, makes the fix |
| Say yes to the deploy | A person | Reads the change, says yes in the session |
| Confirm it's fixed | The same script | Waits for Google to crawl the page again and stop reporting it |
A skill is a written runbook the agent loads when the job comes up. It carries the steps and the traps. A scheduled script is cheap, it can't make things up, and it runs whether or not anybody opens a laptop. An always-on agent would do the script's job at a hundred times the cost and add a new way to fail.
What Google will tell a program, and what it won't.
Google has an API for Search Console. It doesn't cover everything the website shows you, and knowing the gap up front saves a day.
| You want | API? | What to use |
|---|---|---|
| Is this page indexed, and when did Google last crawl it? | Yes | URL Inspection, one page per call |
| Structured data errors on this page | Yes | URL Inspection returns them with the exact message |
| Which sitemaps are registered, and do they have errors? | Yes | Sitemaps list |
| Ask Google to come back | Yes | Resubmit the sitemap |
| The issue list from the Page indexing and Enhancements reports | No | Inspect every sitemap URL and build the list yourself |
| The "Validate fix" button | No | Optional, by hand. The re-inspection is the proof. |
URL Inspection allows 2,000 checks per site per day. A home service site has a few dozen to a few hundred pages, so checking every page every day costs nothing. Our first four sites came to 71 pages in total.
Sort "broken" from "not yet" before you touch anything.
Search Console mixes two very different things into one report. Treat them the same and your agent will spend its time "fixing" pages that aren't broken.
Broken: fix these
Structured data errors. A page telling Google not to index it by mistake. A page Google couldn't load. A 404 or redirect error on a page that's in your sitemap. These are faults in the site, and a change to the site fixes them.
Not yet: report these, don't "fix" them
"Discovered, currently not indexed." "Crawled, currently not indexed." "URL is unknown to Google." On a new or small site these mostly mean Google hasn't gotten around to it. Good internal links and a clean sitemap help. Rewriting the page because Google is slow doesn't.
On the first site we ran this on, 8 of 12 pages were in the "not yet" group. Four had a real error. Without the sort, the list would have looked three times worse than it was.
The first run found a problem the source files didn't have.
The first site was a small vacation rental site we built and host. The daily sweep came back with one error on four pages:
Review snippets: Invalid object type for field "<parent_node>"
/ /about/ /things-to-do/ /homes/…
In plain English: the page tells Google "this has a 5-star rating," but it attaches the rating to a kind of thing Google doesn't show stars for. Google only accepts ratings on certain types, like a local business, a product or an event. This site had put the rating on "Accommodation," which isn't one of them.
The home service version of the same mistake is common: star ratings attached to a Service block ("Water heater repair, 4.9 stars"). Google won't show stars for that either. Put the rating on the business itself (Plumber or LocalBusiness) and it qualifies.
Check the page Google saw, not the file you edited
Here is the part that surprised us. We ran the checker on the site's source files and it found nothing wrong. We ran it on the live page and it found the error right away. The ratings code was added by a build step at deploy time, so it never existed in the files anybody would open.
If a team had "fixed" this by reading the source, they'd have found nothing, clicked Validate fix, and gotten a "Some fixes failed" email a week later. That's where our 12 failures came from.
What the real run taught us
We ran the whole loop on that site before publishing this page, from the first sweep to the live deploy. Five things came out of it that the first draft of this playbook didn't have.
- Google names the exact item that failed. Its answer listed four ratings on the page: the business passed, and the three homes each failed. That one line pointed straight at the cause. The script now saves those names and puts them in the Slack message.
- Google's count is the pages it has crawled, not the pages with the problem. Search Console said four pages. The checker ran on the built site found the same error on 12 of 13. Fix what the build shows, not only what the report lists.
- Sometimes the correct fix is to remove it. There is no type Google accepts for a rating on a single rental unit. So the three unit ratings came out, the business rating stayed, and each home's rating stayed as text on its page. We said that plainly in the change, because removing markup should never be the quiet default.
- Prove the fix is the only thing that ships. A deploy sends the whole site, not one line. We built the site before and after the fix, compared both to the live pages, and confirmed the only difference was the three ratings. That check is now part of step 5.
- Google changes its mind about pages it hasn't crawled. One day a page is "Discovered," the next it is "unknown to Google." The first version of the script logged each change as a new item. It now closes the old one, so the "not yet" list stays honest.
The ten steps.
This is the loop the skill walks an agent through. Steps 1 to 5 need no permission. Step 6 is the only place a person comes in.
- Read the problem from Google. Run the sweep, then inspect the page. Every problem gets an ID, and that ID follows it to the end.
- Sort it. Broken or not yet. Only broken moves on.
- Find the cause on the live page. Fetch it, read the structured data and head tags, read Google's own doc for that error type.
- Fix it once, where it's made. The same error on four pages is almost always one template or one build step. Fix it there, not four times.
- Prove it locally. The checker runs on the built site and has to pass. Then build the site with and without the fix and compare both to the live pages. The fix should be the only difference.
- Stop and ask. Show the person the change, the pages it touches, and one sentence on what was wrong. Wait for a yes.
- Deploy the way that site always deploys.
- Prove it shipped. Run the checker on the live page again. Then mark the problem deployed, which also asks Google to come back.
- Optional: click "Validate fix." It clears the report in Search Console sooner. It's not the proof.
- Let the daily sweep close it. When Google crawls the page again and the error is gone, it's confirmed, with the dates posted.
The one human step is a yes before anything ships.
The agent can do everything except decide that a change goes live on somebody's business website. That stays with a person, once per fix.
- The yes happens in the working session, where the person can see the change. A thumbs up on a Slack message is a reason to open a session, not an approval.
- The script enforces it. It won't let a problem be marked deployed until it has been marked approved. An agent that skips the step gets an error, not a shortcut.
- Nothing deploys overnight. The schedule only reads from Google. It never changes a site.
Confirmed means Google crawled it after the fix and stopped complaining.
Both halves matter. A clean inspection from a crawl that happened before the deploy proves nothing, because Google was looking at the old page. So the script compares Google's last crawl time with the time the fix went live, and only confirms when the crawl is newer and the error is gone.
If Google crawls again and still sees the error, the problem goes to failed and back to step 3. If a confirmed problem comes back months later, it reopens as regressed with its original history.
foundapproveddeployedconfirmedfailedregressed
What the team sees
Three short messages per problem. Site name first, plain words, dates. Nothing posts on a day when nothing changed.
Day 1, found (the real message)
example.com: Google reports a problem on 4 pages
Review snippets: Invalid object type for field "<parent_node>"
Google flagged: the whole house; the upper home; the lower home
Found September 25, 2026. A fix needs your OK before it ships.
Same day, after the yes (the real message)
example.com: fix deployed, waiting on Google
Invalid object type for field "<parent_node>" on 4 pages
Deployed September 25, 2026 after your OK. Sitemaps resubmitted so Google comes back sooner.
When Google crawls again (example dates until ours arrives)
example.com: fixed and confirmed by Google
Invalid object type for field "<parent_node>" on 4 pages
Found September 25, 2026, fixed September 25, 2026, Google re-crawled September 29, 2026 and no longer reports it (4 days after the fix).
That last line is the one the client cares about: what was wrong, when it was fixed, and when Google agreed. It's also a clean record for a monthly report.
Download the kit.
Two files. A skill for Claude Code (or any agent that reads a runbook) and one script with no dependencies. We ran it against a live site before publishing this page: it found the four pages above, grouped them into one message, stayed quiet on the second run, refused to mark a fix deployed without an approval, and then took the real fix through to deployed.
Set it up in about fifteen minutes
- Unzip into
.claude/skills/gsc-self-heal/in your project. You need Node 18 or newer. - In Google Cloud, turn on the Search Console API and make an OAuth client. Get a refresh token for the scope
webmasterswith Google's OAuth Playground. SKILL.md walks through it. - Put the three values in a
.envfile. For Slack, a bot token and a channel ID are the safer choice: a webhook only ever posts to the one channel it was made for, and ours turned out to point somewhere else. - Check it works, then record what's already wrong without posting it:
node gsc-check.mjs --selftest
node gsc-check.mjs sites
node gsc-check.mjs sweep sc-domain:example.com --baseline
Then schedule the sweep once a day, set to run late if the computer was off at that hour. From there, when a problem posts, open your agent and say "use the gsc-self-heal skill on this."
node gsc-check.mjs sweep sc-domain:example.com # daily
node gsc-check.mjs inspect sc-domain:example.com https://example.com/page/
node gsc-check.mjs lint ./dist # before you deploy
node gsc-check.mjs lint https://example.com/page/ # after you deploy
node gsc-check.mjs mark <id,id> approved # after the person says yes
node gsc-check.mjs mark <id,id> deployed # after the live check passes
The stop doing list.
- Stop treating the email as the report. Ask Google for the page-level truth.
- Stop fixing from the source file alone. Check the page Google actually sees.
- Stop fixing the same error page by page. Find the template.
- Stop "fixing" pages that are just waiting on Google. Report them and move on.
- Stop calling it done when you click Validate. It's done when Google crawls the page again and agrees with you.
- Stop letting anything deploy without a person's yes. Speed is the agent's job. Judgment isn't.
What we don't know yet.
This is version one, written the day the kit first ran on a live site. The first fix was found, approved and deployed on September 25, 2026, and every live page passed the checker afterward. What hasn't happened yet is Google crawling those pages again. When it does, the real confirmation date replaces the example above, and if something in the loop doesn't hold up, this section is what changes.
The checker covers one rule today: ratings on a type Google doesn't accept, the most common structured data error we've seen. It will grow as new errors show up. Google can take anywhere from a day to a few weeks to crawl a page again, so how long "confirmed" takes depends on the site, not on the agent.