diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml
index 5a14dd9c..352c1e72 100644
--- a/.github/workflows/deploy-pages.yml
+++ b/.github/workflows/deploy-pages.yml
@@ -38,6 +38,9 @@ jobs:
- name: Install dependencies
run: npm ci
+ - name: Check heading anchor map
+ run: npm run anchors:check
+
- name: Build with VitePress
run: npm run docs:build
diff --git a/docs/.vitepress/anchor-map.json b/docs/.vitepress/anchor-map.json
new file mode 100644
index 00000000..7764a73d
--- /dev/null
+++ b/docs/.vitepress/anchor-map.json
@@ -0,0 +1,2763 @@
+{
+ "harness-designs/claude-code/index.md": {
+ "ids": [
+ "breaking-down-claude-code-s-harness-design",
+ "in-one-sentence",
+ "instruction-subsystem-a-layered-memory-system",
+ "context-subsystem-a-five-layer-compaction-pipeline",
+ "tool-subsystem-four-extension-mechanisms",
+ "feedback-and-verification-deterministic-constraints-human-agent-division-of-labor",
+ "observability-and-session-persistence",
+ "mapping-to-the-course-framework",
+ "designs-worth-adopting",
+ "references-original-sources-source-code"
+ ],
+ "locales": {
+ "ar": 10,
+ "de": 10,
+ "en": 10,
+ "es": 10,
+ "fr": 10,
+ "ja": 10,
+ "ko": 10,
+ "pt-BR": 10,
+ "ru": 10,
+ "tr": 10,
+ "uk": 10,
+ "uz": 10,
+ "vi": 10,
+ "zh": 10,
+ "zh-TW": 10
+ }
+ },
+ "harness-designs/codex/index.md": {
+ "ids": [
+ "breaking-down-codex-s-harness-design",
+ "in-one-sentence",
+ "instruction-subsystem-agents-md-is-a-directory-page-not-an-encyclopedia",
+ "context-subsystem-write-select-compress-isolate",
+ "tools-and-boundaries-worktree-isolation-subagents",
+ "feedback-subsystem-put-verification-commands-in-the-specification",
+ "mapping-to-the-course-framework",
+ "designs-worth-adopting",
+ "references-original-sources-source-code"
+ ],
+ "locales": {
+ "ar": 9,
+ "de": 9,
+ "en": 9,
+ "es": 9,
+ "fr": 9,
+ "ja": 9,
+ "ko": 9,
+ "pt-BR": 9,
+ "ru": 9,
+ "tr": 9,
+ "uk": 9,
+ "uz": 9,
+ "vi": 9,
+ "zh": 14,
+ "zh-TW": 9
+ }
+ },
+ "harness-designs/deepseek/index.md": {
+ "ids": [
+ "breaking-down-deepseek-harness-s-design",
+ "in-one-sentence",
+ "architectural-core-1-capability-seam",
+ "architectural-core-2-event-pipeline",
+ "architectural-core-3-session-event-log-and-model-visible-means-logged",
+ "mapping-to-the-course-framework",
+ "designs-worth-adopting",
+ "references-original-sources-source-code"
+ ],
+ "locales": {
+ "ar": 8,
+ "de": 8,
+ "en": 8,
+ "es": 8,
+ "fr": 8,
+ "ja": 8,
+ "ko": 8,
+ "pt-BR": 8,
+ "ru": 8,
+ "tr": 8,
+ "uk": 8,
+ "uz": 8,
+ "vi": 8,
+ "zh": 8,
+ "zh-TW": 8
+ }
+ },
+ "harness-designs/index.md": {
+ "ids": [
+ "frontier-harness-design-breakdowns",
+ "why-these-breakdowns-matter",
+ "articles",
+ "how-to-read-this-section"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 4,
+ "en": 4,
+ "es": 4,
+ "fr": 4,
+ "ja": 4,
+ "ko": 4,
+ "pt-BR": 4,
+ "ru": 4,
+ "tr": 4,
+ "uk": 4,
+ "uz": 4,
+ "vi": 4,
+ "zh": 4,
+ "zh-TW": 4
+ }
+ },
+ "harness-designs/pi/index.md": {
+ "ids": [
+ "breaking-down-pi-s-harness-design",
+ "in-one-sentence",
+ "core-loop",
+ "instruction-subsystem-agents-md-and-system-md",
+ "state-and-context-where-pi-is-most-granular",
+ "tool-subsystem-skills-and-extensions",
+ "feedback-and-verification-making-learning-part-of-the-harness",
+ "mapping-to-the-course-framework",
+ "designs-worth-adopting",
+ "references-original-sources-source-code"
+ ],
+ "locales": {
+ "ar": 10,
+ "de": 10,
+ "en": 10,
+ "es": 10,
+ "fr": 10,
+ "ja": 10,
+ "ko": 10,
+ "pt-BR": 10,
+ "ru": 10,
+ "tr": 10,
+ "uk": 10,
+ "uz": 10,
+ "vi": 10,
+ "zh": 10,
+ "zh-TW": 10
+ }
+ },
+ "index.md": {
+ "ids": [
+ "welcome-to-learn-harness-engineering",
+ "get-started",
+ "the-core-mechanism-of-a-harness",
+ "what-you-will-learn",
+ "next-steps"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "lectures/lecture-01-why-capable-agents-still-fail/code/failure-signals-checklist.md": {
+ "ids": [
+ "failure-signals-checklist"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-01-why-capable-agents-still-fail/code/index.md": {
+ "ids": [
+ "code-for-lecture-01"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-01-why-capable-agents-still-fail/code/underspecified-task.md": {
+ "ids": [
+ "underspecified-task-example"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-01-why-capable-agents-still-fail/index.md": {
+ "ids": [
+ "lecture-01-strong-models-don-t-mean-reliable-execution",
+ "same-horse-different-fates",
+ "where-agents-actually-get-stuck",
+ "key-terminology",
+ "when-things-fail-fix-the-harness-first",
+ "the-million-line-experiment",
+ "a-more-down-to-earth-example",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 10,
+ "de": 10,
+ "en": 10,
+ "es": 10,
+ "fr": 10,
+ "ja": 10,
+ "ko": 10,
+ "pt-BR": 10,
+ "ru": 10,
+ "tr": 10,
+ "uk": 10,
+ "uz": 10,
+ "vi": 10,
+ "zh": 10,
+ "zh-TW": 10
+ }
+ },
+ "lectures/lecture-02-what-a-harness-actually-is/code/harness-components.md": {
+ "ids": [
+ "harness-components-example"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-02-what-a-harness-actually-is/code/index.md": {
+ "ids": [
+ "code-for-lecture-02"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-02-what-a-harness-actually-is/index.md": {
+ "ids": [
+ "lecture-02-what-a-harness-actually-is",
+ "start-with-an-analogy",
+ "core-concepts",
+ "the-five-subsystem-harness-model",
+ "a-team-s-real-story",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 8,
+ "de": 8,
+ "en": 8,
+ "es": 8,
+ "fr": 8,
+ "ja": 8,
+ "ko": 8,
+ "pt-BR": 8,
+ "ru": 8,
+ "tr": 8,
+ "uk": 8,
+ "uz": 8,
+ "vi": 8,
+ "zh": 8,
+ "zh-TW": 8
+ }
+ },
+ "lectures/lecture-03-why-the-repository-must-become-the-system-of-record/code/index.md": {
+ "ids": [
+ "code-for-lecture-03"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-03-why-the-repository-must-become-the-system-of-record/code/system-of-record-checklist.md": {
+ "ids": [
+ "system-of-record-checklist"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-03-why-the-repository-must-become-the-system-of-record/index.md": {
+ "ids": [
+ "lecture-03-making-the-repository-the-single-source-of-truth",
+ "what-belongs-on-the-map",
+ "knowledge-visibility",
+ "core-concepts",
+ "how-to-draw-a-good-map",
+ "managing-agent-state-with-acid-principles",
+ "a-real-transformation-story",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 10,
+ "de": 10,
+ "en": 10,
+ "es": 10,
+ "fr": 10,
+ "ja": 10,
+ "ko": 10,
+ "pt-BR": 10,
+ "ru": 10,
+ "tr": 10,
+ "uk": 10,
+ "uz": 10,
+ "vi": 10,
+ "zh": 10,
+ "zh-TW": 10
+ }
+ },
+ "lectures/lecture-04-why-one-giant-instruction-file-fails/code/AGENTS-short.md": {
+ "ids": [
+ "agents-md",
+ "start-here",
+ "hard-rules"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "lectures/lecture-04-why-one-giant-instruction-file-fails/code/anti-patterns.md": {
+ "ids": [
+ "instruction-file-anti-patterns"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-04-why-one-giant-instruction-file-fails/code/index.md": {
+ "ids": [
+ "code-for-lecture-04"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-04-why-one-giant-instruction-file-fails/index.md": {
+ "ids": [
+ "lecture-04-split-instructions-across-files",
+ "the-vicious-cycle-at-the-root",
+ "core-concepts",
+ "instruction-architecture",
+ "how-to-split",
+ "real-world-example",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 9,
+ "de": 9,
+ "en": 9,
+ "es": 9,
+ "fr": 9,
+ "ja": 9,
+ "ko": 9,
+ "pt-BR": 9,
+ "ru": 9,
+ "tr": 9,
+ "uk": 9,
+ "uz": 9,
+ "vi": 9,
+ "zh": 9,
+ "zh-TW": 9
+ }
+ },
+ "lectures/lecture-05-why-long-running-tasks-lose-continuity/code/continuity-checklist.md": {
+ "ids": [
+ "continuity-checklist"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-05-why-long-running-tasks-lose-continuity/code/index.md": {
+ "ids": [
+ "code-for-lecture-05"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-05-why-long-running-tasks-lose-continuity/code/session-handoff.md": {
+ "ids": [
+ "session-handoff-example",
+ "completed",
+ "broken-or-unverified",
+ "next-best-step"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 4,
+ "en": 4,
+ "es": 4,
+ "fr": 4,
+ "ja": 4,
+ "ko": 4,
+ "pt-BR": 4,
+ "ru": 4,
+ "tr": 4,
+ "uk": 4,
+ "uz": 4,
+ "vi": 4,
+ "zh": 4,
+ "zh-TW": 4
+ }
+ },
+ "lectures/lecture-05-why-long-running-tasks-lose-continuity/index.md": {
+ "ids": [
+ "lecture-05-keeping-context-alive-across-sessions",
+ "context-windows-not-infinite",
+ "session-continuity-flow",
+ "core-concepts",
+ "what-happens-when-continuity-breaks",
+ "practical-approaches-to-state-persistence",
+ "a-deeper-look-at-context-anxiety",
+ "real-world-example",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 11,
+ "de": 11,
+ "en": 11,
+ "es": 11,
+ "fr": 11,
+ "ja": 11,
+ "ko": 11,
+ "pt-BR": 11,
+ "ru": 11,
+ "tr": 11,
+ "uk": 11,
+ "uz": 11,
+ "vi": 11,
+ "zh": 11,
+ "zh-TW": 11
+ }
+ },
+ "lectures/lecture-06-why-initialization-needs-its-own-phase/code/index.md": {
+ "ids": [
+ "code-for-lecture-06"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-06-why-initialization-needs-its-own-phase/code/initializer-output-checklist.md": {
+ "ids": [
+ "initializer-output-checklist"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-06-why-initialization-needs-its-own-phase/index.md": {
+ "ids": [
+ "lecture-06-make-the-agent-initialize-before-every-work-session",
+ "two-fundamentally-different-kinds-of-work",
+ "initialization-lifecycle",
+ "what-happens-when-you-mix-them",
+ "core-concepts",
+ "how-to-do-initialization-right",
+ "real-world-example",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 10,
+ "de": 10,
+ "en": 10,
+ "es": 10,
+ "fr": 10,
+ "ja": 10,
+ "ko": 10,
+ "pt-BR": 10,
+ "ru": 10,
+ "tr": 10,
+ "uk": 10,
+ "uz": 10,
+ "vi": 10,
+ "zh": 10,
+ "zh-TW": 10
+ }
+ },
+ "lectures/lecture-07-why-agents-overreach-and-under-finish/code/index.md": {
+ "ids": [
+ "code-for-lecture-07"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-07-why-agents-overreach-and-under-finish/code/next-task-template.md": {
+ "ids": [
+ "next-task-template"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-07-why-agents-overreach-and-under-finish/code/scope-surface-example.md": {
+ "ids": [
+ "scope-surface-example"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-07-why-agents-overreach-and-under-finish/index.md": {
+ "ids": [
+ "lecture-07-draw-clear-task-boundaries-for-agents",
+ "attention-is-a-finite-resource",
+ "wip-1-workflow",
+ "core-concepts",
+ "overreach-and-under-finish-are-two-sides-of-the-same-coin",
+ "how-to-do-it-right",
+ "_1-enforce-wip-1",
+ "_2-define-explicit-completion-evidence-for-every-task",
+ "_3-externalize-the-scope-surface",
+ "_4-monitor-verified-completion-rate",
+ "real-world-case",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 14,
+ "de": 14,
+ "en": 14,
+ "es": 14,
+ "fr": 14,
+ "ja": 14,
+ "ko": 14,
+ "pt-BR": 14,
+ "ru": 14,
+ "tr": 14,
+ "uk": 14,
+ "uz": 14,
+ "vi": 14,
+ "zh": 14,
+ "zh-TW": 14
+ }
+ },
+ "lectures/lecture-08-why-feature-lists-are-harness-primitives/code/index.md": {
+ "ids": [
+ "code-for-lecture-08"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-08-why-feature-lists-are-harness-primitives/code/pass-gate-policy.md": {
+ "ids": [
+ "pass-gate-policy"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-08-why-feature-lists-are-harness-primitives/index.md": {
+ "ids": [
+ "lecture-08-use-feature-lists-to-constrain-what-the-agent-does",
+ "agents-don-t-know-what-done-means",
+ "feature-state-machine",
+ "core-concepts",
+ "why-feature-lists-must-be-primitives",
+ "how-to-do-it",
+ "_1-define-a-minimal-feature-list-format",
+ "_2-let-the-harness-control-state-transitions",
+ "_3-write-the-rules-in-claude-md",
+ "_4-calibrate-granularity",
+ "real-world-case",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 14,
+ "de": 14,
+ "en": 14,
+ "es": 14,
+ "fr": 14,
+ "ja": 14,
+ "ko": 14,
+ "pt-BR": 14,
+ "ru": 14,
+ "tr": 14,
+ "uk": 14,
+ "uz": 14,
+ "vi": 14,
+ "zh": 14,
+ "zh-TW": 14
+ }
+ },
+ "lectures/lecture-09-why-agents-declare-victory-too-early/code/clean-state-checklist.md": {
+ "ids": [
+ "clean-state-checklist"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-09-why-agents-declare-victory-too-early/code/index.md": {
+ "ids": [
+ "code-for-lecture-09"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-09-why-agents-declare-victory-too-early/index.md": {
+ "ids": [
+ "lecture-9-preventing-agents-from-declaring-victory-too-early",
+ "the-slippery-slope",
+ "three-layer-termination-check",
+ "core-concepts",
+ "passing-unit-tests-task-complete",
+ "refactoring-while-we-re-at-it-is-poison-to-completion-judgment",
+ "systematic-bias-in-self-evaluation",
+ "how-to-prevent-premature-completion-declarations",
+ "_1-externalize-termination-judgment",
+ "_2-build-a-three-layer-termination-validation",
+ "_3-provide-actionable-error-feedback-to-the-agent",
+ "_4-capture-runtime-signals",
+ "real-world-case",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 16,
+ "de": 16,
+ "en": 16,
+ "es": 16,
+ "fr": 16,
+ "ja": 16,
+ "ko": 16,
+ "pt-BR": 16,
+ "ru": 16,
+ "tr": 16,
+ "uk": 16,
+ "uz": 16,
+ "vi": 16,
+ "zh": 16,
+ "zh-TW": 16
+ }
+ },
+ "lectures/lecture-10-why-end-to-end-testing-changes-results/code/architecture-rules.md": {
+ "ids": [
+ "electron-architecture-rules"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-10-why-end-to-end-testing-changes-results/code/index.md": {
+ "ids": [
+ "code-for-lecture-10"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-10-why-end-to-end-testing-changes-results/code/review-feedback-to-rule.md": {
+ "ids": [
+ "example-turning-review-feedback-into-a-rule"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-10-why-end-to-end-testing-changes-results/index.md": {
+ "ids": [
+ "lecture-10-only-a-full-pipeline-run-counts-as-real-verification",
+ "the-blind-spots-of-unit-tests",
+ "end-to-end-testing-not-only-changes-results-—-it-changes-behavior",
+ "testing-pyramid-and-review-feedback-promotion",
+ "core-concepts",
+ "how-to-do-it",
+ "_0-define-architectural-boundaries-before-writing-e2e-tests",
+ "_1-the-harness-must-include-an-end-to-end-layer",
+ "_2-turn-architectural-rules-into-executable-checks",
+ "_3-design-agent-oriented-error-messages",
+ "_4-establish-a-review-feedback-promotion-process",
+ "real-world-case",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 15,
+ "de": 15,
+ "en": 15,
+ "es": 15,
+ "fr": 15,
+ "ja": 15,
+ "ko": 15,
+ "pt-BR": 15,
+ "ru": 15,
+ "tr": 15,
+ "uk": 15,
+ "uz": 15,
+ "vi": 15,
+ "zh": 15,
+ "zh-TW": 15
+ }
+ },
+ "lectures/lecture-11-why-observability-belongs-inside-the-harness/code/evaluator-rubric.md": {
+ "ids": [
+ "evaluator-rubric-example"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-11-why-observability-belongs-inside-the-harness/code/index.md": {
+ "ids": [
+ "code-for-lecture-11"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-11-why-observability-belongs-inside-the-harness/code/sprint-contract.md": {
+ "ids": [
+ "sprint-contract-example"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-11-why-observability-belongs-inside-the-harness/index.md": {
+ "ids": [
+ "lecture-11-making-the-agent-s-runtime-observable",
+ "the-real-cost-of-missing-observability",
+ "a-real-claude-code-scenario",
+ "layered-observability",
+ "core-concepts",
+ "why-agents-can-t-solve-this-themselves",
+ "how-to-build-observability",
+ "_1-build-runtime-signal-collection-into-the-harness",
+ "_2-implement-sprint-contracts",
+ "_3-establish-an-evaluator-rubric",
+ "_4-standardize-with-opentelemetry",
+ "anthropic-s-three-agent-architecture-experiment",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 17,
+ "de": 17,
+ "en": 15,
+ "es": 17,
+ "fr": 17,
+ "ja": 17,
+ "ko": 17,
+ "pt-BR": 15,
+ "ru": 17,
+ "tr": 17,
+ "uk": 15,
+ "uz": 17,
+ "vi": 15,
+ "zh": 15,
+ "zh-TW": 15
+ }
+ },
+ "lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/benchmark-comparison-template.md": {
+ "ids": [
+ "benchmark-comparison-template"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/cleanup-loop.md": {
+ "ids": [
+ "cleanup-loop-example"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/index.md": {
+ "ids": [
+ "code-for-lecture-12"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-12-why-every-session-must-leave-a-clean-state/index.md": {
+ "ids": [
+ "lecture-12-leave-a-clean-handoff-at-the-end-of-every-session",
+ "entropy-growth-is-the-default-state",
+ "clean-state-more-than-the-code-compiles",
+ "core-concepts",
+ "clean-up-later-means-never-clean-up",
+ "how-to-do-it",
+ "_1-clean-state-is-a-necessary-condition-for-completion",
+ "_2-dual-mode-cleanup-strategy",
+ "_3-maintain-a-quality-document",
+ "_4-periodically-simplify-the-harness",
+ "_5-cleanup-operations-must-be-idempotent",
+ "_6-high-throughput-changes-the-merge-philosophy",
+ "real-world-case",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 18,
+ "de": 17,
+ "en": 16,
+ "es": 17,
+ "fr": 18,
+ "ja": 18,
+ "ko": 18,
+ "pt-BR": 16,
+ "ru": 18,
+ "tr": 18,
+ "uk": 16,
+ "uz": 18,
+ "vi": 16,
+ "zh": 16,
+ "zh-TW": 16
+ }
+ },
+ "lectures/lecture-13-loop-engineering/code/checker-prompt.md": {
+ "ids": [
+ "checker-agent-prompt",
+ "your-role",
+ "checklist",
+ "functional-correctness",
+ "code-quality",
+ "testing",
+ "verification-commands",
+ "safety-and-impact",
+ "output-requirements"
+ ],
+ "locales": {
+ "ar": 9,
+ "de": 9,
+ "en": 9,
+ "es": 9,
+ "fr": 9,
+ "ja": 9,
+ "ko": 9,
+ "pt-BR": 9,
+ "ru": 9,
+ "tr": 9,
+ "uk": 9,
+ "uz": 9,
+ "vi": 9,
+ "zh": 9,
+ "zh-TW": 9
+ }
+ },
+ "lectures/lecture-13-loop-engineering/code/goal-template.md": {
+ "ids": [
+ "goal-loop-template",
+ "goal",
+ "acceptance-criteria",
+ "scope",
+ "fair-game",
+ "hands-off",
+ "verification-method",
+ "stop-conditions",
+ "how-to-work"
+ ],
+ "locales": {
+ "ar": 9,
+ "de": 9,
+ "en": 9,
+ "es": 9,
+ "fr": 9,
+ "ja": 9,
+ "ko": 9,
+ "pt-BR": 9,
+ "ru": 9,
+ "tr": 9,
+ "uk": 9,
+ "uz": 9,
+ "vi": 9,
+ "zh": 9,
+ "zh-TW": 9
+ }
+ },
+ "lectures/lecture-13-loop-engineering/code/index.md": {
+ "ids": [
+ "lecture-13-code-examples"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "lectures/lecture-13-loop-engineering/code/loop-state-template.md": {
+ "ids": [
+ "loop-state-template",
+ "basic-info",
+ "goal",
+ "round-log",
+ "round-1",
+ "issues-found",
+ "round-2",
+ "issues-found-1",
+ "cumulative-stats",
+ "blocker-list",
+ "final-result"
+ ],
+ "locales": {
+ "ar": 11,
+ "de": 11,
+ "en": 11,
+ "es": 11,
+ "fr": 11,
+ "ja": 11,
+ "ko": 11,
+ "pt-BR": 11,
+ "ru": 11,
+ "tr": 11,
+ "uk": 11,
+ "uz": 11,
+ "vi": 11,
+ "zh": 11,
+ "zh-TW": 11
+ }
+ },
+ "lectures/lecture-13-loop-engineering/code/maker-prompt.md": {
+ "ids": [
+ "maker-agent-prompt",
+ "your-role",
+ "working-rules",
+ "deliverables",
+ "output-format"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "lectures/lecture-13-loop-engineering/index.md": {
+ "ids": [
+ "lecture-13-from-manual-prompting-to-autonomous-loops",
+ "goal-the-simplest-possible-loop",
+ "how-goal-grew-organically",
+ "there-s-more-than-one-kind-of-loop",
+ "don-t-confuse-goal-and-loop",
+ "june-2026-three-people-lit-the-same-fuse-in-one-week",
+ "inside-the-loop-vs-outside-the-loop",
+ "core-concepts",
+ "the-six-primitives-of-a-loop",
+ "_1-automations-—-the-heartbeat",
+ "_2-worktrees-—-isolation-at-scale",
+ "_3-skills-—-stop-re-explaining-your-project",
+ "_4-connectors-—-your-loop-touches-real-tools",
+ "_5-sub-agents-—-keep-the-maker-away-from-the-checker",
+ "_6-external-state-—-the-loop-s-memory",
+ "a-complete-loop-anatomized",
+ "generator-evaluator-separation-why-you-can-t-let-the-model-grade-its-own-work",
+ "karpathy-s-autoresearch-the-loop-exemplar",
+ "three-files-three-roles",
+ "input-what-program-md-looks-like",
+ "the-nine-step-ratchet-loop",
+ "output-what-you-see-when-you-wake-up",
+ "what-it-actually-found",
+ "the-most-telling-detail-the-loop-is-written-in-english-not-code",
+ "four-silent-costs",
+ "_1-verification-debt",
+ "_2-comprehension-rot",
+ "_3-cognitive-surrender",
+ "_4-token-blowout",
+ "building-your-first-loop",
+ "step-1-pick-one-recurring-task",
+ "step-2-write-a-goal-and-stopping-condition",
+ "step-3-split-maker-and-checker",
+ "step-4-add-memory",
+ "step-5-set-a-timer",
+ "the-maturity-ladder",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 39,
+ "de": 39,
+ "en": 39,
+ "es": 39,
+ "fr": 39,
+ "ja": 39,
+ "ko": 39,
+ "pt-BR": 39,
+ "ru": 39,
+ "tr": 39,
+ "uk": 39,
+ "uz": 39,
+ "vi": 39,
+ "zh": 39,
+ "zh-TW": 39
+ }
+ },
+ "lectures/lecture-14-graph-engineering/code/index.md": {
+ "ids": [
+ "lecture-14-code"
+ ],
+ "locales": {
+ "en": 1,
+ "zh": 1
+ }
+ },
+ "lectures/lecture-14-graph-engineering/index.md": {
+ "ids": [
+ "lecture-14-from-single-loops-to-graph-engineering",
+ "prompt-context-loop-graph-four-names-one-stack",
+ "take-the-graph-apart-nodes-edges-state-routing",
+ "when-a-loop-stops-being-enough",
+ "three-structural-failures-of-a-single-loop-at-scale",
+ "_1-goodhart-the-numbers-went-up-the-business-got-worse",
+ "_2-blindness-upward-it-never-asks-is-this-the-right-goal",
+ "_3-conflict-independent-loops-fight-each-other",
+ "anchors-pin-the-loop-to-reality",
+ "graph-vs-workflow-not-just-a-rename",
+ "you-ve-been-drawing-graphs-all-along",
+ "build-your-first-graph-from-scratch",
+ "open-source-projects-after-the-name-before-the-name",
+ "cold-water-a-graph-is-not-a-silver-bullet",
+ "when-you-actually-need-a-graph",
+ "core-concepts",
+ "key-takeaways",
+ "further-reading",
+ "exercises"
+ ],
+ "locales": {
+ "ar": 19,
+ "de": 19,
+ "en": 19,
+ "es": 19,
+ "fr": 19,
+ "ja": 19,
+ "ko": 19,
+ "pt-BR": 19,
+ "ru": 19,
+ "tr": 19,
+ "uk": 19,
+ "uz": 19,
+ "vi": 19,
+ "zh": 19,
+ "zh-TW": 19
+ }
+ },
+ "projects/index.md": {
+ "ids": [
+ "welcome-to-projects",
+ "project-overview",
+ "how-to-proceed"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "projects/project-01-baseline-vs-minimal-harness/index.md": {
+ "ids": [
+ "project-01-prompt-only-vs-rules-first-how-much-difference-does-it-make",
+ "what-you-do",
+ "use-the-checked-in-project",
+ "tools",
+ "harness-mechanism",
+ "run-protocol",
+ "preparation",
+ "first-run-weak-harness",
+ "second-run-strong-harness",
+ "how-to-measure-results",
+ "what-to-submit",
+ "experimental-framing",
+ "related-lectures"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 13,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 11,
+ "zh-TW": 13
+ }
+ },
+ "projects/project-02-agent-readable-workspace/index.md": {
+ "ids": [
+ "project-02-make-the-project-readable-and-pick-up-where-you-left-off",
+ "what-you-do",
+ "tools",
+ "harness-mechanism",
+ "use-the-checked-in-project"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 11,
+ "zh-TW": 12
+ }
+ },
+ "projects/project-03-multi-session-continuity/index.md": {
+ "ids": [
+ "project-03-keep-the-agent-working-across-session-restarts",
+ "what-you-do",
+ "tools",
+ "harness-mechanism",
+ "use-the-checked-in-project"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 11,
+ "zh-TW": 12
+ }
+ },
+ "projects/project-04-incremental-indexing/index.md": {
+ "ids": [
+ "project-04-use-runtime-feedback-to-correct-agent-behavior",
+ "what-you-do",
+ "tools",
+ "harness-mechanism",
+ "use-the-checked-in-project"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 11,
+ "zh-TW": 12
+ }
+ },
+ "projects/project-05-grounded-qa-verification/index.md": {
+ "ids": [
+ "project-05-make-the-agent-verify-its-own-work",
+ "what-you-do",
+ "tools",
+ "harness-mechanism",
+ "use-the-checked-in-project"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 13,
+ "zh-TW": 14
+ }
+ },
+ "projects/project-06-runtime-observability-and-debugging/index.md": {
+ "ids": [
+ "project-06-build-a-complete-agent-harness-capstone",
+ "what-you-do",
+ "tools",
+ "harness-mechanism",
+ "use-the-checked-in-project"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 13,
+ "zh-TW": 14
+ }
+ },
+ "projects/project-07-loop-engineering-first-loop/index.md": {
+ "ids": [
+ "project-07-build-your-first-automated-loop",
+ "what-you-ll-do",
+ "project-files",
+ "tools-you-ll-use",
+ "steps",
+ "prep",
+ "experiment-1-goal-loop-—-from-manual-run-to-auto-run",
+ "experiment-2-timer-loop-—-turn-monitoring-into-a-heartbeat",
+ "experiment-3-maker-checker-loop-—-take-yourself-out-of-the-loop",
+ "how-to-measure-results",
+ "what-to-submit",
+ "related-lectures"
+ ],
+ "locales": {
+ "ar": 12,
+ "de": 12,
+ "en": 12,
+ "es": 12,
+ "fr": 12,
+ "ja": 12,
+ "ko": 12,
+ "pt-BR": 12,
+ "ru": 12,
+ "tr": 12,
+ "uk": 12,
+ "uz": 12,
+ "vi": 12,
+ "zh": 12,
+ "zh-TW": 12
+ }
+ },
+ "projects/project-08-graph-engineering-first-graph/index.md": {
+ "ids": [
+ "project-08-draw-your-workflow-as-a-graph",
+ "what-you-ll-do",
+ "tools-you-ll-use",
+ "steps",
+ "prep",
+ "experiment-1-draw-the-loop-as-an-explicit-graph",
+ "experiment-2-add-a-parallel-fan-out-fan-in-node",
+ "experiment-3-add-a-rollback-edge-and-a-human-approval-node",
+ "how-to-measure-results",
+ "what-to-submit",
+ "related-lectures"
+ ],
+ "locales": {
+ "ar": 11,
+ "de": 11,
+ "en": 11,
+ "es": 11,
+ "fr": 11,
+ "ja": 11,
+ "ko": 11,
+ "pt-BR": 11,
+ "ru": 11,
+ "tr": 11,
+ "uk": 11,
+ "uz": 11,
+ "vi": 11,
+ "zh": 11,
+ "zh-TW": 11
+ }
+ },
+ "resources/index.md": {
+ "ids": [
+ "english-resource-library",
+ "when-to-use-it",
+ "start-here",
+ "library-structure",
+ "recommended-minimal-pack"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/index.md": {
+ "ids": [
+ "openai-advanced-pack",
+ "included-starter-layout",
+ "how-to-adopt-it",
+ "sop-library",
+ "design-principles"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 6,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/repo-template/AGENTS.md": {
+ "ids": [
+ "agents-md",
+ "startup-workflow",
+ "routing-map",
+ "working-contract",
+ "definition-of-done",
+ "end-of-session"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 6,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/openai-advanced/repo-template/ARCHITECTURE.md": {
+ "ids": [
+ "architecture-md",
+ "system-shape",
+ "domain-map",
+ "layer-model",
+ "hard-dependency-rules",
+ "cross-cutting-interfaces",
+ "current-hot-spots",
+ "change-checklist"
+ ],
+ "locales": {
+ "ar": 8,
+ "de": 8,
+ "en": 8,
+ "es": 8,
+ "fr": 8,
+ "ja": 8,
+ "ko": 8,
+ "pt-BR": 8,
+ "ru": 8,
+ "tr": 8,
+ "uk": 8,
+ "uz": 8,
+ "vi": 8,
+ "zh": 8,
+ "zh-TW": 8
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/DESIGN.md": {
+ "ids": [
+ "design-md",
+ "purpose",
+ "read-this-when",
+ "canonical-design-docs",
+ "design-rules"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/FRONTEND.md": {
+ "ids": [
+ "frontend-md",
+ "ui-principles",
+ "guardrails",
+ "verification-expectations"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 4,
+ "en": 4,
+ "es": 4,
+ "fr": 4,
+ "ja": 4,
+ "ko": 4,
+ "pt-BR": 4,
+ "ru": 4,
+ "tr": 4,
+ "uk": 4,
+ "uz": 4,
+ "vi": 4,
+ "zh": 4,
+ "zh-TW": 4
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/PLANS.md": {
+ "ids": [
+ "plans-md",
+ "when-a-plan-is-required",
+ "plan-locations",
+ "minimum-plan-sections",
+ "operating-rules"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/PRODUCT_SENSE.md": {
+ "ids": [
+ "product-sense-md",
+ "product-core",
+ "product-rules",
+ "no-go-patterns"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 4,
+ "en": 4,
+ "es": 4,
+ "fr": 4,
+ "ja": 4,
+ "ko": 4,
+ "pt-BR": 4,
+ "ru": 4,
+ "tr": 4,
+ "uk": 4,
+ "uz": 4,
+ "vi": 4,
+ "zh": 4,
+ "zh-TW": 4
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/QUALITY_SCORE.md": {
+ "ids": [
+ "quality-score-md",
+ "grading-scale",
+ "product-domains",
+ "architectural-layers",
+ "benchmark-snapshots",
+ "simplification-log"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 5,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/RELIABILITY.md": {
+ "ids": [
+ "reliability-md",
+ "standard-paths",
+ "required-runtime-signals",
+ "golden-journeys",
+ "reliability-rules"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/SECURITY.md": {
+ "ids": [
+ "security-md",
+ "secrets-and-credentials",
+ "untrusted-input",
+ "external-actions",
+ "dependency-and-review-rules"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 4,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/design-docs/core-beliefs.md": {
+ "ids": [
+ "core-beliefs"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/design-docs/index.md": {
+ "ids": [
+ "design-docs-index",
+ "accepted",
+ "proposed",
+ "deprecated",
+ "maintenance-rules"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/exec-plans/active/index.md": {
+ "ids": [
+ "active-plans"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/exec-plans/completed/index.md": {
+ "ids": [
+ "completed-plans"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/exec-plans/tech-debt-tracker.md": {
+ "ids": [
+ "tech-debt-tracker"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/generated/db-schema.md": {
+ "ids": [
+ "database-schema",
+ "source",
+ "notes"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/product-specs/index.md": {
+ "ids": [
+ "product-specs-index",
+ "active-specs",
+ "rules"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "resources/openai-advanced/repo-template/docs/product-specs/new-user-onboarding.md": {
+ "ids": [
+ "new-user-onboarding",
+ "goal",
+ "entry-conditions",
+ "user-flow",
+ "acceptance-criteria",
+ "failure-states"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 6,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/openai-advanced/repo-template/index.md": {
+ "ids": [
+ "advanced-repo-template",
+ "copy-order",
+ "what-this-template-optimizes-for"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "resources/openai-advanced/sops/chrome-devtools-validation-loop.md": {
+ "ids": [
+ "sop-chrome-devtools-validation-loop",
+ "goal",
+ "core-loop",
+ "required-inputs",
+ "execution-sop",
+ "clean-criteria",
+ "repo-artifacts-to-update"
+ ],
+ "locales": {
+ "ar": 7,
+ "de": 7,
+ "en": 7,
+ "es": 7,
+ "fr": 7,
+ "ja": 7,
+ "ko": 7,
+ "pt-BR": 7,
+ "ru": 7,
+ "tr": 7,
+ "uk": 7,
+ "uz": 7,
+ "vi": 7,
+ "zh": 7,
+ "zh-TW": 7
+ }
+ },
+ "resources/openai-advanced/sops/encode-knowledge-into-repo.md": {
+ "ids": [
+ "sop-encode-unseen-knowledge-into-the-repo",
+ "goal",
+ "trigger-signals",
+ "execution-sop",
+ "good-encoding-rules",
+ "definition-of-done"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 6,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/openai-advanced/sops/index.md": {
+ "ids": [
+ "openai-advanced-sops",
+ "included-sops",
+ "how-to-use-them"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "resources/openai-advanced/sops/layered-domain-architecture.md": {
+ "ids": [
+ "sop-layered-domain-architecture",
+ "goal",
+ "target-model",
+ "setup-checklist",
+ "execution-sop",
+ "definition-of-done",
+ "repo-artifacts-to-update"
+ ],
+ "locales": {
+ "ar": 7,
+ "de": 7,
+ "en": 7,
+ "es": 7,
+ "fr": 7,
+ "ja": 7,
+ "ko": 7,
+ "pt-BR": 7,
+ "ru": 7,
+ "tr": 7,
+ "uk": 7,
+ "uz": 7,
+ "vi": 7,
+ "zh": 7,
+ "zh-TW": 7
+ }
+ },
+ "resources/openai-advanced/sops/observability-feedback-loop.md": {
+ "ids": [
+ "sop-observability-feedback-loop",
+ "goal",
+ "minimum-stack",
+ "execution-sop",
+ "debug-session-checklist",
+ "definition-of-done"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 6,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/reference/coding-agent-startup-flow.md": {
+ "ids": [
+ "coding-agent-startup-flow",
+ "fixed-startup-template",
+ "why-this-order-matters",
+ "end-of-session-mirror"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 4,
+ "en": 4,
+ "es": 4,
+ "fr": 4,
+ "ja": 4,
+ "ko": 4,
+ "pt-BR": 4,
+ "ru": 4,
+ "tr": 4,
+ "uk": 4,
+ "uz": 4,
+ "vi": 4,
+ "zh": 4,
+ "zh-TW": 4
+ }
+ },
+ "resources/reference/index.md": {
+ "ids": [
+ "english-reference",
+ "internal-reference-notes",
+ "primary-articles",
+ "_2026-extended-references",
+ "suggested-reading-order"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 4,
+ "ko": 3,
+ "pt-BR": 5,
+ "ru": 3,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 3,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/reference/initializer-agent-playbook.md": {
+ "ids": [
+ "initializer-agent-playbook",
+ "goal",
+ "required-outputs",
+ "checklist",
+ "success-test"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/reference/method-map.md": {
+ "ids": [
+ "method-map",
+ "operating-principle"
+ ],
+ "locales": {
+ "ar": 2,
+ "de": 2,
+ "en": 2,
+ "es": 2,
+ "fr": 2,
+ "ja": 2,
+ "ko": 2,
+ "pt-BR": 2,
+ "ru": 2,
+ "tr": 2,
+ "uk": 2,
+ "uz": 2,
+ "vi": 2,
+ "zh": 2,
+ "zh-TW": 2
+ }
+ },
+ "resources/reference/prompt-calibration.md": {
+ "ids": [
+ "prompt-calibration",
+ "keep-in-the-root-file",
+ "move-out-of-the-root-file",
+ "working-rule"
+ ],
+ "locales": {
+ "ar": 4,
+ "de": 4,
+ "en": 4,
+ "es": 4,
+ "fr": 4,
+ "ja": 4,
+ "ko": 4,
+ "pt-BR": 4,
+ "ru": 4,
+ "tr": 4,
+ "uk": 4,
+ "uz": 4,
+ "vi": 4,
+ "zh": 4,
+ "zh-TW": 4
+ }
+ },
+ "resources/templates/AGENTS.md": {
+ "ids": [
+ "agents-md",
+ "startup-workflow",
+ "working-rules",
+ "required-artifacts",
+ "definition-of-done",
+ "end-of-session"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 6,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/templates/CLAUDE.md": {
+ "ids": [
+ "claude-md",
+ "operating-loop",
+ "rules",
+ "required-files",
+ "completion-gate",
+ "before-you-stop"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 6,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "resources/templates/claude-progress.md": {
+ "ids": [
+ "progress-log",
+ "current-verified-state",
+ "session-log",
+ "session-001",
+ "session-002"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/templates/clean-state-checklist.md": {
+ "ids": [
+ "clean-state-checklist"
+ ],
+ "locales": {
+ "ar": 1,
+ "de": 1,
+ "en": 1,
+ "es": 1,
+ "fr": 1,
+ "ja": 1,
+ "ko": 1,
+ "pt-BR": 1,
+ "ru": 1,
+ "tr": 1,
+ "uk": 1,
+ "uz": 1,
+ "vi": 1,
+ "zh": 1,
+ "zh-TW": 1
+ }
+ },
+ "resources/templates/evaluator-rubric.md": {
+ "ids": [
+ "evaluator-rubric",
+ "verdict",
+ "required-follow-up"
+ ],
+ "locales": {
+ "ar": 3,
+ "de": 3,
+ "en": 3,
+ "es": 3,
+ "fr": 3,
+ "ja": 3,
+ "ko": 3,
+ "pt-BR": 3,
+ "ru": 3,
+ "tr": 3,
+ "uk": 3,
+ "uz": 3,
+ "vi": 3,
+ "zh": 3,
+ "zh-TW": 3
+ }
+ },
+ "resources/templates/index.md": {
+ "ids": [
+ "template-guide",
+ "how-to-get-started",
+ "agents-md",
+ "init-sh",
+ "claude-progress-md",
+ "feature-list-json",
+ "session-handoff-md",
+ "clean-state-checklist-md",
+ "evaluator-rubric-md",
+ "quality-document-md"
+ ],
+ "locales": {
+ "ar": 7,
+ "de": 10,
+ "en": 10,
+ "es": 10,
+ "fr": 10,
+ "ja": 7,
+ "ko": 10,
+ "pt-BR": 10,
+ "ru": 10,
+ "tr": 10,
+ "uk": 10,
+ "uz": 10,
+ "vi": 2,
+ "zh": 10,
+ "zh-TW": 10
+ }
+ },
+ "resources/templates/quality-document.md": {
+ "ids": [
+ "quality-document",
+ "product-domains",
+ "architectural-layers",
+ "change-history",
+ "yyyy-mm-dd"
+ ],
+ "locales": {
+ "ar": 5,
+ "de": 5,
+ "en": 5,
+ "es": 5,
+ "fr": 5,
+ "ja": 5,
+ "ko": 5,
+ "pt-BR": 5,
+ "ru": 5,
+ "tr": 5,
+ "uk": 5,
+ "uz": 5,
+ "vi": 5,
+ "zh": 5,
+ "zh-TW": 5
+ }
+ },
+ "resources/templates/session-handoff.md": {
+ "ids": [
+ "session-handoff",
+ "verified-now",
+ "changed-this-session",
+ "broken-or-unverified",
+ "next-best-step",
+ "commands"
+ ],
+ "locales": {
+ "ar": 6,
+ "de": 6,
+ "en": 6,
+ "es": 6,
+ "fr": 5,
+ "ja": 6,
+ "ko": 6,
+ "pt-BR": 6,
+ "ru": 6,
+ "tr": 6,
+ "uk": 6,
+ "uz": 6,
+ "vi": 6,
+ "zh": 6,
+ "zh-TW": 6
+ }
+ },
+ "skills/index.md": {
+ "ids": [
+ "skills",
+ "harness-creator",
+ "what-it-does",
+ "quick-start",
+ "reference-patterns",
+ "templates",
+ "scripts",
+ "how-this-skill-was-built"
+ ],
+ "locales": {
+ "ar": 8,
+ "de": 8,
+ "en": 8,
+ "es": 8,
+ "fr": 8,
+ "ja": 8,
+ "ko": 8,
+ "pt-BR": 8,
+ "ru": 8,
+ "tr": 8,
+ "uk": 8,
+ "uz": 8,
+ "vi": 8,
+ "zh": 8,
+ "zh-TW": 8
+ }
+ }
+}
diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index d3be6ede..737bfb7f 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -1,6 +1,8 @@
///
import { defineConfig } from "vitepress";
import { withMermaid } from "vitepress-plugin-mermaid";
+import anchorMap from "./anchor-map.json";
+import { defaultSlugify } from "../../scripts/anchor-map-utils.ts";
const docsBase = "/learn-harness-engineering/";
const brandLogo = 'data:image/svg+xml;utf8,';
@@ -900,6 +902,28 @@ export default withMermaid(
socialLinks
},
markdown: {
+ anchor: {
+ // Heading ids are auto-slugged from heading text, so each locale would
+ // otherwise get ids in its own language. The language switcher carries
+ // the URL hash across locales, so a shared "#實際案例" link dead-ends
+ // after switching to English. Apply the English ids everywhere, keeping
+ // heading text translated: the same convention vitepress.dev uses.
+ //
+ // Only applied where the locale's heading count matches English; a page
+ // whose structure has drifted keeps its localized ids rather than
+ // getting ids that point at the wrong section.
+ slugifyWithState(source: string, state: any) {
+ const [locale, ...rest] = String(state.env.relativePath ?? '').split('/')
+ const page = (anchorMap as Record }>)[
+ rest.join('/')
+ ]
+ if (page && page.locales[locale] === page.ids.length) {
+ const index = (state.env.__anchorIndex = (state.env.__anchorIndex ?? -1) + 1)
+ if (page.ids[index]) return page.ids[index]
+ }
+ return defaultSlugify(source)
+ },
+ },
theme: {
light: 'github-light',
dark: 'github-dark'
diff --git a/package.json b/package.json
index 5891609f..887f14b6 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,8 @@
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs",
"lecture:run": "tsx",
+ "anchors:build": "node --import tsx scripts/build-anchor-map.ts",
+ "anchors:check": "node --import tsx scripts/validate-anchors.ts",
"screenshots:readme": "node --import tsx scripts/capture-readme-screenshots.ts",
"pdf:export": "node --import tsx scripts/build-course-pdfs.ts",
"pdf:build": "npm run docs:build && npm run pdf:export"
diff --git a/scripts/anchor-map-utils.ts b/scripts/anchor-map-utils.ts
new file mode 100644
index 00000000..fbcdea65
--- /dev/null
+++ b/scripts/anchor-map-utils.ts
@@ -0,0 +1,67 @@
+// Heading-id helpers shared by the anchor-map generator, the VitePress config,
+// and the anchor validator.
+//
+// The slugifier below is a transcription of VitePress's default
+// (node_modules/vitepress/dist/node/chunk-D3CUZ4fa.js). It is deliberately not
+// github-slugger, which is declared in package.json but unused: the two disagree
+// on underscores ("foo_bar" -> "foo-bar" vs "foo_bar") and on leading digits
+// ("1. Getting Started" -> "_1-getting-started" vs "1-getting-started").
+
+const rControl = new RegExp('[\\u0000-\\u001f]', 'g')
+const rCombining = new RegExp('[\\u0300-\\u036f]', 'g')
+const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g
+
+export function defaultSlugify(input: string): string {
+ return input
+ .normalize('NFKD')
+ .replace(rCombining, '')
+ .replace(rControl, '')
+ .replace(rSpecial, '-')
+ .replace(/-{2,}/g, '-')
+ .replace(/^-+|-+$/g, '')
+ .replace(/^(\d)/, '_$1')
+ .toLowerCase()
+}
+
+export function localeStrippedPath(relativePath: string): string {
+ return relativePath.replace(/^[^/]+\//, '')
+}
+
+// Heading levels that get anchor ids. VitePress's anchor plugin defaults to
+// level 1, and its unique-slug counter starts at the H1, so ids must be
+// collected from level 1 or every index shifts.
+export const MAX_ANCHOR_LEVEL = 3
+
+// Fence-aware: parse with the real renderer rather than matching /^##/ , which
+// counts pseudo-headings inside ```markdown blocks (lecture-04 has 9 real
+// headings and 12 by naive regex).
+export function collectHeadingIds(md: any, source: string): string[] {
+ const tokens = md.parse(source, {})
+ const ids: string[] = []
+ // markdown-it-anchor keeps a set of taken ids and suffixes collisions with a
+ // per-slug counter: "dup", "dup-1", "dup-2".
+ const taken = new Set()
+
+ for (let i = 0; i < tokens.length; i++) {
+ const token = tokens[i]
+ if (token.type !== 'heading_open') continue
+
+ const level = Number(token.tag.slice(1))
+ if (level > MAX_ANCHOR_LEVEL) continue
+
+ const title = tokens[i + 1]?.content ?? ''
+ const base = defaultSlugify(title)
+
+ let candidate = base
+ let suffix = 1
+ while (taken.has(candidate)) {
+ candidate = `${base}-${suffix}`
+ suffix++
+ }
+
+ taken.add(candidate)
+ ids.push(candidate)
+ }
+
+ return ids
+}
diff --git a/scripts/build-anchor-map.ts b/scripts/build-anchor-map.ts
new file mode 100644
index 00000000..b931c909
--- /dev/null
+++ b/scripts/build-anchor-map.ts
@@ -0,0 +1,105 @@
+// Generates docs/.vitepress/anchor-map.json.
+//
+// Heading ids are auto-slugged from heading text, so every locale gets ids in
+// its own language. The language switcher carries the URL hash across locales
+// (vitepress/dist/client/theme-default/composables/langs.js appends hash.value
+// unconditionally), so a shared link such as "#實際案例" dead-ends after
+// switching to English.
+//
+// This script records the English ids as canonical so the VitePress config can
+// apply them to every locale, matching how vitepress.dev itself behaves: ids are
+// locale-invariant, heading text is translated.
+//
+// Run from the repo root: node --import tsx scripts/build-anchor-map.ts
+
+import path from 'node:path'
+import { promises as fs } from 'node:fs'
+import { createMarkdownRenderer } from 'vitepress'
+import { collectHeadingIds, localeStrippedPath } from './anchor-map-utils.ts'
+import { docsRoot } from './export-site-utils.ts'
+
+const anchorMapPath = path.resolve(docsRoot, '.vitepress/anchor-map.json')
+
+export type AnchorMapEntry = {
+ // Canonical ids in document order, covering heading levels 1..3.
+ ids: string[]
+ // Heading count per locale, so the validator can tell an intentionally
+ // unanchored page (structure drift) from a regression.
+ locales: Record
+}
+
+export type AnchorMap = Record
+
+const SOURCE_LOCALE = 'en'
+
+async function listLocales(): Promise {
+ const entries = await fs.readdir(docsRoot, { withFileTypes: true })
+ return entries
+ .filter((entry) => entry.isDirectory() && entry.name !== 'public' && entry.name !== '.vitepress')
+ .map((entry) => entry.name)
+ .sort()
+}
+
+async function walkMarkdown(targetDir: string): Promise {
+ const entries = await fs.readdir(targetDir, { withFileTypes: true })
+ const nested = await Promise.all(
+ entries.map(async (entry) => {
+ const full = path.join(targetDir, entry.name)
+ if (entry.isDirectory()) return walkMarkdown(full)
+ return entry.isFile() && entry.name.endsWith('.md') ? [full] : []
+ }),
+ )
+ return nested.flat()
+}
+
+async function main() {
+ const md = await createMarkdownRenderer(docsRoot, {}, '/')
+ const locales = await listLocales()
+
+ if (!locales.includes(SOURCE_LOCALE)) {
+ throw new Error(`Source locale "${SOURCE_LOCALE}" not found under ${docsRoot}`)
+ }
+
+ const anchorMap: AnchorMap = {}
+ const sourceFiles = (await walkMarkdown(path.join(docsRoot, SOURCE_LOCALE))).sort()
+ const sourceKeys = new Set()
+
+ for (const file of sourceFiles) {
+ const relativePath = path.relative(docsRoot, file).split(path.sep).join('/')
+ const key = localeStrippedPath(relativePath)
+ const ids = collectHeadingIds(md, await fs.readFile(file, 'utf8'))
+
+ if (ids.length === 0) continue
+ sourceKeys.add(key)
+ anchorMap[key] = { ids, locales: {} }
+ }
+
+ // Record how many headings each locale actually has, so the config applies the
+ // canonical ids only where the structure lines up.
+ for (const locale of locales) {
+ const files = await walkMarkdown(path.join(docsRoot, locale))
+ for (const file of files) {
+ const key = localeStrippedPath(path.relative(docsRoot, file).split(path.sep).join('/'))
+ if (!sourceKeys.has(key)) continue
+ const ids = collectHeadingIds(md, await fs.readFile(file, 'utf8'))
+ anchorMap[key].locales[locale] = ids.length
+ }
+ }
+
+ await fs.writeFile(anchorMapPath, `${JSON.stringify(anchorMap, null, 2)}\n`, 'utf8')
+
+ const pages = Object.keys(anchorMap).length
+ const aligned = Object.values(anchorMap).filter((entry) =>
+ Object.entries(entry.locales).every(([, count]) => count === entry.ids.length),
+ ).length
+
+ console.log(`Wrote ${path.relative(process.cwd(), anchorMapPath)}`)
+ console.log(` pages: ${pages}`)
+ console.log(` all-locales-aligned: ${aligned}`)
+ console.log(` with drift: ${pages - aligned}`)
+}
+
+main().catch((error) => {
+ console.error(error)
+ process.exitCode = 1
+})
diff --git a/scripts/validate-anchors.ts b/scripts/validate-anchors.ts
new file mode 100644
index 00000000..ba1b2f30
--- /dev/null
+++ b/scripts/validate-anchors.ts
@@ -0,0 +1,109 @@
+// Checks that docs/.vitepress/anchor-map.json is in sync with the English source.
+//
+// Heading ids are canonical English slugs applied to every locale, so the map
+// must be regenerated whenever English headings change:
+//
+// npm run anchors:build # after editing any English heading
+// npm run anchors:check # fails if the map is stale; runs in CI
+//
+// Editing rules that keep cross-language anchor links working:
+//
+// - Ids are matched by position, not by heading text. Translated titles are
+// free; what must line up with English is the number and order of headings.
+// - Reordering sections without changing the count is not detected here. It
+// would silently mis-map ids, so reorder English and the locale together.
+//
+// 15 pages have known structure drift and intentionally keep localized ids:
+// lecture-11 and lecture-12 in 9 locales each (ar, de, es, fr, ja, ko, ru, tr,
+// uz), project-01 in 13, projects 02-06 in zh/zh-TW, six resources pages
+// (openai-advanced, reference, templates, plus two repo-template files), and
+// harness-designs/codex in zh. Cross-language anchor links do not resolve on
+// those pages. This is not a bug to fix: the translations are structurally
+// different documents, and for the project pages the Chinese is more complete
+// than the English stub. They are reported below as a note and do not fail.
+//
+// Run from the repo root: node --import tsx scripts/validate-anchors.ts
+
+import { promises as fs } from 'node:fs'
+import { readFileSync } from 'node:fs'
+import { createMarkdownRenderer } from 'vitepress'
+import { collectHeadingIds, localeStrippedPath } from './anchor-map-utils.ts'
+import { docsRoot } from './export-site-utils.ts'
+
+const anchorMapPath = `${docsRoot}/.vitepress/anchor-map.json`
+const SOURCE_LOCALE = 'en'
+
+type Finding = {
+ docPath: string
+ message: string
+}
+
+async function walkMarkdown(targetDir: string): Promise {
+ const entries = await fs.readdir(targetDir, { withFileTypes: true })
+ const nested = await Promise.all(
+ entries.map(async (entry) => {
+ const full = `${targetDir}/${entry.name}`
+ if (entry.isDirectory()) return walkMarkdown(full)
+ return entry.isFile() && entry.name.endsWith('.md') ? [full] : []
+ }),
+ )
+ return nested.flat()
+}
+
+async function main() {
+ const md = await createMarkdownRenderer(docsRoot, {}, '/')
+ const anchorMap = JSON.parse(readFileSync(anchorMapPath, 'utf8')) as Record<
+ string,
+ { ids: string[]; locales: Record }
+ >
+
+ const findings: Finding[] = []
+ const drifted: Finding[] = []
+
+ const sourceFiles = (await walkMarkdown(`${docsRoot}/${SOURCE_LOCALE}`)).sort()
+
+ for (const file of sourceFiles) {
+ const key = localeStrippedPath(file.slice(docsRoot.length + 1).split('\\').join('/'))
+ const ids = collectHeadingIds(md, await fs.readFile(file, 'utf8'))
+ if (ids.length === 0) continue
+
+ const entry = anchorMap[key]
+ if (!entry) {
+ findings.push({ docPath: key, message: `missing from anchor-map.json (${ids.length} headings)` })
+ continue
+ }
+
+ if (JSON.stringify(entry.ids) !== JSON.stringify(ids)) {
+ findings.push({ docPath: key, message: 'canonical ids are stale; run scripts/build-anchor-map.ts' })
+ }
+ }
+
+ for (const [key, entry] of Object.entries(anchorMap)) {
+ for (const [locale, count] of Object.entries(entry.locales)) {
+ if (count !== entry.ids.length) {
+ drifted.push({
+ docPath: key,
+ message: `${locale} has ${count} headings, English has ${entry.ids.length}; keeps localized ids`,
+ })
+ }
+ }
+ }
+
+ if (findings.length > 0) {
+ console.error(`Anchor map is out of date (${findings.length}):`)
+ for (const finding of findings) console.error(`- ${finding.docPath}: ${finding.message}`)
+ process.exitCode = 1
+ return
+ }
+
+ console.log(`OK: anchor map matches the English source (${Object.keys(anchorMap).length} pages).`)
+ if (drifted.length > 0) {
+ const pages = new Set(drifted.map((d) => d.docPath)).size
+ console.log(`Note: ${pages} page(s) have locale structure drift; those locales keep localized ids.`)
+ }
+}
+
+main().catch((error) => {
+ console.error(error)
+ process.exitCode = 1
+})