What the agent does
The agent clones the repository into its own sandbox, installs with the lockfile, and builds the site, because an SEO audit of an Astro project is an audit of the HTML the build emits, not of the source alone. In a site built on arthelokyo/astrowind, astro.config.ts sets output: 'static' with the sitemap, mdx, icon and compress integrations, .nvmrc pins Node 22, and the build script is astro build. The agent runs npm ci, npm run build, serves dist/ with astro preview, and crawls every page the sitemap lists, keeping the response for each.
Then it reads where the metadata comes from, so each finding points at a file and not at a URL. In AstroWind that is src/config.yaml, which sets site, base, trailingSlash: false, the default title template %s — AstroWind, the description, robots.index and follow, the Open Graph image at 1200 by 628 and the Twitter card type; src/components/common/Metadata.astro, which merges those defaults with each page's props and renders them through astro-seo, computing the canonical from getCanonical in src/utils/permalinks.ts; and src/layouts/Layout.astro, which sets <html lang> from the i18n block and places Metadata, SiteVerification, Analytics and the ClientRouter in the head. The blog post page under src/pages/[...blog]/index.astro adds StructuredData and Breadcrumbs, and src/pages/rss.xml.ts builds the feed from the content collection.
The crawl checks each page against what those files promise. It compares every <title> and description for length and duplication across pages, confirms the canonical matches the final URL including the trailingSlash rule, checks that robots meta on tag pages reflects index: false from the blog.tag block of config.yaml while category pages stay indexable, reads public/robots.txt, which allows everything and names no sitemap, and verifies sitemap-index.xml lists the pages that exist and none that return 404. It validates the JSON-LD the blog pages emit, checks every image for alt and the Open Graph image for an absolute URL, and reads the <html lang> value. Headings are checked for one h1 per page, and internal links for redirects and dead targets.
What it finds is written against the source. A description over the length that search results show is traced to the metadata.description string in config.yaml or to the page's own metadata prop; a missing Sitemap: line to public/robots.txt; a tag page that is indexable when the config says otherwise to blogPostRobots in src/utils/blog.ts. It changes no file and opens no pull request.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Audit this Astro site for technical SEO and write seo-audit.md. Install with the lockfile, run the production build, serve the output and crawl every page the generated sitemap lists, keeping each response. Read the site config, the metadata component, the layouts and the robots and sitemap sources so every finding names the file and line that produces it. Check titles and descriptions for length and duplicates, canonical URLs against the trailing-slash rule, robots meta and robots.txt, the sitemap for missing or dead entries, structured data validity, Open Graph and Twitter tags with absolute image URLs, html lang, one h1 per page, image alt text, and internal links that redirect or 404. For each issue write the pages affected, the file and line, and the fix, ordered by impact. Do not invent issues the crawl did not show. Change no code and open no pull request.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
- Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
- Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.
What comes back
seo-audit.md comes back as an artifact on the session, with a download link good for an hour that reading the session again renews. It opens with how the site was built and crawled: the Node version, the install and build commands, the number of pages the sitemap listed and the number crawled, so the reader knows the scope. Then come the findings, ordered by impact, each with the pages affected, the file:line that renders the tag, the value the crawl saw, and the fix.
A second section lists what was checked and found correct, with the file that makes it so, such as canonicals that match the trailingSlash: false rule from config.yaml or the JSON-LD on blog posts that validated. A third lists the checks that need a live domain and were not run, such as crawl budget, Core Web Vitals field data, or whether the deployed robots.txt differs from the one in public/.
A reviewer opens the file beside the report, confirms the line produces the tag the crawl saw, and fixes the ones that matter. The clone is clean: no commit, no pull request, no edited file. The transcript keeps the build output and every crawled response.
Run it on every weekly build
In the console, add an automation to the Project with this prompt and a schedule trigger, with cron set to a weekly hour in your timezone; each run builds the current default branch and returns a fresh seo-audit.md as its artifact. A GitHub trigger on pull_request.opened does the same per pull request so a change to config.yaml or a layout gets audited before it merges, with the event added after the prompt.
From your own server, POST /o/{org}/sessions with this prompt and the repository in resources starts one on demand, and a webhook_url on the key POSTs run.completed with the session_url to fetch the report from.
The use case this job follows, with its automation and trigger: Produce a report or file, no repo.
Why run it on Rush?
An SEO checklist applied to source files guesses what the build will emit; Astro's metadata goes through a config file, a merge in a component and a layout before it becomes a tag. The sandbox builds the site, serves it and crawls the real HTML, so every finding is something a search engine would see, and every finding names the line that caused it.
The result is a file with citations, not a tool's dashboard. A developer fixes config.yaml or Metadata.astro with the report open, and the next scheduled run shows the finding gone. Nothing in the repository changes unless someone asks for a pull request in a follow-up.
Frequently asked questions
Will it edit the metadata or open a pull request?
No. The prompt forbids changing code, and the report is a session artifact. If you want fixes, reply to the same session with a follow-up asking for a pull request, and the agent applies the report's fixes in the same sandbox with the build still there.
Does it need my production domain?
No. The crawl runs against the build served in the sandbox, with the site value from the config used for canonicals and the sitemap. Checks that only a live domain can answer, such as field performance data or what the deployed robots.txt serves, are listed as not run.
My site uses server rendering or a hybrid output. Does the crawl still work?
Yes. The agent reads output in astro.config and, for server or hybrid, starts the adapter's server in the sandbox and crawls the same routes. The sitemap integration still emits the list of static routes; dynamic routes are crawled by following internal links.
Does it check the RSS feed and structured data?
Yes. It requests rss.xml, checks it parses and that its links resolve, and validates every JSON-LD block the pages emit. In AstroWind the feed comes from src/pages/rss.xml.ts and the structured data from the StructuredData component on blog posts, and the report names both.