diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 18240ba..55609fa 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,4 +16,24 @@ jobs:
- name: Contract tests
run: npm test
- name: Link check
- run: node Scripts/check-markdown-links.js
\ No newline at end of file
+ run: node Scripts/check-markdown-links.js
+
+ # Validate that the GitHub Pages site builds without warnings on every
+ # push/PR. `mkdocs build --strict` fails on any broken link or warning, so
+ # this is the site-validation gate; the deploy workflow (deploy-site.yml)
+ # reuses the same steps on main.
+ docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ - name: Install site build deps
+ run: pip install -r requirements.txt
+ - name: Assemble site source
+ run: node Scripts/assemble-site-source.js
+ - name: Build site (strict)
+ run: mkdocs build --strict
+ - name: Generate llms.txt files
+ run: node Scripts/generate-llms.js
\ No newline at end of file
diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml
new file mode 100644
index 0000000..8a8d5c0
--- /dev/null
+++ b/.github/workflows/deploy-site.yml
@@ -0,0 +1,63 @@
+name: Deploy documentation site
+
+# Builds the MkDocs site (plus robots.txt, sitemap.xml, llms.txt and
+# llms-full.txt) and publishes it to GitHub Pages. Runs on pushes to main and
+# can be triggered manually after enabling Pages with `build_type=workflow`.
+#
+# Site source of truth: the repository's own markdown, staged into a gitignored
+# docs/ by Scripts/assemble-site-source.js (MkDocs requires docs_dir to be a
+# child directory). The repo root remains the single source of truth; this
+# workflow is the only place the site is assembled and deployed.
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+
+# Pages deployments must use the built-in pages token with this exact set.
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Configure Pages
+ id: pages
+ uses: actions/configure-pages@v5
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+
+ - name: Install site build deps
+ run: pip install -r requirements.txt
+
+ - name: Assemble site source
+ run: node Scripts/assemble-site-source.js
+
+ - name: Build site (strict)
+ run: mkdocs build --strict
+
+ - name: Generate llms.txt files
+ run: node Scripts/generate-llms.js
+
+ - name: Upload Pages artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: site
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index d4a76cf..818f980 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,7 @@
# Node
node_modules/
npm-debug.log*
+
+# Generated docs site staging + output (built by CI; see mkdocs.yml)
+docs/
+site/
diff --git a/README.md b/README.md
index 86ed239..87c3a81 100644
--- a/README.md
+++ b/README.md
@@ -3,17 +3,20 @@
**AI Engineering Lab** is a personal research and development space for
understanding AI engineering systems, developer tooling, LLM infrastructure,
-observability, and workflow automation. It exists to document work as it
-happens — how each project is investigated, verified, and built — and to keep
-that record with the finished result. The **Provider-Aware Statusline** is the
-lab's first public flagship project: a statusline for Claude Code behind the
-OmniRoute routing gateway that shows which provider actually answered your
-request. The research, findings, architecture, and ADRs in this repository are
-the trail of how that project was investigated and built, kept alongside the
-code rather than hidden away. See [Origin-Story.md](Origin-Story.md) for how
-the lab started and why this project exists.
-
-[](LICENSE) [](Statusline/test/statusline.test.js) [](package.json) [](package.json)
+observability, and workflow automation. Its flagship project, the
+**Provider-Aware Statusline**, is a statusline for Claude Code behind the
+OmniRoute LLM routing gateway that shows which provider and model actually
+served your request. This repository keeps the evidence-first trail of how that
+project was investigated and built — research, findings, architecture, and
+ADRs — alongside the code, rather than hidden away. See
+[Origin-Story.md](Origin-Story.md) for how the lab started and why this project
+exists.
+
+**Hosted documentation (for humans and AI agents):**
+[unscriptedbykramy.github.io/AI-Engineering-Lab](https://unscriptedbykramy.github.io/AI-Engineering-Lab/)
+— rendered docs, full-text for AI agents (`llms.txt`), and search.
+
+[](LICENSE) [](https://github.com/UnscriptedByKraMy/AI-Engineering-Lab/blob/main/Statusline/test/statusline.test.js) [](package.json) [](package.json)
@@ -39,6 +42,38 @@ The current implementation targets Claude Code behind OmniRoute, but the underly
- **Degrades gracefully** — on every failure path it falls back to model-only or the
requested label; it never crashes, never guesses, and never leaks tokens or prompts.
+## FAQ
+
+**Which provider/model actually served my request?**
+The statusline shows the resolved route from the session transcript — e.g.
+`opencode/big-pickle` — not the requested label. `auto/cheap` is what you asked
+for; `opencode/big-pickle` is what answered.
+
+**How does the statusline know which model answered?**
+It reads the last assistant message's `model` field from the local session
+transcript (JSONL) and resolves the provider and real context window from a
+local empirical mapping. It is a reader, not an inferrer — see
+[Architecture.md](Architecture.md) for the verified data flow.
+
+**Does it read my prompts or tokens?**
+Never. It reads only the session transcript and a local mapping file — no
+tokens, prompts, request bodies, or gateway credentials. It never writes
+anything and never makes network requests.
+
+**Do I need OmniRoute or Docker?**
+No for the statusline itself: it only reads local files and works without a
+gateway (it then omits the provider). Docker is needed only for the optional
+out-of-band mapping-refresh script.
+
+**What is AI Engineering Lab?**
+The evidence-first research and development space this repository documents.
+See [Origin-Story.md](Origin-Story.md) for how it started.
+
+**Where is the hosted documentation?**
+The rendered docs site:
+[unscriptedbykramy.github.io/AI-Engineering-Lab](https://unscriptedbykramy.github.io/AI-Engineering-Lab/)
+— with full text for AI agents via [`llms.txt`](https://unscriptedbykramy.github.io/AI-Engineering-Lab/llms.txt).
+
## Try it in three steps
1. **Clone** this repository.
@@ -190,6 +225,7 @@ tools couldn't answer it, and how it became a reusable tool.
| Path | Purpose |
|---|---|
| `README.md` | Project overview and operating principles |
+| **Hosted site** | Rendered documentation, search, and full text for AI agents (`llms.txt`) at [unscriptedbykramy.github.io/AI-Engineering-Lab](https://unscriptedbykramy.github.io/AI-Engineering-Lab/) |
| `Origin-Story.md` | How this project started and why it exists |
| `Roadmap.md` | Phases, gates, deliverables, and next actions |
| `Knowledge-Base.md` | Consolidated verified knowledge and open questions |
diff --git a/Scripts/assemble-site-source.js b/Scripts/assemble-site-source.js
new file mode 100644
index 0000000..a4b5a1d
--- /dev/null
+++ b/Scripts/assemble-site-source.js
@@ -0,0 +1,70 @@
+#!/usr/bin/env node
+// SPDX-License-Identifier: MIT
+"use strict";
+// Copy the documentation + static assets into docs/ so MkDocs can build the
+// GitHub Pages site from the repository's existing markdown (MkDocs requires
+// docs_dir to be a child directory). The repository root remains the single
+// source of truth; docs/ is a gitignored staging area.
+//
+// The file list comes from git's index plus untracked non-ignored files
+// (`-c -o --exclude-standard`), so the script works both on a committed CI
+// checkout and in a working tree with uncommitted new docs (e.g. robots.txt).
+//
+// Usage: node Scripts/assemble-site-source.js
+
+const { execSync } = require("child_process");
+const fs = require("fs");
+const path = require("path");
+
+const ROOT = path.resolve(__dirname, "..");
+const DEST = path.join(ROOT, "docs");
+
+// Everything tracked under these prefixes is excluded from the site.
+const EXCLUDED = [
+ "CLAUDE.md",
+ ".github/",
+ ".claude/",
+ "Scripts/",
+ "Statusline/lib/",
+ "Statusline/statusline.js",
+ "Statusline/test/",
+ "node_modules/",
+];
+
+// Non-markdown files referenced by the docs (badges, license, robots.txt).
+const ASSETS = [
+ "LICENSE",
+ "LICENSE.docs",
+ "package.json",
+ "robots.txt",
+];
+
+function shouldInclude(rel) {
+ if (rel.startsWith(".")) return false; // dotfiles/dirs
+ if (EXCLUDED.some((p) => rel === p || rel.startsWith(p))) return false;
+ return true;
+}
+
+function main() {
+ const tracked = execSync("git ls-files -c -o --exclude-standard", { encoding: "utf8" })
+ .trim()
+ .split("\n")
+ .filter(Boolean);
+
+ const wanted = tracked.filter((f) => {
+ if (/\.md$/i.test(f)) return shouldInclude(f);
+ if (f.startsWith("Assets/")) return true;
+ return ASSETS.includes(f);
+ });
+
+ fs.rmSync(DEST, { recursive: true, force: true });
+ for (const rel of wanted) {
+ const src = path.resolve(ROOT, rel);
+ const dst = path.resolve(DEST, rel);
+ fs.mkdirSync(path.dirname(dst), { recursive: true });
+ fs.copyFileSync(src, dst);
+ }
+ console.log(`assemble-site-source: staged ${wanted.length} files into ${DEST}`);
+}
+
+main();
\ No newline at end of file
diff --git a/Scripts/generate-llms.js b/Scripts/generate-llms.js
new file mode 100644
index 0000000..7b0857e
--- /dev/null
+++ b/Scripts/generate-llms.js
@@ -0,0 +1,206 @@
+#!/usr/bin/env node
+// SPDX-License-Identifier: MIT
+"use strict";
+// Generate llms.txt and llms-full.txt for the GitHub Pages docs site.
+//
+// Why this script exists (and why it is the only custom piece):
+// The llms.txt convention (https://llmstxt.org) is not emitted by any
+// static-site generator, and hand-maintaining llms-full.txt — a concatenation
+// of every published doc — would drift the moment any doc changes. Everything
+// else on the site (markdown rendering, anchors, link rewriting, nav, search,
+// sitemap) is handled by MkDocs; this script only produces the two
+// llms.txt-family files from the same source markdown.
+//
+// Usage: node Scripts/generate-llms.js [--src
] [--out ]
+// --src: where the published markdown lives (default: docs/, the staged copy
+// produced by Scripts/assemble-site-source.js)
+// --out: where llms.txt / llms-full.txt are written (default: site/)
+
+const fs = require("fs");
+const path = require("path");
+
+const ROOT = path.resolve(__dirname, "..");
+const SITE_URL = "https://unscriptedbykramy.github.io/AI-Engineering-Lab/";
+
+// Ordered list of published docs, mirroring the `nav` in mkdocs.yml. Add a new
+// published doc to exactly one of these arrays (and to mkdocs.yml nav).
+const DESIGN = [
+ "Statusline/Design/README.md",
+ "Statusline/Design/01-display-requirements.md",
+ "Statusline/Design/02-input-output-contract.md",
+ "Statusline/Design/03-provider-model-naming.md",
+ "Statusline/Design/04-caching-timeout-policy.md",
+ "Statusline/Design/05-security-privacy.md",
+ "Statusline/Design/06-test-cases-acceptance.md",
+ "Statusline/Design/07-design-handoff.md",
+];
+
+const FINDINGS = [
+ "Findings/2026-08-01 - Phase 1B Investigation Plan.md",
+ "Findings/2026-08-01 - Phase 1B - Auto-Cheap Classifier Gating.md",
+ "Findings/2026-08-01 - Phase 1B - OmniRoute Topology and Logs.md",
+ "Findings/2026-08-01 - Phase 1B - Resolved-Route Exposure.md",
+ "Findings/2026-08-01 - Phase 1B - Statusline Input Contract.md",
+ "Findings/2026-08-02 - Phase 2 - Read-only Verification.md",
+ "Findings/2026-08-02 - Phase 2 Architecture Plan.md",
+ "Findings/2026-08-02 - Phase 4 Implementation Plan.md",
+ "Findings/2026-08-03 - Phase 5 - Validation Evidence and Staleness Contract Check.md",
+ "Findings/2026-08-03 - Phase 5 - Validation Report.md",
+ "Findings/2026-08-04 - Context Window Data Source and Statusline Styling.md",
+];
+
+const RESEARCH = [
+ "Research/2026-08-01 - Perplexity Research Round 01 - Initial Investigation.md",
+ "Research/2026-08-01 - Perplexity Research Round 02 - OmniRoute Metadata.md",
+ "Research/2026-08-01 - Perplexity Research Round 03 - Source Code Investigation.md",
+ "Research/2026-08-01 - Perplexity Research Round 04 - Endpoint Investigation.md",
+];
+
+// Key resources first (what an LLM should read for a full picture), then
+// Optional (skippable for shorter contexts) — per the llms.txt spec.
+const KEY = [
+ "README.md",
+ "Statusline/README.md",
+ "Architecture.md",
+ "Decisions.md",
+ "Knowledge-Base.md",
+ "Roadmap.md",
+ "Origin-Story.md",
+];
+
+const OPTIONAL = [
+ "Project Charter.md",
+ "PROJECT_RETROSPECTIVE.md",
+ "Skill-Candidates.md",
+ ...DESIGN,
+ ...FINDINGS,
+ ...RESEARCH,
+ "References/Bibliography.md",
+ "Assets/screenshots/README.md",
+ "CHANGELOG.md",
+ "CONTRIBUTING.md",
+ "CODE_OF_CONDUCT.md",
+ "SECURITY.md",
+ "LICENSING.md",
+];
+
+const KEY_NOTES = {
+ "README.md": "the lab's flagship project overview",
+ "Statusline/README.md": "full operational guide, install, and troubleshooting",
+ "Architecture.md": "verified data flow and component responsibilities",
+ "Decisions.md": "Architecture Decision Records and project-level decisions",
+ "Knowledge-Base.md": "consolidated verified knowledge and open questions",
+ "Roadmap.md": "phases, gates, deliverables, and next actions",
+ "Origin-Story.md": "how the lab started and why the project exists",
+};
+
+const OPTIONAL_NOTES = {
+ "Project Charter.md": "scope, constraints, success criteria, and non-goals",
+ "PROJECT_RETROSPECTIVE.md": "project retrospective",
+ "Skill-Candidates.md": "engineering evidence ledger for reusable workflows",
+ "References/Bibliography.md": "source links and provenance",
+ "Assets/screenshots/README.md": "real statusline output frames",
+ "CHANGELOG.md": "release history",
+ "CONTRIBUTING.md": "contribution guidelines",
+ "CODE_OF_CONDUCT.md": "code of conduct",
+ "SECURITY.md": "security policy",
+ "LICENSING.md": "dual-license guide (MIT code, CC BY 4.0 docs)",
+};
+
+const DOCS = new Set([...KEY, ...OPTIONAL]);
+const enc = (url) => url.replace(/ /g, "%20");
+
+// Map a published doc path to its MkDocs page URL (directory URLs are enabled).
+function pageUrl(docPath) {
+ const slash = docPath.lastIndexOf("/");
+ const dir = slash === -1 ? "" : docPath.slice(0, slash);
+ const name = slash === -1 ? docPath : docPath.slice(slash + 1);
+ const dirPart = dir ? dir + "/" : "";
+ if (name.toLowerCase() === "readme.md") return SITE_URL + dirPart;
+ return SITE_URL + dirPart + name.replace(/\.md$/i, "") + "/";
+}
+
+// Rewrite relative links in a doc to absolute site URLs (absolute, mailto, and
+// fragment-only links are left untouched).
+function rewriteLinks(src, docPath) {
+ return src.replace(/(\[[^\]]*\]\()([^)]+)(\))/g, (m, pre, target, post) => {
+ const t = target.trim();
+ if (/^(https?:|mailto:|#)/i.test(t)) return m;
+ const fragIdx = t.indexOf("#");
+ const frag = fragIdx === -1 ? "" : t.slice(fragIdx);
+ const raw = (fragIdx === -1 ? t : t.slice(0, fragIdx)).trim();
+ if (!raw) return m;
+ const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(docPath), raw));
+ if (DOCS.has(resolved)) return pre + enc(pageUrl(resolved)) + frag + post;
+ if (fs.existsSync(path.resolve(SRC, resolved))) {
+ return pre + enc(SITE_URL + resolved) + frag + post;
+ }
+ return m;
+ });
+}
+
+function buildLlmsFull() {
+ const parts = [];
+ for (const doc of [...KEY, ...OPTIONAL]) {
+ const abs = path.resolve(SRC, doc);
+ if (!fs.existsSync(abs)) {
+ console.error(`generate-llms: missing published doc: ${doc}`);
+ process.exit(1);
+ }
+ const src = fs.readFileSync(abs, "utf8");
+ parts.push(`# File: ${doc}\n\n${rewriteLinks(src, doc).trim()}`);
+ }
+ return parts.join("\n\n") + "\n";
+}
+
+function buildLlmsTxt() {
+ const lines = [];
+ lines.push("# AI Engineering Lab");
+ lines.push("");
+ lines.push(
+ "> Evidence-first AI engineering: the Provider-Aware Statusline for Claude Code behind the OmniRoute LLM routing gateway — see which provider and model actually served your request. Zero-dependency Node.js statusline (68 contract tests) plus the research, findings, architecture, and ADRs that prove how it works."
+ );
+ lines.push("");
+ lines.push(`[llms-full.txt](${SITE_URL}llms-full.txt)`);
+ lines.push("");
+ lines.push("## Key resources");
+ lines.push("");
+ for (const doc of KEY) {
+ const note = KEY_NOTES[doc];
+ lines.push(`- [${KEY_NOTES[doc]}](${enc(pageUrl(doc))}) — ${doc}`);
+ }
+ lines.push("");
+ lines.push("## Optional");
+ lines.push("");
+ for (const doc of OPTIONAL) {
+ const slash = doc.lastIndexOf("/");
+ const name = slash === -1 ? doc : doc.slice(slash + 1);
+ const note = OPTIONAL_NOTES[doc];
+ lines.push(
+ `- [${name.replace(/\.md$/i, "")}](${enc(pageUrl(doc))})${note ? ` — ${note}` : ""}`
+ );
+ }
+ return lines.join("\n") + "\n";
+}
+
+const srcArg = process.argv.indexOf("--src");
+const srcArgVal = srcArg === -1 ? null : process.argv[srcArg + 1];
+const SRC = srcArgVal ? path.resolve(srcArgVal) : path.resolve(ROOT, "docs");
+
+const outArg = process.argv.indexOf("--out");
+const outDir = outArg === -1 ? path.resolve(ROOT, "site") : path.resolve(process.argv[outArg + 1]);
+fs.mkdirSync(outDir, { recursive: true });
+
+const llms = buildLlmsTxt();
+const llmsFull = buildLlmsFull();
+fs.writeFileSync(path.join(outDir, "llms.txt"), llms);
+fs.writeFileSync(path.join(outDir, "llms-full.txt"), llmsFull);
+
+// Self-check: llms.txt must open with an H1 and a blockquote (spec requirement).
+if (!/^# .+\n\n> /.test(llms)) {
+ console.error("generate-llms: llms.txt does not start with H1 + blockquote");
+ process.exit(1);
+}
+console.log(
+ `generate-llms: wrote llms.txt (${llms.split("\n").length} lines) and llms-full.txt (${llmsFull.split("\n").length} lines) to ${outDir}`
+);
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..5fbd4ea
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,110 @@
+# MkDocs site configuration — AI Engineering Lab
+#
+# This builds the GitHub Pages documentation site from the repository's own
+# markdown. Because MkDocs requires docs_dir to be a child directory, the docs
+# are first staged into a gitignored `docs/` (which mirrors the repo structure)
+# by Scripts/assemble-site-source.js — the repository root remains the single
+# source of truth and the site is not a separate product to maintain.
+# Build/validate with:
+# pip install -r requirements.txt
+# node Scripts/assemble-site-source.js
+# mkdocs build --strict # fails on any broken link or warning
+site_name: AI Engineering Lab
+site_description: >-
+ Provider-Aware Statusline for Claude Code behind the OmniRoute LLM routing
+ gateway — see which provider and model actually served your request.
+ Zero-dependency Node.js statusline (68 contract tests) plus an evidence-first
+ AI engineering research trail: research, findings, ADRs, and design docs.
+site_author: UnscriptedByKraMy
+site_url: https://unscriptedbykramy.github.io/AI-Engineering-Lab/
+repo_url: https://github.com/UnscriptedByKraMy/AI-Engineering-Lab
+repo_name: AI-Engineering-Lab
+
+docs_dir: docs
+site_dir: site
+
+theme:
+ name: material
+ palette:
+ - scheme: slate # dark — matches the project's terminal identity
+ primary: teal
+ accent: amber
+ features:
+ - navigation.top
+ - content.code.copy
+ language: en
+
+# `search` is the default MkDocs plugin; core MkDocs also emits `sitemap.xml`
+# automatically because `site_url` is set above (no plugin needed).
+plugins:
+ - search
+
+markdown_extensions:
+ - tables
+ - fenced_code
+ - admonition
+ - attr_list
+ - md_in_html
+ - toc:
+ permalink: true
+
+# The `assemble-site-source.js` script controls exactly which files land in
+# docs/. This list is a safety net for anything that shouldn't leak through.
+exclude_docs: |
+ CLAUDE.md
+ node_modules/
+ site/
+
+# The README links to one hand-written in-page anchor (#for-users--install--use)
+# whose slug does not match MkDocs' generated heading slug. GitHub resolves it;
+# on the site the in-page jump is a harmless no-op. Downgrade the warning so
+# `--strict` stays green.
+validation:
+ anchors: info
+
+nav:
+ - Overview: README.md
+ - Origin Story: Origin-Story.md
+ - Roadmap: Roadmap.md
+ - Project Charter: Project Charter.md
+ - Architecture: Architecture.md
+ - Decisions (ADRs): Decisions.md
+ - Knowledge Base: Knowledge-Base.md
+ - Project Retrospective: PROJECT_RETROSPECTIVE.md
+ - Statusline:
+ - Statusline: Statusline/README.md
+ - Design:
+ - Statusline/Design/README.md
+ - 01 - Display Requirements: Statusline/Design/01-display-requirements.md
+ - 02 - Input/Output Contract: Statusline/Design/02-input-output-contract.md
+ - 03 - Provider/Model Naming: Statusline/Design/03-provider-model-naming.md
+ - 04 - Caching and Timeout Policy: Statusline/Design/04-caching-timeout-policy.md
+ - 05 - Security and Privacy: Statusline/Design/05-security-privacy.md
+ - 06 - Test Cases and Acceptance: Statusline/Design/06-test-cases-acceptance.md
+ - 07 - Design Handoff: Statusline/Design/07-design-handoff.md
+ - Findings:
+ - 2026-08-01 - Phase 1B Investigation Plan: Findings/2026-08-01 - Phase 1B Investigation Plan.md
+ - "2026-08-01 - Phase 1B - Auto-Cheap Classifier Gating": "Findings/2026-08-01 - Phase 1B - Auto-Cheap Classifier Gating.md"
+ - 2026-08-01 - Phase 1B - OmniRoute Topology and Logs: Findings/2026-08-01 - Phase 1B - OmniRoute Topology and Logs.md
+ - 2026-08-01 - Phase 1B - Resolved-Route Exposure: Findings/2026-08-01 - Phase 1B - Resolved-Route Exposure.md
+ - 2026-08-01 - Phase 1B - Statusline Input Contract: Findings/2026-08-01 - Phase 1B - Statusline Input Contract.md
+ - 2026-08-02 - Phase 2 - Read-only Verification: Findings/2026-08-02 - Phase 2 - Read-only Verification.md
+ - 2026-08-02 - Phase 2 Architecture Plan: Findings/2026-08-02 - Phase 2 Architecture Plan.md
+ - 2026-08-02 - Phase 4 Implementation Plan: Findings/2026-08-02 - Phase 4 Implementation Plan.md
+ - 2026-08-03 - Phase 5 - Validation Evidence and Staleness Contract Check: Findings/2026-08-03 - Phase 5 - Validation Evidence and Staleness Contract Check.md
+ - 2026-08-03 - Phase 5 - Validation Report: Findings/2026-08-03 - Phase 5 - Validation Report.md
+ - 2026-08-04 - Context Window Data Source and Statusline Styling: Findings/2026-08-04 - Context Window Data Source and Statusline Styling.md
+ - Research:
+ - Round 01 - Initial Investigation: Research/2026-08-01 - Perplexity Research Round 01 - Initial Investigation.md
+ - Round 02 - OmniRoute Metadata: Research/2026-08-01 - Perplexity Research Round 02 - OmniRoute Metadata.md
+ - Round 03 - Source Code Investigation: Research/2026-08-01 - Perplexity Research Round 03 - Source Code Investigation.md
+ - Round 04 - Endpoint Investigation: Research/2026-08-01 - Perplexity Research Round 04 - Endpoint Investigation.md
+ - References:
+ - Bibliography: References/Bibliography.md
+ - Project records:
+ - Changelog: CHANGELOG.md
+ - Skill Candidates: Skill-Candidates.md
+ - Contributing: CONTRIBUTING.md
+ - Code of Conduct: CODE_OF_CONDUCT.md
+ - Security: SECURITY.md
+ - Licensing: LICENSING.md
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..407f0b6
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,6 @@
+# Build-time dependencies for the GitHub Pages documentation site only.
+# The shipped statusline has zero runtime dependencies; these are used by CI
+# and (optionally) for local site previews.
+# sitemap.xml needs no plugin: MkDocs core generates it when `site_url` is set.
+mkdocs>=1.6,<2
+mkdocs-material>=9.5,<10
diff --git a/robots.txt b/robots.txt
new file mode 100644
index 0000000..a5e39f6
--- /dev/null
+++ b/robots.txt
@@ -0,0 +1,6 @@
+# Allow all crawlers (including AI crawlers such as GPTBot, PerplexityBot,
+# ClaudeBot, and Google-Extended) to index the documentation site.
+User-agent: *
+Allow: /
+
+Sitemap: https://unscriptedbykramy.github.io/AI-Engineering-Lab/sitemap.xml