From 2868c47ca25b1495f1b2a04289df1487cf54f927 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sun, 26 Jul 2026 02:20:59 +0200 Subject: [PATCH] docs(agents): point skill authoring at agent-skills, not the synced plugin copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit § Agent definition locations named plugins/agentic-engineering/skills/agent-improvement/SKILL.md as a version-controlled authoring surface. That file carries metadata.github-repo provenance and is re-pulled by the daily update-agent-skills workflow, so an edit there survives until the next sync and then silently disappears — no conflict, no CI failure, no signal. The same plugin directory's agents/agent-improver.agent.md carries no provenance and IS authored there, so the rule is per-file, not per-directory. Points skill bodies at devantler-tech/agent-skills, keeps the agents half unchanged, and states the grep -l github-repo check so the next new file is classified rather than guessed. Adds a guard test (4 assertions, each individually RED-proven) wired into CI through its own paths filter, which lists the guard and ci.yaml so deleting either still runs it. --- .../authoring-surface-provenance.test.sh | 68 +++++++++++++++++++ .github/workflows/ci.yaml | 22 ++++++ AGENTS.md | 16 +++-- 3 files changed, 102 insertions(+), 4 deletions(-) create mode 100755 .claude/scripts/authoring-surface-provenance.test.sh diff --git a/.claude/scripts/authoring-surface-provenance.test.sh b/.claude/scripts/authoring-surface-provenance.test.sh new file mode 100755 index 00000000..1809dd5b --- /dev/null +++ b/.claude/scripts/authoring-surface-provenance.test.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# +# Guards § Agent definition locations against naming a SYNCED file as an authoring +# surface. +# +# `plugins/*/skills/*/SKILL.md` in devantler-tech/agent-plugins carry +# `metadata.github-repo` provenance and are re-pulled by the daily +# `update-agent-skills` workflow. A hand-edit there survives until the next sync and +# then silently disappears — no conflict, no CI failure, no signal. The sibling +# `plugins/*/agents/*.agent.md` carry no provenance and ARE authored there, so +# "editable here?" is a per-file question and a per-directory rule gets it wrong. +# +# The contract named the synced agent-improvement SKILL.md as a version-controlled +# authoring target (caught 2026-07-25 on agent-plugins#89, rated Major), which would +# route a generic skill change into a file that reverts it. This pins that shut. + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +constitution="${repo_root}/AGENTS.md" + +fail() { + echo "authoring-surface provenance: FAIL — $*" >&2 + exit 1 +} + +[ -f "${constitution}" ] || fail "missing ${constitution}" + +# Flatten so a rule wrapped across lines is still matched (prose guards must +# flatten whitespace — a line-anchored grep silently passes on reflowed text). +flat="$(tr '\n' ' ' <"${constitution}" | tr -s ' ')" + +section="$(printf '%s' "${flat}" | + sed -n 's/.*### Agent definition locations\(.*\)### Authority model.*/\1/p')" +[ -n "${section}" ] || fail "could not isolate § Agent definition locations" + +# 1. No CONCRETE bundled skill path may be named as an authoring surface. The glob +# form `plugins/*/skills/*/SKILL.md` is the warning itself and must stay allowed, +# so match only path segments that name a real plugin and a real skill. +if printf '%s' "${section}" | + grep -qE 'plugins/[A-Za-z0-9_.-]+/skills/[A-Za-z0-9_.-]+/SKILL\.md'; then + fail "§ Agent definition locations names a concrete bundled + plugins//skills//SKILL.md path as an authoring surface. + Those files are SYNCED from their metadata.github-repo upstream and an edit there is + silently reverted. Name the upstream authoring repo instead (agent-skills)." +fi + +# 2. The true upstream for skill bodies must be named, by its FULL slug. A bare +# `agent-skills` would be satisfied by the `update-agent-skills` workflow name +# that this same paragraph mentions — a vacuous assertion. +printf '%s' "${section}" | grep -q 'devantler-tech/agent-skills' || + fail "§ Agent definition locations must name devantler-tech/agent-skills as the + authoring home for generic skill bodies." + +# 3. The sibling agents file genuinely IS authored in agent-plugins — keep it named, +# so a fix for (1) does not over-correct and strand the agent definition. +printf '%s' "${section}" | grep -q 'agents/agent-improver\.agent\.md' || + fail "§ Agent definition locations must still name + plugins/agentic-engineering/agents/agent-improver.agent.md, which carries no + provenance and is authored in agent-plugins." + +# 4. The per-file provenance test must be stated, not just the conclusion — the +# directory mixes both kinds, so the next new file needs the check, not the answer. +printf '%s' "${section}" | grep -q 'metadata\.github-repo' || + fail "§ Agent definition locations must state the per-file provenance check by its + exact key (metadata.github-repo) rather than only its conclusion for today's files." + +echo "authoring-surface provenance: OK — 4 assertions passed" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 00d8b0fc..a53041f6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,6 +33,7 @@ jobs: board-add: ${{ steps.filter.outputs.board-add }} flow-scorecard: ${{ steps.filter.outputs.flow-scorecard }} memory-hygiene: ${{ steps.filter.outputs.memory-hygiene }} + authoring-surface: ${{ steps.filter.outputs.authoring-surface }} steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -159,6 +160,12 @@ jobs: - '.claude/scripts/product-value-contract.test.sh' - 'docs/README.md' - '.github/workflows/ci.yaml' + authoring-surface: + # The guard script itself is listed so a PR deleting it still runs it, + # and ci.yaml so removing the job below is covered the same way. + - 'AGENTS.md' + - '.claude/scripts/authoring-surface-provenance.test.sh' + - '.github/workflows/ci.yaml' build-docs: needs: changes @@ -419,6 +426,21 @@ jobs: - name: Verify the product value contract run: bash .claude/scripts/product-value-contract.test.sh + test-authoring-surface-provenance: + name: Test authoring-surface provenance + needs: changes + if: needs.changes.outputs.authoring-surface == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Verify the authoring-surface provenance guard + run: bash .claude/scripts/authoring-surface-provenance.test.sh + test-self-review-contract: name: Test self-review contract needs: changes diff --git a/AGENTS.md b/AGENTS.md index 9c668012..0725c2b9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -263,10 +263,18 @@ definition surface, and an installed/cache copy is never an authoring target. script, the provider-neutral desired state, plugin settings, and the Cursor loader source. The local Agent Improver agent/skill forks are retired, and so is the standalone FinOps agent fork — the reviewed plugin is the source for both roles. -- The generic upstream source in `devantler-tech/agent-plugins`, specifically - `plugins/agentic-engineering/agents/agent-improver.agent.md`, - `plugins/agentic-engineering/skills/agent-improvement/SKILL.md`, the plugin README/desired state, - and their manifest/contract validation. Change generic behaviour there first, merge it, then update +- The generic upstream source — **in the repository that actually authors the file**, which differs + per file inside one plugin directory. In `devantler-tech/agent-plugins`: + `plugins/agentic-engineering/agents/agent-improver.agent.md`, the plugin README/desired state, and + their manifest/contract validation. **Skill bodies are NOT authored there:** + `plugins/*/skills/*/SKILL.md` carry `metadata.github-repo` provenance and are re-pulled by the + daily `update-agent-skills` workflow, so a hand-edit survives until the next sync and then + **silently disappears** — no conflict, no CI failure, no signal. Author them in the repo that + `github-repo` names, normally **`devantler-tech/agent-skills`** (the Agent Improver's skill is + `agent-improvement/SKILL.md` there), and let the sync carry the bundled copy down; the interval + where the bundled copy still reads the old wording is correct, not a miss. Provenance is a + **per-file** question — run `grep -l github-repo ` before editing anything under a plugin, + rather than trusting the directory. Change generic behaviour upstream first, merge it, then update this consumer's `libraries/agent-plugins` gitlink and copied desired state. **Runtime-local surfaces — back up before editing, verify in place, and record before/after in native