From eb6861311c2231faa6a78eb8de53a4cc4521bffd Mon Sep 17 00:00:00 2001 From: Dieter Baier Date: Sun, 12 Jul 2026 10:39:02 +0200 Subject: [PATCH 1/3] Add thin toolkit-routing agent adapters Add scripts/build-agent-adapters.js and check-agent-adapters.js that generate thin Codex/Vibe/GitHub Copilot/Cursor adapters routing to the architecture-knowledge-toolkit (no local skills). Wire adapters/check-adapters/test into build.sh and the CI validate job, turn .github/copilot-instructions.md into a thin entry point, and document the reference-don't-copy principle in AGENTS.md and general-semantic-contracts.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/copilot-instructions.md | 25 ++- .github/workflows/architecture-docs.yml | 6 + AGENTS.md | 27 +++ README.md | 9 + adapters/codex/AGENTS.md | 29 +++ adapters/cursor/rules/docs-toolbox.mdc | 33 ++++ .../github-copilot/copilot-instructions.md | 29 +++ adapters/vibe/AGENTS.md | 29 +++ build.sh | 34 +++- general-semantic-contracts.md | 16 +- scripts/build-agent-adapters.js | 185 ++++++++++++++++++ scripts/check-agent-adapters.js | 7 + test/build-agent-adapters.test.mjs | 104 ++++++++++ 13 files changed, 510 insertions(+), 23 deletions(-) create mode 100644 adapters/codex/AGENTS.md create mode 100644 adapters/cursor/rules/docs-toolbox.mdc create mode 100644 adapters/github-copilot/copilot-instructions.md create mode 100644 adapters/vibe/AGENTS.md create mode 100644 scripts/build-agent-adapters.js create mode 100644 scripts/check-agent-adapters.js create mode 100644 test/build-agent-adapters.test.mjs diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 9143d0e..523a02a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,21 +1,18 @@ # Repository Instructions For GitHub Copilot -Follow the project `AGENTS.md`. +This file is a GitHub Copilot entry point only. Keep GitHub Copilot-specific +integration guidance under `adapters/github-copilot/` and keep reusable +architecture and SDLC semantics in the architecture-knowledge-toolkit. -This project uses architecture-knowledge-toolkit for architecture documentation, -ADRs, quality scenarios, risks, traceability metadata, templates, validators, -generated include fragments, and SDLC task workflows that are not described more -specifically in this repository. +Follow repository-root `adapters/github-copilot/copilot-instructions.md`, then +the contract hierarchy in repository-root `AGENTS.md` and +`general-semantic-contracts.md`. -Use the toolkit repository as source of truth when local toolkit files are missing: +Use the toolkit repository as source of truth when local toolkit files are +missing: https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit -For architecture-related or SDLC workflow changes: - -- prefer small, reviewable changes -- preserve stable IDs -- keep AI-generated or AI-modified architecture content in `draft` or `proposed` state unless reviewed -- do not manually maintain generated fragments -- consult the relevant toolkit skill before issue slicing, issue implementation, commit message, pull request review, post-merge synchronization, ADR, quality scenario, risk, or traceability-review work when local instructions are missing -- do not introduce Copilot-specific rules into engine-independent toolkit files +Do not duplicate architecture, ADR, quality scenario, risk, traceability, +metadata, arc42, or SDLC rules here. Add durable rules to the canonical toolkit +source instead. diff --git a/.github/workflows/architecture-docs.yml b/.github/workflows/architecture-docs.yml index 4363a02..4decc36 100644 --- a/.github/workflows/architecture-docs.yml +++ b/.github/workflows/architecture-docs.yml @@ -24,6 +24,12 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Check agent adapters + run: ./build.sh check-adapters + + - name: Test agent adapter generator + run: ./build.sh test + - name: Build architecture HTML run: ./build.sh build diff --git a/AGENTS.md b/AGENTS.md index 32d02d0..3e32145 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,3 +38,30 @@ Before architecture or SDLC workflow work: - set `reviewed: false` unless human acceptance is already recorded - do not manually maintain generated fragments when a generator exists - copy missing toolkit templates, schemas, validators, and generator scripts from the toolkit instead of inventing alternatives + +## Reference, Don't Copy + +Treat the architecture-knowledge-toolkit as the single source of truth for +architecture skills, contracts, and features. Do not copy toolkit +`skills/**/SKILL.md`, `features/`, or contract text into this repository; +resolve them from the toolkit through the lookup order above. Only executable +tooling that must run here — metamodel schemas under `metamodel/`, templates +under `templates/`, and validator/generator scripts under `scripts/` — is copied +or vendored and kept in sync with the toolkit. + +This repository has no local architecture skills of its own. It references the +toolkit for all architecture and SDLC work and generates thin adapters that +route agents to it. If a project-specific skill is ever added, it must extend +the toolkit or explicitly override a specific rule, never silently duplicate it. + +## Agent Adapters + +This repository keeps no local agent skills; it routes agents to the +architecture-knowledge-toolkit. The thin routing wrappers under `adapters/` +(`adapters/codex/AGENTS.md`, `adapters/vibe/AGENTS.md`, +`adapters/github-copilot/copilot-instructions.md`, and +`adapters/cursor/rules/docs-toolbox.mdc`) are generated by +`scripts/build-agent-adapters.js`. Do not edit them by hand; change the +generator and run `./build.sh adapters`. CI runs `./build.sh check-adapters` +to fail on stale adapters. Keep `.github/copilot-instructions.md` as an entry +point only that points back to `adapters/github-copilot/copilot-instructions.md`. diff --git a/README.md b/README.md index 9e08f33..61dd7fe 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,15 @@ image from the current Dockerfile if that exact image does not exist. ./build.sh build ``` +It also generates the thin agent adapters that route AI agents (Codex, Vibe, +GitHub Copilot, Cursor) to the architecture-knowledge-toolkit: + +```bash +./build.sh adapters # regenerate adapters under adapters/ +./build.sh check-adapters # fail if the generated adapters are stale +./build.sh test # run the adapter generator behaviour tests +``` + ### GitHub Actions (example) ```yaml diff --git a/adapters/codex/AGENTS.md b/adapters/codex/AGENTS.md new file mode 100644 index 0000000..d2d03a4 --- /dev/null +++ b/adapters/codex/AGENTS.md @@ -0,0 +1,29 @@ + +# Codex Adapter + +This is a thin Codex-specific wrapper for the docs-toolbox +repository. docs-toolbox keeps no local agent skills of its own; architecture and +software-development-lifecycle semantics are delegated to the +architecture-knowledge-toolkit. + +When Codex performs architecture-sensitive or SDLC work in this +repository: + +1. Read repository-root `AGENTS.md`. +2. Read repository-root `general-semantic-contracts.md`. +3. Follow the toolkit lookup order in `AGENTS.md`, then read the relevant + canonical `skills/**/SKILL.md` from the architecture-knowledge-toolkit. +4. Treat this adapter as routing guidance only. + +## Toolkit Source Of Truth + +Prefer local toolkit files when present; otherwise use the public repository: + +https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit + +## Adapter Boundary + +Do not duplicate architecture, ADR, quality scenario, risk, traceability, +metadata, or arc42 rules here. Agent-specific files may only wrap, point to, or +invoke the canonical toolkit sources and repository-root +`general-semantic-contracts.md`. diff --git a/adapters/cursor/rules/docs-toolbox.mdc b/adapters/cursor/rules/docs-toolbox.mdc new file mode 100644 index 0000000..8e632fd --- /dev/null +++ b/adapters/cursor/rules/docs-toolbox.mdc @@ -0,0 +1,33 @@ +--- +description: docs-toolbox adapter +alwaysApply: true +--- + +# Cursor Rule + +This is a thin Cursor-specific wrapper for the docs-toolbox +repository. docs-toolbox keeps no local agent skills of its own; architecture and +software-development-lifecycle semantics are delegated to the +architecture-knowledge-toolkit. + +When Cursor performs architecture-sensitive or SDLC work in this +repository: + +1. Read repository-root `AGENTS.md`. +2. Read repository-root `general-semantic-contracts.md`. +3. Follow the toolkit lookup order in `AGENTS.md`, then read the relevant + canonical `skills/**/SKILL.md` from the architecture-knowledge-toolkit. +4. Treat this adapter as routing guidance only. + +## Toolkit Source Of Truth + +Prefer local toolkit files when present; otherwise use the public repository: + +https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit + +## Adapter Boundary + +Do not duplicate architecture, ADR, quality scenario, risk, traceability, +metadata, or arc42 rules here. Agent-specific files may only wrap, point to, or +invoke the canonical toolkit sources and repository-root +`general-semantic-contracts.md`. diff --git a/adapters/github-copilot/copilot-instructions.md b/adapters/github-copilot/copilot-instructions.md new file mode 100644 index 0000000..bab075e --- /dev/null +++ b/adapters/github-copilot/copilot-instructions.md @@ -0,0 +1,29 @@ + +# GitHub Copilot Adapter + +This is a thin GitHub Copilot-specific wrapper for the docs-toolbox +repository. docs-toolbox keeps no local agent skills of its own; architecture and +software-development-lifecycle semantics are delegated to the +architecture-knowledge-toolkit. + +When GitHub Copilot performs architecture-sensitive or SDLC work in this +repository: + +1. Read repository-root `AGENTS.md`. +2. Read repository-root `general-semantic-contracts.md`. +3. Follow the toolkit lookup order in `AGENTS.md`, then read the relevant + canonical `skills/**/SKILL.md` from the architecture-knowledge-toolkit. +4. Treat this adapter as routing guidance only. + +## Toolkit Source Of Truth + +Prefer local toolkit files when present; otherwise use the public repository: + +https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit + +## Adapter Boundary + +Do not duplicate architecture, ADR, quality scenario, risk, traceability, +metadata, or arc42 rules here. Agent-specific files may only wrap, point to, or +invoke the canonical toolkit sources and repository-root +`general-semantic-contracts.md`. diff --git a/adapters/vibe/AGENTS.md b/adapters/vibe/AGENTS.md new file mode 100644 index 0000000..97d55d7 --- /dev/null +++ b/adapters/vibe/AGENTS.md @@ -0,0 +1,29 @@ + +# Vibe Adapter + +This is a thin Vibe-specific wrapper for the docs-toolbox +repository. docs-toolbox keeps no local agent skills of its own; architecture and +software-development-lifecycle semantics are delegated to the +architecture-knowledge-toolkit. + +When Vibe performs architecture-sensitive or SDLC work in this +repository: + +1. Read repository-root `AGENTS.md`. +2. Read repository-root `general-semantic-contracts.md`. +3. Follow the toolkit lookup order in `AGENTS.md`, then read the relevant + canonical `skills/**/SKILL.md` from the architecture-knowledge-toolkit. +4. Treat this adapter as routing guidance only. + +## Toolkit Source Of Truth + +Prefer local toolkit files when present; otherwise use the public repository: + +https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit + +## Adapter Boundary + +Do not duplicate architecture, ADR, quality scenario, risk, traceability, +metadata, or arc42 rules here. Agent-specific files may only wrap, point to, or +invoke the canonical toolkit sources and repository-root +`general-semantic-contracts.md`. diff --git a/build.sh b/build.sh index 1f841ef..0e37e0c 100755 --- a/build.sh +++ b/build.sh @@ -8,12 +8,15 @@ SOURCE_DOC="${SOURCE_DOC:-src/docs/doc-001-arc42.adoc}" usage() { cat <<'USAGE' -Usage: ./build.sh [build|validate|clean] +Usage: ./build.sh [build|validate|adapters|check-adapters|test|clean] Commands: - build Validate, generate architecture fragments, and render HTML. - validate Validate and generate architecture documentation metadata. - clean Remove local architecture build output. + build Validate, generate architecture fragments, and render HTML. + validate Validate and generate architecture documentation metadata. + adapters Regenerate the thin agent adapters under adapters/. + check-adapters Fail if the generated agent adapters are out of date. + test Run the agent adapter generator behaviour tests. + clean Remove local architecture build output. The script prefers a published docs-toolbox image tagged with the local Dockerfile hash (df-). If that image is not available, it builds a local @@ -43,6 +46,18 @@ run_validate() { ruby scripts/validate-metamodel.rb --generate } +run_adapters() { + node scripts/build-agent-adapters.js +} + +run_check_adapters() { + node scripts/check-agent-adapters.js +} + +run_test() { + node --test test/build-agent-adapters.test.mjs +} + run_build() { run_validate mkdir -p "$BUILD_DIR" @@ -67,6 +82,15 @@ run_local() { validate) run_validate ;; + adapters) + run_adapters + ;; + check-adapters) + run_check_adapters + ;; + test) + run_test + ;; clean) rm -rf "$BUILD_DIR" echo "Removed $BUILD_DIR" @@ -115,7 +139,7 @@ if [ "${DOCS_TOOLBOX_IN_CONTAINER:-}" = "1" ]; then fi case "$COMMAND" in - build|validate) + build|validate|adapters|check-adapters|test) ENGINE="$(find_engine)" if [ -n "$ENGINE" ]; then run_in_container "$ENGINE" diff --git a/general-semantic-contracts.md b/general-semantic-contracts.md index d011571..396fcc2 100644 --- a/general-semantic-contracts.md +++ b/general-semantic-contracts.md @@ -9,16 +9,19 @@ instructions, workflow definitions, source code, tests, and reviewed architecture records are evidence. AI-created architecture content is draft or proposed until reviewed by the accountable owner. -For missing guidance, use the toolkit lookup order in `AGENTS.md`. Do not copy -the full toolkit rule set into this repository; keep this file as the local -semantic entry point and let the toolkit remain the maintained source. +For missing guidance, use the toolkit lookup order in `AGENTS.md`. Reference, +don't copy: do not copy toolkit `skills/**/SKILL.md`, `features/`, or contract +text into this repository. Only executable tooling that must run here — metamodel +schemas, templates, and validator/generator scripts — is copied or vendored and +kept in sync with the toolkit. Keep this file as the local semantic entry point +and let the toolkit remain the maintained source. Project-local facts currently supported by repository evidence: - The product is a Docker image named `docs-toolbox`. - The image supports reproducible Docs-as-Code pipelines locally and in CI. - The Dockerfile uses `openjdk:22-jdk-slim`. -- The image installs Asciidoctor, Pandoc, Graphviz, unzip, curl, and Python 3. +- The image installs Asciidoctor, Pandoc, Graphviz, unzip, curl, Python 3, and Node.js (with npm). - GitHub Actions builds and pushes multi-platform images to GHCR. - Tags include a Dockerfile hash tag and, for Git-tagged commits, the Git tag and `latest`. - The project is MIT licensed. @@ -26,3 +29,8 @@ Project-local facts currently supported by repository evidence: Architecture documentation in this repository is under `src/docs/` and follows the toolkit metamodel. Generated files under `generated/` directories are derived output and must not be edited manually. + +Agent adapters under `adapters/` are thin, toolkit-routing wrappers generated by +`scripts/build-agent-adapters.js`. They are derived output: do not edit them by +hand. Regenerate with `./build.sh adapters` and verify with +`./build.sh check-adapters`. diff --git a/scripts/build-agent-adapters.js b/scripts/build-agent-adapters.js new file mode 100644 index 0000000..583a6df --- /dev/null +++ b/scripts/build-agent-adapters.js @@ -0,0 +1,185 @@ +#!/usr/bin/env node + +// docs-toolbox keeps no local agent skills of its own. It delegates architecture +// and software-development-lifecycle semantics to the +// architecture-knowledge-toolkit. This generator therefore emits thin, +// toolkit-routing adapters. If local skills are ever added under skills/, they +// are listed as well, so the generator stays aligned with the toolkit template. + +async function main() { + const fs = await import("fs"); + const path = await import("path"); + const scriptDir = path.default.dirname(path.default.resolve(process.argv[1])); + const root = path.default.resolve(scriptDir, ".."); + + const project = "docs-toolbox"; + const toolkitUrl = + "https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit"; + + const generatedNotice = [ + "", + "", + ].join("\n"); + const defaultWrap = (body) => `${generatedNotice}${body}`; + + const targets = [ + { + path: "adapters/codex/AGENTS.md", + title: "Codex Adapter", + agent: "Codex", + wrap: defaultWrap, + }, + { + path: "adapters/vibe/AGENTS.md", + title: "Vibe Adapter", + agent: "Vibe", + wrap: defaultWrap, + }, + { + path: "adapters/github-copilot/copilot-instructions.md", + title: "GitHub Copilot Adapter", + agent: "GitHub Copilot", + wrap: defaultWrap, + }, + { + path: `adapters/cursor/rules/${project}.mdc`, + title: "Cursor Rule", + agent: "Cursor", + wrap: (body) => `--- +description: ${project} adapter +alwaysApply: true +--- +${generatedNotice}${body}`, + }, + ]; + + function usage() { + console.error("Usage: node scripts/build-agent-adapters.js [--check]"); + } + + function listSkillFiles() { + const skillsDir = path.default.join(root, "skills"); + if (!fs.default.existsSync(skillsDir)) { + return []; + } + return fs.default + .readdirSync(skillsDir, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => path.default.join("skills", entry.name, "SKILL.md")) + .filter((skillPath) => fs.default.existsSync(path.default.join(root, skillPath))) + .sort(); + } + + function parseSkill(skillPath) { + const text = fs.default.readFileSync(path.default.join(root, skillPath), "utf8"); + const match = text.match(/^---\n([\s\S]*?)\n---\n/); + const meta = {}; + + if (match) { + for (const line of match[1].split(/\r?\n/)) { + const field = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/); + if (field) { + meta[field[1]] = field[2].replace(/^["']|["']$/g, ""); + } + } + } + + return { + path: skillPath, + name: meta.name || path.default.basename(path.default.dirname(skillPath)), + adapterExpose: meta.adapter_expose !== "false", + }; + } + + function renderTarget(target, skills) { + const localSkillsSection = + skills.length > 0 + ? `\n## Local Skills + +Paths are relative to the ${project} repository root. + +${skills.map((skill) => `- \`${skill.name}\`: \`${skill.path}\``).join("\n")} +` + : ""; + + const body = `# ${target.title} + +This is a thin ${target.agent}-specific wrapper for the ${project} +repository. ${project} keeps no local agent skills of its own; architecture and +software-development-lifecycle semantics are delegated to the +architecture-knowledge-toolkit. + +When ${target.agent} performs architecture-sensitive or SDLC work in this +repository: + +1. Read repository-root \`AGENTS.md\`. +2. Read repository-root \`general-semantic-contracts.md\`. +3. Follow the toolkit lookup order in \`AGENTS.md\`, then read the relevant + canonical \`skills/**/SKILL.md\` from the architecture-knowledge-toolkit. +4. Treat this adapter as routing guidance only. +${localSkillsSection} +## Toolkit Source Of Truth + +Prefer local toolkit files when present; otherwise use the public repository: + +${toolkitUrl} + +## Adapter Boundary + +Do not duplicate architecture, ADR, quality scenario, risk, traceability, +metadata, or arc42 rules here. Agent-specific files may only wrap, point to, or +invoke the canonical toolkit sources and repository-root +\`general-semantic-contracts.md\`. +`; + + return target.wrap(body); + } + + const args = process.argv.slice(2); + const check = args.includes("--check"); + const unknown = args.filter((arg) => arg !== "--check"); + if (unknown.length > 0) { + usage(); + process.exit(2); + } + + const skills = listSkillFiles().map(parseSkill).filter((skill) => skill.adapterExpose); + const stale = []; + + for (const target of targets) { + const targetPath = path.default.join(root, target.path); + const expected = renderTarget(target, skills); + const actual = fs.default.existsSync(targetPath) + ? fs.default.readFileSync(targetPath, "utf8") + : null; + + if (check) { + if (actual !== expected) { + stale.push(target.path); + } + continue; + } + + fs.default.mkdirSync(path.default.dirname(targetPath), { recursive: true }); + fs.default.writeFileSync(targetPath, expected); + console.log(`wrote ${target.path}`); + } + + if (check && stale.length > 0) { + console.error("Generated agent adapters are stale:"); + for (const file of stale) { + console.error(` - ${file}`); + } + console.error("Run: node scripts/build-agent-adapters.js"); + process.exit(1); + } + + if (check) { + console.log("Generated agent adapters are current."); + } +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/scripts/check-agent-adapters.js b/scripts/check-agent-adapters.js new file mode 100644 index 0000000..2810953 --- /dev/null +++ b/scripts/check-agent-adapters.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node + +process.argv = [process.argv[0], process.argv[1], "--check"]; +import("./build-agent-adapters.js").catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/test/build-agent-adapters.test.mjs b/test/build-agent-adapters.test.mjs new file mode 100644 index 0000000..ccd9c7a --- /dev/null +++ b/test/build-agent-adapters.test.mjs @@ -0,0 +1,104 @@ +// Behaviour specification for the agent adapter generator. +// +// docs-toolbox emits thin, toolkit-routing adapters and keeps no local skills. +// node:test is a classic test runner, so each scenario name reads like a +// requirement and Given/When/Then comment anchors separate Arrange, Act, and +// Assert. Each test runs against an isolated copy of scripts/ and adapters/ in a +// temporary workspace so the real repository tree is never modified. + +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +const ADAPTERS = [ + "adapters/codex/AGENTS.md", + "adapters/vibe/AGENTS.md", + "adapters/github-copilot/copilot-instructions.md", + "adapters/cursor/rules/docs-toolbox.mdc", +]; + +function makeWorkspace(t) { + const workspace = fs.mkdtempSync(path.join(os.tmpdir(), "docs-toolbox-adapters-")); + t.after(() => fs.rmSync(workspace, { recursive: true, force: true })); + for (const dir of ["scripts", "adapters"]) { + fs.cpSync(path.join(repoRoot, dir), path.join(workspace, dir), { recursive: true }); + } + return workspace; +} + +function runGenerator(workspace, args = []) { + return spawnSync( + process.execPath, + [path.join(workspace, "scripts/build-agent-adapters.js"), ...args], + { encoding: "utf8" }, + ); +} + +test("Build regenerates all four adapters and routes to the toolkit", (t) => { + // Given: a repository with no generated adapters + const workspace = makeWorkspace(t); + for (const adapter of ADAPTERS) { + fs.rmSync(path.join(workspace, adapter), { force: true }); + } + + // When: the adapter generator runs + const result = runGenerator(workspace); + + // Then: it writes all four adapters, each routing to the toolkit and carrying + // the generated-file notice + assert.equal(result.status, 0, result.stderr); + for (const adapter of ADAPTERS) { + const adapterPath = path.join(workspace, adapter); + assert.ok(fs.existsSync(adapterPath), `expected ${adapter} to be written`); + const text = fs.readFileSync(adapterPath, "utf8"); + assert.match(text, /GENERATED FILE: edit scripts\/build-agent-adapters\.js/); + assert.match(text, /architecture-knowledge-toolkit/); + } +}); + +test("Adapters list no local skills when the repository has none", (t) => { + // Given: a repository whose adapters were just generated and that has no skills/ + const workspace = makeWorkspace(t); + runGenerator(workspace); + + // When: the codex adapter is read + const codex = fs.readFileSync(path.join(workspace, "adapters/codex/AGENTS.md"), "utf8"); + + // Then: it contains no Local Skills section + assert.doesNotMatch(codex, /## Local Skills/); +}); + +test("Check reports adapters are current on a clean tree", (t) => { + // Given: a repository whose adapters were just generated + const workspace = makeWorkspace(t); + runGenerator(workspace); + + // When: the adapter generator runs in check mode + const result = runGenerator(workspace, ["--check"]); + + // Then: it exits successfully and reports that the adapters are current + assert.equal(result.status, 0, result.stderr); + assert.match(result.stdout, /Generated agent adapters are current\./); +}); + +test("Check detects a stale adapter", (t) => { + // Given: a repository whose generated adapter was edited by hand + const workspace = makeWorkspace(t); + runGenerator(workspace); + const codex = path.join(workspace, "adapters/codex/AGENTS.md"); + fs.appendFileSync(codex, "\nhand-edited drift\n"); + + // When: the adapter generator runs in check mode + const result = runGenerator(workspace, ["--check"]); + + // Then: it exits with a failure and names the stale adapter + assert.equal(result.status, 1); + assert.match(result.stderr, /stale/); + assert.match(result.stderr, /adapters\/codex\/AGENTS\.md/); +}); From 74dbecbe2182790daca20b47e74a0478f3511bfd Mon Sep 17 00:00:00 2001 From: Dieter Baier Date: Sun, 12 Jul 2026 10:53:10 +0200 Subject: [PATCH 2/3] Search upward for a local toolkit checkout Do not assume the architecture-knowledge-toolkit is a direct sibling. The local lookup order now searches ../architecture-knowledge-toolkit and then each parent directory up to the filesystem root, so projects outside the toolkit's parent folder still resolve it before the public fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3e32145..e178baa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,8 +23,12 @@ https://github.com/docs-as-code-toolkit/architecture-knowledge-toolkit Preferred local lookup order: -1. `$ARCHITECTURE_KNOWLEDGE_TOOLKIT` -2. `../architecture-knowledge-toolkit` +1. `$ARCHITECTURE_KNOWLEDGE_TOOLKIT` if it is set +2. otherwise the nearest local `architecture-knowledge-toolkit` checkout found by + searching upward from this project directory: + `../architecture-knowledge-toolkit`, then the same directory name in each + parent directory up to the filesystem root (do not assume the toolkit is a + direct sibling; this project may live outside the toolkit's parent folder) 3. project-local recorded toolkit reference, submodule, vendored copy, or pinned path 4. the public repository above, preferably at a stable release tag or commit SHA From 96051d145940f07357c9a1ea1d2d1950d90535e5 Mon Sep 17 00:00:00 2001 From: Dieter Baier Date: Sun, 12 Jul 2026 11:17:36 +0200 Subject: [PATCH 3/3] Render adapter intro conditionally on local skills Review nit: the generator appended a Local Skills section once skills existed but still claimed docs-toolbox has no local skills. Make the intro and skill-selection step depend on skills.length so the wording stays correct if local skills are ever added. No change to current output (no local skills today). Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/build-agent-adapters.js | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/scripts/build-agent-adapters.js b/scripts/build-agent-adapters.js index 583a6df..19927da 100644 --- a/scripts/build-agent-adapters.js +++ b/scripts/build-agent-adapters.js @@ -92,30 +92,44 @@ ${generatedNotice}${body}`, } function renderTarget(target, skills) { - const localSkillsSection = - skills.length > 0 - ? `\n## Local Skills + const hasSkills = skills.length > 0; + + const localSkillsSection = hasSkills + ? `\n## Local Skills Paths are relative to the ${project} repository root. ${skills.map((skill) => `- \`${skill.name}\`: \`${skill.path}\``).join("\n")} ` - : ""; + : ""; + + const intro = hasSkills + ? `Keep project semantics in repository-root \`general-semantic-contracts.md\` +and canonical \`skills/**/SKILL.md\` files. Architecture and +software-development-lifecycle work not covered by a local skill is delegated to +the architecture-knowledge-toolkit.` + : `${project} keeps no local agent skills of its own; architecture and +software-development-lifecycle semantics are delegated to the +architecture-knowledge-toolkit.`; + + const selectStep = hasSkills + ? `3. Select and read the relevant skill: a local skill from the list below when + one applies, otherwise the matching canonical \`skills/**/SKILL.md\` from the + architecture-knowledge-toolkit.` + : `3. Follow the toolkit lookup order in \`AGENTS.md\`, then read the relevant + canonical \`skills/**/SKILL.md\` from the architecture-knowledge-toolkit.`; const body = `# ${target.title} This is a thin ${target.agent}-specific wrapper for the ${project} -repository. ${project} keeps no local agent skills of its own; architecture and -software-development-lifecycle semantics are delegated to the -architecture-knowledge-toolkit. +repository. ${intro} When ${target.agent} performs architecture-sensitive or SDLC work in this repository: 1. Read repository-root \`AGENTS.md\`. 2. Read repository-root \`general-semantic-contracts.md\`. -3. Follow the toolkit lookup order in \`AGENTS.md\`, then read the relevant - canonical \`skills/**/SKILL.md\` from the architecture-knowledge-toolkit. +${selectStep} 4. Treat this adapter as routing guidance only. ${localSkillsSection} ## Toolkit Source Of Truth