From 0dd044a782a0d7f8a70109558f57ae1c6bf87054 Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Tue, 11 Aug 2026 17:17:32 +0000 Subject: [PATCH] docs(kyberforge): add ADR-0016, agent tools-field omitted at plugin scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #89's grilling session surfaced a real upstream gap: APM's agent primitive has no per-target compile integrator, so tools: and every Claude-only field (isolation, maxTurns, effort, memory, permissionMode) would verbatim-copy into Copilot's file with an incompatible or unrecognized shape. Omitting them entirely is the only option that never ships a wrong value to a real harness. Scoped to plugin-scope agent-author only — project/user scope keep today's Claude+Copilot pair model unchanged. Partially supersedes ADR-0005 and ADR-0008's plugin-scope clauses (addenda appended to both); ADR-0009's field-inventory.md mechanism is unaffected, only its plugin-scope content shape changes. Refs: #89 --- ...005-agent-author-dual-provider-scaffold.md | 5 ++ ...0008-agent-audit-single-file-invocation.md | 6 ++ ...rimitive-drops-provider-specific-fields.md | 88 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 docs/adr/0016-apm-agent-primitive-drops-provider-specific-fields.md diff --git a/docs/adr/0005-agent-author-dual-provider-scaffold.md b/docs/adr/0005-agent-author-dual-provider-scaffold.md index 6dc004d..06cd8bc 100644 --- a/docs/adr/0005-agent-author-dual-provider-scaffold.md +++ b/docs/adr/0005-agent-author-dual-provider-scaffold.md @@ -44,3 +44,8 @@ separate single-provider skill, adding complexity with no benefit. file now lives at `/sources.md`, outside the `agents/` directory, because `claude plugin validate --strict` auto-discovers every `.md` under `agents/` as an agent requiring frontmatter. See ADR-0010 for the empirical finding and rationale. + +**Update (ADR-0016):** the plugin-scope clause above is superseded. Plugin scope is no longer +detected via `plugin.json`, and no longer produces a Claude+Copilot file pair — a directory +containing `apm.yml` now gets a single vendor-neutral `.apm/agents/.agent.md` file with +no provider-specific fields. Project scope and user scope are unaffected. See ADR-0016. diff --git a/docs/adr/0008-agent-audit-single-file-invocation.md b/docs/adr/0008-agent-audit-single-file-invocation.md index 642e675..3eca37f 100644 --- a/docs/adr/0008-agent-audit-single-file-invocation.md +++ b/docs/adr/0008-agent-audit-single-file-invocation.md @@ -14,3 +14,9 @@ - Scope detection walks up from the input file: first directory containing `plugin.json` → plugin scope; first directory containing `.git` without `plugin.json` → project scope; path under `~` with neither → user scope. - At user scope the derivation crosses filesystem locations (`~/.claude/agents/` ↔ `~/.copilot/agents/`); the script must handle the home directory case explicitly. - The invocation signature is the public contract. Changing it is a breaking change to any caller — treat it as such. + +**Update (ADR-0016):** the plugin-scope clause above is superseded. Plugin scope is no longer +detected via `plugin.json`, and there is no counterpart to derive — a directory containing +`apm.yml` produces a single `.apm/agents/.agent.md` file, and `agent-audit` validates it +directly with no pair-consistency check. Project scope and user scope keep the pair-derivation +mechanism described above unchanged. See ADR-0016. diff --git a/docs/adr/0016-apm-agent-primitive-drops-provider-specific-fields.md b/docs/adr/0016-apm-agent-primitive-drops-provider-specific-fields.md new file mode 100644 index 0000000..c8daf82 --- /dev/null +++ b/docs/adr/0016-apm-agent-primitive-drops-provider-specific-fields.md @@ -0,0 +1,88 @@ +# Plugin-scope agent-author omits `tools:` and all Claude-only fields from `.apm/agents/*.agent.md` + +This ADR is a narrower, downstream consequence discovered while designing issue #89's +implementation under ADR-0015's broader direction (Microsoft APM replaces hand-authored +plugin/marketplace authoring). It does not restate ADR-0015's rationale — see that ADR for +the parent decision. + +## Context + +APM's agent primitive (`.apm/agents/.agent.md`) has no per-target integrator in +`apm compile` — confirmed via APM's own Python source (`integration/targets.py` and related +files, cited in `plugins/kyberforge/docs/research/docs/microsoft-apm/agent-primitive-schema.md`). +Compilation does a naive verbatim copy of the whole frontmatter and body to both the Claude +Code and Copilot CLI targets. This is unlike: + +- The **skill** primitive, which is also a straight copy (confirmed in the same research doc) + but has no field semantics to conflict — `SKILL.md`'s content is target-agnostic already. +- The **prompt**, **instructions**, and **hooks** primitives, which each get real per-target + reconstruction through a dedicated integrator (field allowlisting, key renaming, dropped-field + warnings). + +Because the agent primitive ships the same frontmatter unchanged to both harnesses, two +concrete incompatibilities surface: + +1. **`tools:`** — Claude Code expects a space-separated tool-name string; Copilot CLI expects a + list drawn from its own alias vocabulary (`execute`/`read`/`edit`/`search`/`agent`/`web`). A + value correct for one harness is wrong for the other. +2. **Claude-only knobs with no Copilot equivalent** — `isolation`, `maxTurns`, `effort`, + `memory`, `permissionMode`. Writing any of these means Copilot's copy carries frontmatter + keys it doesn't recognize at all. Whether Copilot's agent loader ignores unknown keys or + errors on them is unconfirmed by research. + +## Decision + +At **plugin scope only** (destination package has an `apm.yml` at its root — an APM producer +package compiled via `apm compile`), `.apm/agents/.agent.md` carries only `name`, +`description`, `model`, and the prose body. No `tools:` field, no Claude-only fields, at all. + +Absent `tools:` means inherit-all-tools on both harnesses — the one value that is never wrong +on either target, unlike a present, harness-specific value that is guaranteed wrong on at least +one of them. + +`agent-audit`, at plugin scope, flags — as a **SUGGESTION**, not a FAIL, since this is an +upstream schema limitation rather than an authoring mistake — any agent whose description or +body implies a need for tool restriction or a Claude-only behavior the frontmatter can no +longer express. This gives visibility into the gap without pretending the schema can do +something it can't. + +### Scope boundary + +This decision applies to **plugin-scope `agent-author` only**. Project scope (`.claude/agents/` ++ `.github/agents/`) and user scope (`~/.claude/agents/` + `~/.copilot/agents/`) are not APM +packages — neither goes through `apm compile` — so both keep today's dual-file Claude+Copilot +pair model exactly as ADR-0005 and ADR-0008 already describe. Those two ADRs remain fully +authoritative for project and user scope; only their plugin-scope clauses are affected by this +ADR (see the update notes appended to each). + +## Considered options + +**Pick one harness's vocabulary and accept breakage on the other (rejected).** E.g. always +write Claude's space-separated `tools:` string. Rejected because it ships a value that is +silently wrong (or possibly a hard error) on Copilot, and which harness "wins" would be an +arbitrary, undocumented asymmetry. + +**Same as above, but `agent-audit` flags the cross-harness breakage as a tracked finding +(rejected).** Rejected for the same core reason — it still ships a wrong value to a real +harness. Tracking the breakage doesn't prevent it, and the chosen decision already gets +equivalent visibility (a SUGGESTION finding) without ever shipping the wrong value in the first +place. + +## Consequences + +- Every plugin-scope APM agent loses per-agent tool restriction and any Claude-only capability + (isolation, maxTurns, effort, memory, permissionMode) until APM ships a real per-target + integrator for the agent primitive. This is a known, accepted regression, not an oversight. +- **ADR-0005 is partially superseded** — its plugin-scope clause ("directory containing + `plugin.json` is plugin scope → both files land in `/agents/`") no longer applies. + Plugin scope is now "directory containing `apm.yml` → single vendor-neutral file lands in + `/.apm/agents/`." Project and user scope, and the rest of ADR-0005, are unaffected. +- **ADR-0008 is partially superseded** — its counterpart-derivation/pair-validation mechanism + no longer applies at plugin scope; `agent-audit` takes the single file directly there. Project + and user scope, where a real pair still exists, are unaffected. +- **ADR-0009 is not superseded.** The mechanism it established — `agent-audit` reading field + lists from `references/field-inventory.md` rather than hardcoding them, with a `source_keys` + provenance chain — survives and is reused. Only the *content shape* changes for plugin scope: + `field-inventory.md` shifts from two side-by-side CC-only/Copilot-only blocklists to one + vendor-neutral allowlist (`name`/`description`/`model`) for plugin-scope agents, while + continuing to serve its original two-blocklist role for project/user-scope validation.