---
title: "Recce Documentation Site"
description: "Case study: contributing to docs.reccehq.com on MkDocs Material. Resilient gh-deploy retry loop, accessibility-as-infrastructure with .md mirrors and JSON-LD, llms-full.txt optimization, and a numbered-to-flat namespace migration without a single 404."
doc_version: 1
last_updated: 2026-05-24
canonical: https://variable.team/projects/recce-docs
---

<!--
  Source of truth: app/projects/recce-docs/page.tsx. Keep the h1 in sync.
  scripts/check-markdown-drift.ts verifies this in pre-commit.
-->

# Recce Docs

- **Company:** [Recce](https://reccehq.com)
- **Industry:** Data Engineering / Analytics Engineering
- **Dates:** Apr 2025 to Present
- **Project link:** <https://docs.reccehq.com>
- **Stack:** MkDocs, Material for MkDocs, Python, Markdown, Sass, GitHub
  Actions, GitHub Pages

### A retry loop for gh-deploy's transient 500s

The docs site deploys via mkdocs gh-deploy, which occasionally hits a
transient GitHub 500. Before, that meant a manual rerun or a noisy
escalation in Slack. I wrapped the deploy step in a 3-attempt loop with
exponential backoff and set the DISABLE_MKDOCS_2_WARNING environment
variable to keep the output clean. Transient failures now self-heal in CI
without any operator involvement.

### Accessibility treated as infrastructure

Most docs sites treat a11y as a polish pass. Recce treats it as ongoing
infrastructure. I added an AGENTS.md config for AI consumers, JSON-LD
TechArticle metadata on every page, .md mirrors so agents can fetch a
canonical text version of any URL, and the glossary wired into the nav.
The a14y score moved out of the mid-60s and into the 90s without the
surface coverage going narrow.

### Optimizing the LLM-friendly export

The site emits an llms-full.txt that concatenates the full docs for AI
agents. Material's default selector pulled in sidebar navigation and theme
chrome, which inflated the file to 216KB of mostly-useless content. I
switched to the md-content__inner selector and used Python's stdlib
html.unescape for entity decoding. The export dropped to 162KB, and the
content stayed useful for Claude plugins and MCP agents.

### A namespace migration that doesn't break links

The docs moved from numbered top-level sections (2-getting-started/) to
flat namespaces (getting-started/) for cleaner URLs. The catch was that
internal references, blog post links, and customer bookmarks all pointed
at the old paths. I built redirect maps for the mkdocs redirects plugin so
every old URL still resolves, and shipped the restructuring under DRC-1868
without a single 404.

## Sitemap

[Full site index](/sitemap.md)
