fix(agents): relocate provenance sources.md outside agents/ dir

`claude plugin validate --strict` auto-discovers every .md under a
plugin's agents/ directory as an agent requiring frontmatter, so the
provenance file there always needs fake agent frontmatter to pass
validation. Confirmed empirically that an explicit `agents` manifest
array can't suppress this discovery. Move the file to <plugin-root>/
sources.md instead, and update agent-author/agent-audit accordingly.

Adds ADR-0010, partially superseding ADR-0005's `agents/sources.md`
convention. Fixes #63.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 09:01:06 +00:00
parent 5deed07a95
commit 996d9be428
16 changed files with 125 additions and 68 deletions

View File

@@ -109,7 +109,7 @@ Open the scaffolded Claude Code file. Replace every `FILL IN:` placeholder. **Re
- `initialPrompt`: auto-submitted as the first turn when this agent activates as the main session thread; only set when this agent is intended for main-thread activation
- `background`: set `true` to force background execution
**`source_keys`** — top-level list of research source slugs that informed this agent. Add only when research sources were used (i.e. entries with `` `extracted` `` status are in context from a prior `/research` session). Each slug must match an H2 heading in `agents/sources.md`. Omit entirely when no research was used.
**`source_keys`** — top-level list of research source slugs that informed this agent. Add only when research sources were used (i.e. entries with `` `extracted` `` status are in context from a prior `/research` session). Each slug must match an H2 heading in `sources.md` (plugin root). Omit entirely when no research was used.
```yaml
source_keys:
@@ -145,14 +145,14 @@ There are **two distinct Copilot agent formats** with different paths and field
The system prompt body should match the Claude Code version — the agent's task definition is the same across providers.
### Step 4 — Populate or delete `agents/sources.md` (plugin scope only)
### Step 4 — Populate or delete `sources.md` (plugin scope only)
Skip this step at project and user scope.
Skip this step at project and user scope. The file lives at the plugin root, not inside `agents/` — `claude plugin validate --strict` auto-discovers every `.md` under `agents/` as an agent requiring frontmatter, and a flat provenance file would fail that check (see ADR-0010).
If a research `sources.md` is present in the conversation context:
1. Filter to entries with `` `extracted` `` status only.
2. For each entry, identify which agent files in the pair it contributed to.
3. Write `agents/sources.md` using the format below. Paths in `Contributing files:` are relative to the plugin root.
3. Write `sources.md` at the plugin root using the format below. Paths in `Contributing files:` are relative to the plugin root.
```markdown
# Sources
@@ -168,7 +168,7 @@ If a research `sources.md` is present in the conversation context:
Each slug must match an H2 heading, and each slug must also appear in the `source_keys` list of every file listed under `Contributing files:`.
If no research sources are in context, delete `agents/sources.md`.
If no research sources are in context, delete `sources.md`.
### Step 5 — Validate and close

View File

@@ -62,7 +62,7 @@ description: FILL IN: Action-first description of what this agent does and when
<!-- source_keys:
- slug-name
Development-only. Add when research sources informed this agent (slugs must match agents/sources.md).
Development-only. Add when research sources informed this agent (slugs must match sources.md at the plugin root).
Omit when no research was used. Not a runtime field — silently ignored by Claude Code. -->
<!-- NOTE: hooks, mcpServers, and permissionMode are silently ignored for plugin agents.

View File

@@ -35,7 +35,7 @@ description: FILL IN: Action-first description of what this agent does and when
<!-- source_keys:
- slug-name
Development-only. Add when research sources informed this agent (slugs must match agents/sources.md).
Development-only. Add when research sources informed this agent (slugs must match sources.md at the plugin root).
Omit when no research was used. Not a Copilot runtime field — silently ignored. -->
<!-- DO NOT include these Claude Code-only fields:

View File

@@ -17,7 +17,7 @@ Arguments:
plugin scope : root contains plugin.json
→ creates <root>/agents/<name>.md
→ creates <root>/agents/<name>.agent.md
→ creates <root>/agents/sources.md (if absent)
→ creates <root>/sources.md (if absent)
project scope : root is a project directory (no plugin.json)
→ creates <root>/.claude/agents/<name>.md
→ creates <root>/.github/agents/<name>.agent.md
@@ -86,7 +86,7 @@ case "$SCOPE" in
plugin)
CC_DIR="$ROOT/agents"
CP_DIR="$ROOT/agents"
SOURCES_DIR="$ROOT/agents"
SOURCES_DIR="$ROOT"
;;
project)
CC_DIR="$ROOT/.claude/agents"

View File

@@ -42,11 +42,11 @@ teardown() {
assert [ -d "$ROOT/agents" ]
}
@test "plugin scope: creates sources.md in agents/" {
@test "plugin scope: creates sources.md at plugin root" {
touch "$ROOT/plugin.json"
run bash "$SCRIPT" my-agent "$ROOT"
assert_success
assert [ -f "$ROOT/agents/sources.md" ]
assert [ -f "$ROOT/sources.md" ]
}
@test "plugin scope: no-op if claude code file already exists" {