`app.motir.co/robots.txt` 404s — motir-core ships a sitemap, JSON-LD and canonicals on its public surface but no `app/robots.ts`
Type: code · Executor: coding_agent · Repo: motir-core
Found while working MOTIR-1155 (8.3.8, Search Console setup), 2026-08-27.
https://app.motir.co/robots.txt returns 404 (text/html, Next.js' not-found page — measured with a Googlebot UA). motir-core has no app/robots.ts, while the rest of the public-surface SEO scaffolding did ship under 6.13/8.9.4: app/sitemap.ts (10 URLs), per-project + explore JSON-LD, canonicals, section OG images.
Severity is low, and the honest reason matters: an absent robots.txt reads as allow everything, so nothing is blocked or de-indexed today, and sitemap discovery is already solved a better way — the sitemap is submitted directly to the verified Search Console property (MOTIR-1155). This is crawl hygiene ahead of going public, not a live defect.
What is actually missing is the ability to say don't crawl this: /api/*, the auth routes, and the ?rank= facet URLs (/explore?rank=popular, /explore?rank=recent) which are duplicate views of /explore and currently sit in the sitemap as separate <loc>s.
Scope
- Add
app/robots.ts(Next.jsMetadataRoute.Robots) — allow crawl,sitemap:→https://app.motir.co/sitemap.xml,hostset. - Disallow:
/api/,/sign-in,/sign-up, and the other authed-only route groups that currently return a redirect to sign-in. - Decide the
?rank=facets deliberately — either drop them fromapp/sitemap.tsin favour of the canonical/explore, or leave them and let the existing canonical tags do the de-duplication. Don't do both half-way. - Build the URLs from the same base the sitemap uses; no second hardcoded host. (
metadataBasewas the subject of MOTIR-2505 — reuse it, don't reintroduce a literal.)
⚠️ This card creates the file, ONE host at a time. It ships the app host's directives against today's single origin; making the same route answer by host is MOTIR-3881's work, not this card's. Do not anticipate the second host here — a robots.ts that branches on a hostname nothing yet serves is untestable and pre-empts the ADR (MOTIR-3879) that decides which host answers for what.
Acceptance criteria
https://app.motir.co/robots.txtreturns200 text/plainwith aSitemap:line pointing at the live sitemap.- The disallow set covers
/api/and the auth routes;/exploreand/p/*remain crawlable. - A test asserts the route renders and that
/exploreis NOT disallowed — the failure mode of a robots file is silently de-indexing the surface it was meant to help, so guard the ALLOW, not just the deny. - The
?rank=facet decision is recorded on this card, not left implicit.
Context refs
app/sitemap.ts(motir-core) — the existing, shipped sitemap this must reference- MOTIR-1154 (8.3.7) plans a
robots.tsfor motir-marketing — a different repo, a different file; that card is not widened to cover this one - MOTIR-2505 —
metadataBase; the base-URL source of truth - blocks MOTIR-1130 (8.10.3, smoke the public surfaces) — going public is where this bites
- blocks MOTIR-3881 — the card that makes this file host-aware once
motir.cois served by motir-core
⚠️ Where this card lives, and why it moved (2026-08-29)
Authored under 8.10, re-parented to MOTIR-3876 — beside MOTIR-3881, the card it gates. A prerequisite takes the SAME parent as the gated card and the blocked_by edge is the whole relationship; left under 8.10 the edge crossed a story boundary and made MOTIR-3876 un-finishable (validate_work_item returned valid: false naming exactly this edge). The MOTIR-1130 edge is unchanged and now points backward into an earlier story, which is the legal direction.