From 11f1ce6f3a226b0317864c2e02cf60f028aa8b96 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 11:21:25 +0000 Subject: [PATCH 1/2] fix(agents): stage regenerated adapters on commit and validate them in CI What changed: - Add a --stage flag to build-agent-instructions.js that git-adds the files it generates: PLATFORM_REFERENCE.md, .github/instructions, .claude/rules, .claude/skills, and the scoped AGENTS.md files. - Run the pre-commit build with --stage, format staged instruction sources before building, and exclude those sources from the parallel lint-markdown-instructions hook. - Match files directly under .agents/instructions, .github/instructions, and .claude/rules. The previous **/*.md globs required a subfolder. - Add the Agent Instructions workflow, which runs yarn validate:agent-instructions on pull requests that touch agent sources, adapters, or the build scripts. Why: - The build hook never ran for .agents/instructions/*.md because of the glob. When it did run, stage_fixed re-staged only the matched sources, so commits shipped without their regenerated adapters. #7877 merged that way. - The parallel remark hook could reformat a source after the build read it, so the committed adapters would not match the committed source. - Hooks can be skipped, so CI must check the result. Impact: - Committing an instruction change commits its formatted source and matching adapters together. - Pull requests with stale or invalid adapters fail the new check. Verification: - On a throwaway branch, committing an unformatted edit to .agents/instructions/content.md committed the formatted source and all three content adapters, left nothing unstaged, and yarn validate:agent-instructions passed. Before the fix, the build hook was skipped and the adapters stayed stale. - yarn validate:agent-instructions exits 1 on this branch before the adapter regeneration commit. - npx lefthook validate passes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018NiFuxdSqYvtMpAhNfWBbM --- .github/workflows/pr-agent-instructions.yml | 55 +++++++++++++++++++++ helper-scripts/build-agent-instructions.js | 17 +++++++ lefthook.yml | 21 ++++++-- 3 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/pr-agent-instructions.yml diff --git a/.github/workflows/pr-agent-instructions.yml b/.github/workflows/pr-agent-instructions.yml new file mode 100644 index 0000000000..69b39196ce --- /dev/null +++ b/.github/workflows/pr-agent-instructions.yml @@ -0,0 +1,55 @@ +name: Agent Instructions + +# Fails when generated agent instruction adapters don't match their +# .agents/ sources. The commit hook regenerates and stages them, but +# --no-verify, web edits, and missing hooks bypass it. + +on: + pull_request: + paths: + - 'AGENTS.md' + - '.agents/**' + - '.claude/rules/**' + - '.claude/skills' + - '.github/instructions/**' + - 'api-docs/AGENTS.md' + - 'assets/AGENTS.md' + - 'content/AGENTS.md' + - 'layouts/AGENTS.md' + - 'PLATFORM_REFERENCE.md' + - 'data/products.yml' + - 'helper-scripts/build-agent-instructions.js' + - 'helper-scripts/validate-agent-instructions.js' + - 'helper-scripts/agent-instruction-limits.js' + - '.github/workflows/pr-agent-instructions.yml' + +permissions: + contents: read + +concurrency: + group: pr-agent-instructions-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + validate: + name: Validate generated agent instructions + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Setup docs environment + env: + CYPRESS_INSTALL_BINARY: 0 + uses: ./.github/actions/setup-docs-env + + - name: Validate agent instructions and generated adapters + run: | + if ! yarn validate:agent-instructions; then + echo '::error::Agent instruction adapters are out of date or invalid. Run yarn build:agent:instructions and commit the result.' + git status --short + git diff --stat + exit 1 + fi diff --git a/helper-scripts/build-agent-instructions.js b/helper-scripts/build-agent-instructions.js index 6813fe4892..18a3bc3410 100644 --- a/helper-scripts/build-agent-instructions.js +++ b/helper-scripts/build-agent-instructions.js @@ -8,6 +8,7 @@ import path from 'path'; import process from 'process'; import matter from 'gray-matter'; import yaml from 'js-yaml'; +import { execFileSync } from 'child_process'; import { pathToFileURL } from 'url'; export { @@ -47,6 +48,13 @@ const SCOPED_AGENTS = [ { dir: 'content', title: 'Documentation Content' }, { dir: 'layouts', title: 'Hugo Layouts and Shortcodes' }, ]; +const GENERATED_PATHS = [ + 'PLATFORM_REFERENCE.md', + '.github/instructions', + '.claude/rules', + '.claude/skills', + ...SCOPED_AGENTS.map(({ dir }) => `${dir}/AGENTS.md`), +]; if (import.meta.url === pathToFileURL(process.argv[1]).href) { (async () => { @@ -54,6 +62,7 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) { await buildPlatformReference(); await buildAgentInstructionAdapters(); ensureClaudeSkillsSymlink(); + if (process.argv.includes('--stage')) stageGeneratedFiles(); } catch (error) { console.error('Error generating agent instructions:', error); process.exitCode = 1; @@ -61,6 +70,14 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) { })(); } +function stageGeneratedFiles() { + const existingPaths = GENERATED_PATHS.filter((generatedPath) => + fs.existsSync(path.join(PROJECT_ROOT, generatedPath)) + ); + execFileSync('git', ['add', '--', ...existingPaths], { cwd: PROJECT_ROOT }); + console.log('✅ Staged generated agent instruction files'); +} + async function buildAgentInstructionAdapters() { const instructions = readCanonicalInstructions(); diff --git a/lefthook.yml b/lefthook.yml index 4f2f1cecd2..c17d6850a8 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -69,13 +69,22 @@ pre-commit: glob: "assets/js/*.js" run: yarn eslint {staged_files} fail_text: "Debug helpers found! Remove debug imports and calls before committing." + # Formats instruction sources before building so adapters match the + # committed sources; lint-markdown-instructions excludes them to avoid a + # parallel write. --stage adds the generated adapters to the commit. build-agent-instructions: glob: - "AGENTS.md" - - ".agents/instructions/**/*.md" + - ".agents/instructions/*.md" - ".agents/skills/**/SKILL.md" - "data/products.yml" - run: yarn build:agent:instructions + run: | + sources=$(echo '{staged_files}' | tr ' ' '\n' | grep '^\.agents/instructions/' | tr '\n' ' ' | sed 's/ $//') + if [ -n "$sources" ]; then + .ci/remark/remark.sh $sources --output --quiet || \ + echo "⚠️ Remark found formatting issues in instruction sources. Automatic formatting applied." + fi + yarn build:agent:instructions --stage stage_fixed: true # Auto-fix markdown formatting for instruction and README files (like prettier). # The wrapper at .ci/remark/remark.sh runs the local Node install when present @@ -92,6 +101,8 @@ pre-commit: - "assets/AGENTS.md" - "content/AGENTS.md" - "layouts/AGENTS.md" + exclude: + - ".agents/instructions/*.md" run: | # Shortcode .md files contain Hugo template syntax that remark-lint would # escape, so filter content/ and layouts/ paths before running remark. @@ -214,10 +225,10 @@ pre-push: tags: lint glob: - "AGENTS.md" - - ".agents/instructions/**/*.md" + - ".agents/instructions/*.md" - ".agents/skills/**/SKILL.md" - - ".github/instructions/**/*.md" - - ".claude/rules/**/*.md" + - ".github/instructions/*.md" + - ".claude/rules/*.md" - "api-docs/AGENTS.md" - "assets/AGENTS.md" - "content/AGENTS.md" From 37a85b45243a1336f102d8c78a9513dfd74ac6f6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 11:00:40 +0000 Subject: [PATCH 2/2] chore(agents): regenerate content instruction adapters What changed: - Regenerate .claude/rules/content.md, .github/instructions/content.instructions.md, and content/AGENTS.md from .agents/instructions/content.md. Why: - #7877 updated the shared-content guidance in .agents/instructions but not the generated adapters, so yarn validate:agent-instructions fails on master and the commit hooks rewrite these files on every run. Impact: - Agents that read the adapters get the current shared-content preview guidance. Verification: - yarn validate:agent-instructions passes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018NiFuxdSqYvtMpAhNfWBbM --- .claude/rules/content.md | 6 +++++- .github/instructions/content.instructions.md | 6 +++++- content/AGENTS.md | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.claude/rules/content.md b/.claude/rules/content.md index a645636c75..c3f1bbb4d2 100644 --- a/.claude/rules/content.md +++ b/.claude/rules/content.md @@ -25,7 +25,11 @@ the `docs` CLI or direct editing. examples. - Do not hardcode production docs URLs when a relative link or `relref` works. - Shared files have no frontmatter. A stub's `source:` must begin `/shared/`. - Direct shared edits require touching every source stub; `docs edit` finds them. + Identify every consumer before editing shared content. When previewing changes + with a running `hugo server`, touch each consuming stub or restart the server + because the watcher doesn't rebuild consumers automatically after shared-source + changes. Fresh builds, including CI builds and checks, don't require touching + consumer stubs. Edit stub content only when its frontmatter needs to change. - Use resource-ownership language for import/write/load guidance and write recommendations in InfluxData's first-person plural voice. diff --git a/.github/instructions/content.instructions.md b/.github/instructions/content.instructions.md index 302a0113a9..7439c2b467 100644 --- a/.github/instructions/content.instructions.md +++ b/.github/instructions/content.instructions.md @@ -24,7 +24,11 @@ the `docs` CLI or direct editing. examples. - Do not hardcode production docs URLs when a relative link or `relref` works. - Shared files have no frontmatter. A stub's `source:` must begin `/shared/`. - Direct shared edits require touching every source stub; `docs edit` finds them. + Identify every consumer before editing shared content. When previewing changes + with a running `hugo server`, touch each consuming stub or restart the server + because the watcher doesn't rebuild consumers automatically after shared-source + changes. Fresh builds, including CI builds and checks, don't require touching + consumer stubs. Edit stub content only when its frontmatter needs to change. - Use resource-ownership language for import/write/load guidance and write recommendations in InfluxData's first-person plural voice. diff --git a/content/AGENTS.md b/content/AGENTS.md index 6bb868ca05..e74e89a181 100644 --- a/content/AGENTS.md +++ b/content/AGENTS.md @@ -24,7 +24,11 @@ the `docs` CLI or direct editing. examples. - Do not hardcode production docs URLs when a relative link or `relref` works. - Shared files have no frontmatter. A stub's `source:` must begin `/shared/`. - Direct shared edits require touching every source stub; `docs edit` finds them. + Identify every consumer before editing shared content. When previewing changes + with a running `hugo server`, touch each consuming stub or restart the server + because the watcher doesn't rebuild consumers automatically after shared-source + changes. Fresh builds, including CI builds and checks, don't require touching + consumer stubs. Edit stub content only when its frontmatter needs to change. - Use resource-ownership language for import/write/load guidance and write recommendations in InfluxData's first-person plural voice.