feat(kyberforge): enforce the ADR-0020 context contract for skills and agents

Skill name+description pairs are preloaded into every session, costing
~6,200 tokens across 39 skills before any skill is invoked. The authoring
rules mandated that growth: skill-author:104 and description-quality.md:21
both required padding, while skill-author:102 (the deflating rule) had no
FAIL condition behind it.

Gates (blocking, no baseline file):
- description 250 chars SUGGESTION / 400 FAIL, measured on the folded
  YAML value
- body-only 600 words SUGGESTION / 900 FAIL, independent of the unchanged
  whole-file 2770-word / 500-line spec backstop
- every boundary-clause routing target must resolve to a real skill or
  agent; catches skill-improve, neuledge-context and gitea-labels
- agents take the description gates but deliberately no body gate; a test
  pins that absence

Vale: DescriptionOpener widened to ^This\b, new CompositionNote rule
banning architecture notes from descriptions. 10 hits, 0 false positives.

Kyberforge's own four skills retrofitted: descriptions 3,364 -> 938 chars
(-72%), bodies 8,306 -> 2,487 words (-70%), all via the apm-workflow
dispatch pattern. Fixes the skill-improve dangling route and the
agent-author misroute to manual review.

Also fixes a pre-existing false positive where any line-initial 'read '
was flagged as interactive input, which had already caused two scripts to
be rewritten around it.

Refs: ADR-0020
This commit is contained in:
2026-08-14 21:13:13 +00:00
parent 1c6eababb0
commit 4a5c3c0cff
104 changed files with 6272 additions and 1880 deletions

View File

@@ -30,10 +30,15 @@ bash scripts/new-agent.sh security-reviewer ~
| File | Purpose |
|------|---------|
| `SKILL.md` | Skill instructions for agents |
| `SKILL.md` | Skill instructions for agents — gotchas, the create/improve dispatch table, the scope dispatch table, the shared gates, and validation/close |
| `scripts/new-agent.sh` | Scaffolds agent definition file(s) from templates — a single `.apm/agents/<name>.agent.md` at plugin/APM scope, or a Claude Code + Copilot CLI pair at project/user scope |
| `references/deployment-modes.md` | Plugin/APM vs project vs user scope: restrictions, scoped identifiers, path conventions |
| `references/scripts.md` | Conventions for new-agent.sh and any future scripts: contract, template variables, file placement, error messages |
| `references/create.md` | Create flow: prerequisites, scaffold and scope walk-up, what to fill in, package-root `sources.md` |
| `references/improve.md` | Improve flow: signal verification, root-cause grouping, generalizing, delegation over growth, ADR-0020 retrofit |
| `references/contract.md` | Description and body contract: three-part description shape, 250/400 tiers, delegation rule in place of a body word gate, invocation axis |
| `references/plugin-scope.md` | Plugin/APM scope field rules for the single vendor-neutral file, plus its pre-audit checklist |
| `references/project-user-scope.md` | Project/user scope field rules for the Claude Code + Copilot pair, both Copilot formats, plus its pre-audit checklist |
| `references/deployment-modes.md` | Scope hierarchy and precedence, scoped identifiers, cache isolation, path conventions |
| `references/scripts.md` | Conventions for new-agent.sh and the templates it copies: contract, template variables, file placement, error messages |
| `references/sources.md` | Research provenance — sources that informed this skill |
| `assets/templates/claude-code.md` | Annotated Claude Code agent definition template (project/user scope) |
| `assets/templates/copilot.agent.md.template` | Annotated Copilot CLI agent definition template (project/user scope) |

View File

@@ -1,18 +1,9 @@
---
name: agent-author
description: >
Use when the user wants to create a new agent definition file from scratch
("write an agent for X", "build a subagent that does Y", "create an agent
definition for Z"), or improve an existing one. Handles agent definitions at
plugin/APM, project, and user scope. Project and user scope always generate
a Claude Code (`.md`) + Copilot CLI (`.agent.md`) file pair in one pass;
plugin/APM scope generates a single vendor-neutral `.apm/agents/<name>.agent.md`
file instead (no per-target Claude Code / Copilot split). Also use when the
user provides inline feedback about an agent's behavior and wants it applied,
or when a grill session has produced findings the user wants acted on — even
if they don't say "improve" explicitly. Do not use for read-only review —
examine agent files manually or run a grill session to generate improvement
signals. Do not use to author skills — use /skill-author instead.
Use when the user wants to create a new agent definition file from scratch, or
apply grill findings, audit findings, or inline feedback to an existing one.
Not read-only review -> `agent-audit`. Not skills -> `skill-author`.
allowed-tools: Bash Read Write Edit
metadata:
category: factory
@@ -20,240 +11,52 @@ metadata:
- context7-websites-code-claude
- claude-code-plugins-docs
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
- github-cli-plugin-reference
- github-plugins-creating
---
## Gotchas
- At plugin/APM scope, bump the resolved package's `apm.yml` `version` after every change — minor for a new agent, patch for a fix. Consumers compare this version to detect updates; skipping it hides the change.
- At plugin/APM scope, `tools` and all Claude-only fields (`isolation`, `maxTurns`, `effort`, `memory`, `permissionMode`, `skills`, `color`, `initialPrompt`, `background`, `hooks`, `mcpServers`) are omitted entirely, not merely restricted (ADR-0016: `apm compile` copies frontmatter verbatim to both harnesses with no per-target integrator, so a harness-specific value is wrong on at least one). Only project/user scope supports these fields.
- `disallowedTools` is the one exception, on **shape**, not favouritism. `tools` is an *allowlist* whose vocabulary differs per harness (Claude tool names vs Copilot's `execute`/`read`/`edit`/`search`/`agent`/`web`), so verbatim copy makes one value wrong on one target. A *denylist* cannot fail that way: an unrecognised name denies nothing, so the worst case is a missing fence, never a wrong grant. Claude Code honours it for plugin subagents — `docs/research/docs/claude-code-plugins/agent-definition.md:99` lists the three fields plugin agents ignore (`hooks`, `mcpServers`, `permissionMode`) and this is not one. Write it on every read-only plugin-scope agent (ADR-0016's 2026-08-14 amendment).
- That fence is partial: it denies only the tools it names. It does not deny `Bash`, which a plugin-scope agent with no `tools` inherits, so a shell redirect still writes. Say the agent is read-only in the body too.
- An `apm.yml` with no top-level `type:` field is a marketplace-only manifest, not a package root — the walk-up skips it and keeps going.
- `AskUserQuestion`, `EnterPlanMode`, `ExitPlanMode`, `ScheduleWakeup`, and `WaitForMcpServers` are never available to any subagent regardless of the `tools` field. Exception: `ExitPlanMode` is available when the parent session runs in `permissionMode: plan`.
- Duplicate `name` values in the same scope: Claude Code silently discards one without warning. Always verify uniqueness before shipping.
- Plugin agents in subdirectories get scoped identifiers (`plugin:folder:name`) — keep agents flat in `agents/` to avoid this. Applies to project/user-scope Claude Code agents only.
- Copilot CLI agent files **must** use the `.agent.md` extension — a plain `.md` file isn't picked up. The plugin/APM-scope single file also ends in `.agent.md` by convention, but it's vendor-neutral, not Copilot-only — it compiles to Claude Code too.
- Copilot has no `permissionMode`, `maxTurns`, `isolation`, or `memory` fields — do not include them in project/user-scope Copilot files.
- `model` resolution order for Claude Code: `CLAUDE_CODE_SUBAGENT_MODEL` env var → per-invocation parameter → frontmatter `model` → main session model. The frontmatter value is a low-priority default, not a guarantee.
- At plugin/APM scope `tools` and every Claude-only field are omitted entirely, not merely ignored: `apm compile` copies frontmatter verbatim to both harnesses, so fencing a read-only agent with `tools:` is wrong on one of them. `disallowedTools` is the one restriction that survives (ADR-0016).
- That fence is partial. It denies only the tools it names, never `Bash`, which a plugin-scope agent inherits — a shell redirect still writes. State the read-only boundary in the body too.
- An agent body carries no word gate; delegation replaces it. A plugin/APM agent is one file with no sibling `references/` directory, so it cannot disclose to itself, only invoke skills — and a body restating a procedure an invocable skill owns is an `agent-audit` FAIL.
- Duplicate `name` values in one scope: Claude Code discards one silently. Verify uniqueness before shipping.
## Route
## Step 1 — Dispatch
If the destination resolves to plugin/APM scope (scope detection in Step 1 finds a `type:`-bearing `apm.yml` at or above the root), read `references/deployment-modes.md`.
| Condition | Flow | Reference |
|---|---|---|
| No agent file at the target path(s) | Create | `references/create.md` |
| A file exists, at least one improvement signal present | Improve | `references/improve.md` |
| A file exists, no signals | Stop and ask | — |
Determine which flow before touching the filesystem:
Signals: grill output, `agent-audit` findings, inline feedback, session context describing what went wrong. With none, ask: "No improvement signals found. Did you mean to create a new agent, or do you have feedback to apply?"
- **Neither `<name>.md` nor `<name>.agent.md` exist at the target paths** → follow **Creating a new agent**
- **At least one file exists + improvement signals present** → follow **Improving an existing agent**
- **At least one file exists + no signals** → ask: "No improvement signals found. Did you mean to create a new agent, or do you have feedback to apply?"
Read only the reference for the resolved flow. Capture `git log --oneline -1` before touching the filesystem; Step 4 needs it.
Signals: grill session output, inline user feedback, session context describing what went wrong.
## Step 2 — Scope
## Creating a new agent
Scope decides which fields exist, so resolve it first. `scripts/new-agent.sh` walks up for a `type:`-bearing `apm.yml` and prints the scope it chose — read that output.
### Prerequisites
| Resolved scope | Emits | Read |
|---|---|---|
| plugin/APM | one vendor-neutral `.apm/agents/<name>.agent.md` | `references/plugin-scope.md` |
| project or user | a Claude Code `.md` + Copilot `.agent.md` pair | `references/project-user-scope.md` |
Before touching the filesystem, confirm you have:
- [ ] Agent name (kebab-case, e.g. `code-reviewer`)
- [ ] Root directory (a path inside a package for plugin/APM scope, project root, or `~` for user scope)
- [ ] Agent purpose — one sentence describing the task this agent handles
- [ ] Trigger condition — when should the runtime delegate to this agent?
Read only the file for the resolved scope; the other describes fields this run cannot use. If precedence, cache isolation or path conventions matter, read `references/deployment-modes.md`.
If any are missing, stop and ask before proceeding. Then capture `git log --oneline -1` before touching the filesystem — Step 5 needs it to verify a real commit landed.
## Step 3 — Contract
Verify `kyberforge:agent-audit` is available — it ships with the kyberforge plugin and is co-installed with this skill. If unavailable, stop and tell the user to install the kyberforge plugin before continuing.
Before writing or editing a `description`, or restructuring a body, read `references/contract.md` — the three-part shape, banned content, the delegation rule and the body pattern.
### Step 1 — Scaffold
Gates `agent-audit` enforces at every scope:
Run the scaffold script with the agent name and root directory:
- **Description** — a trigger clause, at most one capability clause, and a boundary clause shaped `Not <thing> -> <name>` that resolves to a real skill or agent. 250 characters SUGGESTION, 400 FAIL, value only: an agent's `name` and `description` is preloaded into every session exactly as a skill's is.
- **Body** — no word gate, and a delegation check in its place: name the skill to invoke rather than restating what it does.
- **Invocation** — decide whether the agent is model-delegated or reached only by name. Only Copilot's cloud/IDE format expresses that in frontmatter (`disable-model-invocation`, `user-invocable`).
```bash
bash scripts/new-agent.sh <name> <root>
```
## Step 4 — Validate and close
Examples:
```bash
bash scripts/new-agent.sh code-reviewer packages/my-package/ # plugin/APM scope if packages/my-package/apm.yml has a type: field
bash scripts/new-agent.sh deploy-assistant .
bash scripts/new-agent.sh security-reviewer ~
```
Invoke `agent-audit` on each file written and resolve every FAIL before reporting done. It checks the field allowlist, name-to-stem match, leftover placeholders and template comments, the description budget and the Copilot body limit — do not hand-check those.
**Scope detection (script handles this automatically).** The script walks up from `<root>` for a package boundary — same shape `agent-audit`'s `validate.sh` uses:
- Nearest ancestor `apm.yml` with a top-level `type:` field (`instructions`/`skill`/`hybrid`/`prompts`) → **plugin/APM scope** → `<package-root>/.apm/agents/<name>.agent.md` (single vendor-neutral file). A `type:`-less `apm.yml` is marketplace-only — skipped, walk continues upward.
- No such `apm.yml`, `<root>` is a project directory → **project scope** (unchanged) → `<root>/.claude/agents/<name>.md` + `<root>/.github/agents/<name>.agent.md`
- `<root>` is exactly `~` (checked directly, no walk-up) → **user scope** (unchanged) → `~/.claude/agents/<name>.md` + `~/.copilot/agents/<name>.agent.md`
At plugin/APM scope bump the resolved package's `apm.yml` `version` — **minor** on create, **patch** on improve — because consumers compare it to detect updates. Project and user scope have no manifest.
A bare `plugin.json` with no `apm.yml` no longer signals plugin scope — that path is fully replaced, not dual-mode; it falls through to project scope.
The script is file-by-file no-op — it skips any file that already exists.
### Step 2 — Fill in the agent file(s)
**At plugin/APM scope**, there is exactly one file: `<package-root>/.apm/agents/<name>.agent.md`. Its frontmatter allowlist is the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md`, read from there as data: `name`, `description`, `model`, `source_keys` (provenance metadata, not a runtime field — see the template), and `disallowedTools` for a read-only agent. Never `tools` or the other Claude-only fields listed in Gotchas (ADR-0016). Fill those in plus the system prompt body per the guidance below; the rest of this step's field-by-field guidance is project/user scope only. Skip Step 3 and go to Step 4.
**At project/user scope**, continue below to fill in both provider files — this step covers the Claude Code file (`<name>.md`); Step 3 covers the Copilot file.
Open the scaffolded Claude Code file. Replace every `FILL IN:` placeholder. **Remove all template documentation comments from the YAML frontmatter after filling in required fields** — these are marked with `<!--` and `-->` and must be deleted before shipping.
**`name`** — lowercase letters and hyphens only. Must be unique within the scope.
**`description`** — the most important field for autonomous delegation:
- Start with an action verb: "Reviews...", "Analyzes...", "Generates..."
- If this agent should trigger without explicit user direction, include "Use proactively" in the description
- Specific about the triggering condition and expertise domain
- Under 300 characters preferred
**`tools`** (project/user scope only — never at plugin/APM scope) — restrict to what the agent actually needs. Omit to inherit all tools. Use `Agent(type1,type2)` to limit which subagent types this agent can spawn; omit `Agent` entirely to prevent spawning.
**`disallowedTools`** (all scopes, including plugin/APM) — denylist applied before `tools` and taking precedence over it; supports `mcp__<server>`, `mcp__<server>__*`, and `mcp__*` globs. `api-reference.md:40` types it `string / list` and `agent-definition.md:71` types it `string[]`, so a YAML list or a delimited string both work; this repo's plugin-scope agents use the comma-separated string (`disallowedTools: Edit, Write, NotebookEdit`) — match that.
**Optional fields worth considering (project/user scope only — never at plugin/APM scope, with the exception of `model`, which is allowed at every scope):**
- `model`: set when this agent needs a different capability tier (`haiku` for fast tasks, `opus` for deep reasoning)
- `maxTurns`: set a cap to prevent runaway agents on bounded tasks
- `effort`: set to `low` for single-lookup tasks, `high` or above for deep reasoning or multi-file analysis — overrides session effort level; omit to inherit
- `memory`: `user`, `project`, or `local` — only when cross-session state is genuinely needed
- `isolation: worktree` — only when the agent modifies files and needs an isolated copy
- `skills`: list of skill names preloaded at agent startup — different from the `source_keys` metadata field
- `color`: UI color for the agent tile (`red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`, `cyan`)
- `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 `sources.md` — see Step 4 for where that file lives (plugin/APM scope only). Omit entirely when no research was used.
```yaml
source_keys:
- my-source-slug
```
**System prompt body** — write as a direct role instruction:
- Open with: "You are a [role]. When invoked, [primary action]."
- Cover: inputs expected, process steps, output format, error handling
- One job per agent
### Step 3 — Fill in the Copilot agent file (project/user scope only)
Skip this step entirely at plugin/APM scope — there is no separate Copilot file there. The single `.apm/agents/<name>.agent.md` file from Step 2 already compiles to both Claude Code and Copilot CLI via `apm compile`.
**Two distinct Copilot agent formats** exist, with different paths and field sets. Choose one based on the deployment target:
**CLI format** (default — what the scaffold creates):
- Path: `.github/agents/<name>.agent.md` (project) or `~/.copilot/agents/<name>.agent.md` (user)
- Extension: **must be `.agent.md`**
- Supported fields: `name` (required), `description` (required), `tools` (optional)
- `tools` uses Copilot aliases: `execute` (shell), `read`, `edit`, `search`, `agent`, `web`
- Body length limit: **30,000 characters** — content beyond this is silently truncated
**Cloud/IDE format** (use when targeting Copilot Chat in VS Code or GitHub.com):
- Path: `.github/copilot/agents/<name>.md` (note: plain `.md`, different directory)
- Additional fields available: `target` (`vscode`, `github-copilot`, or omit for both), `user-invocable` (set `false` to hide from manual invocation), `disable-model-invocation` (set `true` to require explicit user invocation), `mcp-servers` (MCP server config — processed by cloud runtime, ignored in VS Code)
- Body length limit: **30,000 characters** — silently truncated
**Do not include Claude Code-only fields in either format**: `maxTurns`, `isolation`, `memory`, `permissionMode`, `effort`, `hooks`, `mcpServers`.
**`source_keys`** — add the same top-level list as the CC file when research sources were used. Omit when no research was used.
**Delete the `<!-- -->` template comments from the frontmatter**, as in Step 2.
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 `sources.md` (plugin/APM scope only)
Skip at project/user scope. The file lives at the package root (alongside `apm.yml`), not inside `.apm/agents/` — otherwise tooling that scans that directory for agent definitions would treat it as an agent needing frontmatter (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 file it contributed to.
3. Write `sources.md` at the package root using the format below. Paths in `Contributing files:` are relative to the package root.
```markdown
# Sources
## slug-name
- **URL:** <source URL>
- **Research doc:** <path/to/research/sources.md relative to repo root>
- **Description:** <what this source covers>
- **Contributing files:** .apm/agents/<name>.agent.md
- **Status:** `extracted`
```
Each slug must match an H2 heading, and each slug must also appear in the `source_keys` list of the file listed under `Contributing files:`.
If no research sources are in context, delete `sources.md`.
### Step 5 — Validate and close
Run this checklist before invoking the audit.
**Every file, at every scope:**
- [ ] `name` present and kebab-case; `description` present
- [ ] System prompt body present and non-empty
- [ ] No `FILL IN:` placeholders and no `<!-- -->` template comments remain
**Plugin/APM scope — single file (`<name>.agent.md`):**
- [ ] `name` unique in scope; `description` action-first
- [ ] Every frontmatter field is in the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md` — the single source of truth, read as data by `validate.sh`. As of 2026-08-14: `name`, `description`, `model`, `source_keys`, `disallowedTools`. Nothing else — in particular no `tools`
- [ ] A read-only agent carries `disallowedTools` **and** says so in the body
**Project/user scope — Claude Code file (`<name>.md`):**
- [ ] `name` unique in scope; `description` action-first
**Project/user scope — Copilot CLI file (`<name>.agent.md`):**
- [ ] File extension is `.agent.md` (not `.md`)
- [ ] `name` matches the filename stem (e.g. `name: my-agent` in `my-agent.agent.md`)
- [ ] No Claude Code-only fields (`maxTurns`, `isolation`, `memory`, `permissionMode`, `effort`, `hooks`, `mcpServers`)
- [ ] Body does not exceed 30,000 characters
At plugin/APM scope, apply a **minor bump** to the resolved package's `apm.yml` `version` (single manifest, e.g. `1.0.4` → `1.1.0`).
Invoke `kyberforge:agent-audit` on the created file(s) before closing — validates the pair at project/user scope, the single file at plugin/APM scope.
**Commit verification.** Once the audit is clean, run `git add` and `git commit` for the new agent files — do not stop at staging. Then confirm `git log --oneline -1` differs from the hash captured before Step 1. A non-empty `git diff --stat` is not proof of completion: staged-but-uncommitted work is part of no commit and can be silently lost if the working tree is cleaned up. Only report the agent as done once the hash has actually changed.
## Improving an existing agent
### Step 1 — Verify inputs
Confirm the agent files exist and at least one improvement signal is present in the conversation or a referenced file.
If no signals: "This skill applies existing signals to an agent. For a blind review, examine the files manually or run a grill session first."
Verify `kyberforge:agent-audit` is available, as in the create flow's Prerequisites. Capture `git log --oneline -1` now, before making any edits — Step 5 needs it to verify a real commit landed.
**Partial state (project/user scope only)** — if one provider file exists but not the other, scaffold the missing one (`bash scripts/new-agent.sh <name> <root>`, file-by-file no-op) then continue. Doesn't apply at plugin/APM scope — single file, no partial-pair state.
### Step 2 — Gather and group signals
Read the current agent file(s). Collect all signals from the conversation.
Group by **root cause**, not symptom. One root cause → one fix.
```text
Example:
- User feedback: agent keeps trying to push to remote
- Session context: no scope boundary in system prompt
→ Root cause: system prompt lacks git scope constraint → fix: add explicit boundary
```
### Step 3 — Announce planned changes
Before editing, state which root causes were identified, what evidence supports each, and which files will change. Then proceed — edits are reversible via git.
### Step 4 — Apply changes
Edit any file the signals point to. Generalize the fix — find the underlying gap, not the specific example that failed. For every sentence you add, ask: "Would the agent get this wrong without it?" A shorter, focused definition consistently outperforms an exhaustive one. For Copilot files, verify no Claude Code-only fields are introduced. For a plugin/APM-scope single file, verify every field is still in the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md`, and that an existing `disallowedTools` fence was not dropped by the edit.
If the edit adds or removes research-sourced content, update `source_keys` in the edited file(s) and the corresponding entry in `sources.md` per Create flow's Step 4.
### Step 5 — Validate and close
Re-run the validation checklist from the create flow's Step 5 on any edited file.
At plugin/APM scope, apply a **patch bump** to the resolved package's `apm.yml` `version` (e.g. `1.0.4` → `1.0.5`).
Invoke `kyberforge:agent-audit` on the edited file(s) to confirm no regressions — the pair at project/user scope, the single file at plugin/APM scope.
**Commit verification.** Exactly as in the create flow's Step 5, against the hash captured at Step 1: commit the changed files once the audit is clean, and only report the improvement as done once `git log --oneline -1` shows a different hash.
**Commit verification.** Once the audit is clean, run `git add` and `git commit` — do not stop at staging. Re-run `git log --oneline -1` and confirm the hash changed from Step 1's. A non-empty `git diff --stat` is not proof: staged-but-uncommitted work is part of no commit and is lost if the tree is cleaned up. Report done only once the hash has changed.

View File

@@ -3,6 +3,7 @@
## templates/
Annotated agent definition templates copied by `scripts/new-agent.sh` when scaffolding a new agent.
All three scaffold the `description` in the three-part ADR-0020 shape — a `Use when` trigger clause, at most one capability clause, and a boundary clause — rather than the deleted action-verb opener, and each carries a delegate-don't-restate note in the body.
- **`claude-code.md`** — Claude Code agent definition template (project/user scope). Includes all supported frontmatter fields (required and optional) with inline guidance comments and `FILL IN:` placeholders.
- **`copilot.agent.md.template`** — Copilot CLI agent definition template (CLI format, project/user scope). Excludes cloud/IDE-only fields (`target`, `user-invocable`, `disable-model-invocation`, `mcp-servers`) and Claude Code-only fields. Uses Copilot tool aliases (`execute`, `read`, `edit`, `search`, `agent`, `web`).

View File

@@ -27,11 +27,17 @@
name: AGENT_NAME
<!-- Required. Lowercase letters and hyphens only. Must be unique within the scope. -->
description: FILL IN: Action-first description of what this agent does and when to invoke it.
<!-- Required. The primary signal for autonomous delegation.
Start with a verb: "Reviews...", "Analyzes...", "Generates..."
Be specific about the triggering condition and expertise domain.
Example: "Reviews pull request diffs for security issues. Use proactively after code changes." -->
description: FILL IN: Use when <trigger>. <One capability clause.> Not <thing> -> <name>.
<!-- Required. The primary signal for autonomous delegation, and preloaded into every
session whether or not this agent is ever used. Three parts, nothing else:
a trigger clause opening "Use when", at most one capability clause, and a
boundary clause naming a real sibling skill or agent.
250 characters is the target, 400 the hard ceiling (ADR-0020).
Do not open with an action verb ("Reviews...", "Analyzes...") — that rule was
deleted. Add "Use proactively" only if the runtime should delegate here without
the user naming this agent.
Example: "Use when a diff needs checking for injected credentials before it
merges. Not general code review -> code-reviewer." -->
<!-- model: sonnet
Optional. Aliases: sonnet, opus, haiku, fable. Or full model ID.
@@ -58,6 +64,11 @@ FILL IN: System prompt body. Write as a direct role instruction.
You are a FILL IN: role description. When invoked, FILL IN: primary action.
<!-- Delegate, don't restate. If an installed skill already owns a procedure this agent
needs, name it ("invoke `git-commits`") instead of transcribing it — a body that
restates a procedure an invocable skill owns is an agent-audit FAIL. One job per
agent. Delete this comment before shipping. -->
## Inputs
FILL IN: What inputs does this agent expect? (files, context, parameters)

View File

@@ -7,12 +7,17 @@ name: AGENT_NAME
<!-- Required. Lowercase letters and hyphens only. Must be unique within the scope.
Duplicate names are silently discarded — no warning is emitted. -->
description: FILL IN: Action-first description of what this agent does and when to invoke it.
<!-- Required. The primary signal for autonomous delegation.
Start with a verb: "Reviews...", "Analyzes...", "Generates..."
Include "Use proactively" to trigger automatic invocation.
Be specific about the triggering condition and domain.
Example: "Reviews pull request diffs for security issues. Use proactively after code changes." -->
description: FILL IN: Use when <trigger>. <One capability clause.> Not <thing> -> <name>.
<!-- Required. The primary signal for autonomous delegation, and preloaded into every
session whether or not this agent is ever used. Three parts, nothing else:
a trigger clause opening "Use when", at most one capability clause, and a
boundary clause naming a real sibling skill or agent.
250 characters is the target, 400 the hard ceiling (ADR-0020).
Do not open with an action verb ("Reviews...", "Analyzes...") — that rule was
deleted. Add "Use proactively" only if the runtime should delegate here without
the user naming this agent.
Example: "Use when a diff needs checking for injected credentials before it
merges. Not general code review -> code-reviewer." -->
<!-- tools: Read, Bash, Grep
Optional. Allowlist of tool names: a comma-separated string or a YAML list.
@@ -78,6 +83,11 @@ FILL IN: System prompt body. Write as a direct role instruction.
You are a FILL IN: role description. When invoked, FILL IN: primary action.
<!-- Delegate, don't restate. If an installed skill already owns a procedure this agent
needs, name it ("invoke `git-commits`") instead of transcribing it — a body that
restates a procedure an invocable skill owns is an agent-audit FAIL. One job per
agent. Delete this comment before shipping. -->
## Inputs
FILL IN: What inputs does this agent expect? (files, context, parameters)

View File

@@ -12,10 +12,16 @@
name: AGENT_NAME
<!-- Required. Kebab-case identifier. Home-directory version wins on name collision. -->
description: FILL IN: Action-first description of what this agent does and when to invoke it.
<!-- Required. Used by the runtime for automatic agent selection — quality matters.
Start with a verb: "Reviews...", "Analyzes...", "Generates..."
Example: "Reviews pull request diffs for security issues." -->
description: FILL IN: Use when <trigger>. <One capability clause.> Not <thing> -> <name>.
<!-- Required. Used by the runtime for automatic agent selection, and preloaded into
every session whether or not this agent is ever used. Three parts, nothing else:
a trigger clause opening "Use when", at most one capability clause, and a
boundary clause naming a real sibling skill or agent.
250 characters is the target, 400 the hard ceiling (ADR-0020).
Do not open with an action verb ("Reviews...", "Analyzes...") — that rule was deleted.
Keep it identical in wording to the Claude Code half of the pair.
Example: "Use when a diff needs checking for injected credentials before it
merges. Not general code review -> code-reviewer." -->
<!-- tools: ["read", "search", "edit"]
Optional. Array of tool names. Omit = all available tools. [] = no tools.
@@ -46,6 +52,11 @@ FILL IN: System prompt body. Should match the Claude Code version — the agent'
You are a FILL IN: role description. When invoked, FILL IN: primary action.
<!-- Delegate, don't restate. If an installed skill already owns a procedure this agent
needs, name it ("invoke `git-commits`") instead of transcribing it — a body that
restates a procedure an invocable skill owns is an agent-audit FAIL. One job per
agent. Delete this comment before shipping. -->
## Inputs
FILL IN: What inputs does this agent expect? (files, context, parameters)

View File

@@ -4,14 +4,52 @@ source_keys: []
# references/
## create.md
The create flow, loaded from SKILL.md Step 1 when no agent file exists at the target path.
Covers: prerequisites, the scaffold script and its scope walk-up, what to fill in at every scope,
and populating or deleting the package-root `sources.md`.
## improve.md
The improve flow, loaded from SKILL.md Step 1 when a file exists and at least one improvement
signal is present. Covers: signal verification, partial-pair recovery, root-cause grouping,
generalizing rather than patching, delegation over growth, and the ADR-0020 retrofit rule.
## contract.md
The description and body contract, loaded from SKILL.md Step 3 before any description is written
or any body restructured. Covers: the three-part description shape, banned description content,
boundary-target resolution, the 250/400 length tiers, the body role-instruction pattern, the
delegation rule that replaces a body word gate, and the invocation axis.
## plugin-scope.md
Field rules and the pre-audit checklist for the single vendor-neutral `.apm/agents/<name>.agent.md`
file. Loaded from SKILL.md Step 2 when the scaffold resolves plugin/APM scope.
## project-user-scope.md
Field rules and the pre-audit checklist for the Claude Code `.md` + Copilot `.agent.md` pair,
including the two distinct Copilot formats. Loaded from SKILL.md Step 2 when the scaffold resolves
project or user scope.
## deployment-modes.md
Agent scope hierarchy, precedence rules, and per-scope restrictions. Covers: which frontmatter fields a plugin/APM-scope agent may carry and the allowlist-vs-denylist shape rule that decides it (deferring to `agent-audit`'s `references/field-inventory.md` for the list itself), scoped identifiers for plugin subdirectory agents, cache isolation behaviour, and Copilot CLI path conventions. Loaded conditionally from SKILL.md when the destination is a plugin directory.
Scope hierarchy and precedence, scoped identifiers for plugin subdirectory agents, cache isolation
behaviour, and Copilot CLI path conventions. Loaded from SKILL.md Step 2 when precedence, paths or
cache isolation matter to the run.
## scripts.md
Conventions for the `new-agent.sh` scaffold script and any future scripts added to this skill. Covers: what scripts should and should not do, file placement, error handling, template variable conventions, and the no-interactive-prompts rule.
Conventions for the `new-agent.sh` scaffold script, the templates it copies, and any future script
in this skill. Loaded from `create.md` Step 1 when the script or a template has to change. Covers:
the no-interactive-prompts rule, structured output, idempotency, template variables, file
placement, error messages, and the no-restated-field-roster rule that `tests/new-agent.bats`
enforces.
## sources.md
Research provenance record for this skill. Lists the upstream research sources (claude-code-plugins and github-copilot-plugins research docs) that informed SKILL.md, the templates, and the deployment-modes reference. Used by `skill-audit` to validate the provenance chain.
Research provenance record for this skill. Lists the upstream research sources
(claude-code-plugins and github-copilot-plugins research docs) that informed SKILL.md and the
reference files. Used by `skill-audit` to validate the provenance chain.

View File

@@ -0,0 +1,117 @@
---
source_keys:
- claude-code-subagents-docs
- github-custom-agents-configuration
---
# The agent description and body contract
House contract, set by ADR-0020. The counts and the boundary targets are enforced by
`agent-audit`'s `scripts/validate.sh`; the prose patterns by the Vale styles it bundles; the
judgment calls by its reference files.
## Why the budget exists
An agent's `name` and `description` is loaded into every session's context at startup, whether or
not the agent is ever delegated to — the same cost a skill's description carries, so agents take
the same numbers. The body is different: it is not loaded into the caller's conversation at all,
it *becomes the system prompt of a fresh context* when the agent runs. That is why the body has no
word gate here and a skill body has one.
## Description
A description carries exactly three things:
1. **Trigger clause** — when to delegate, imperative: "Use when …", never "This agent …". Describe
the user's intent and the triggering condition, not the agent's internal mechanics.
2. **At most one capability clause** — what it does, one clause, no enumeration. Be specific
("reviews a diff for injected credentials", not "helps with security").
3. **Boundary clause** — form: `Not <thing> -> <name>.` Add one only where a near-miss agent or
skill could steal delegations.
Banned from a description; move it to the body or to `README.md`:
- Capability enumeration or feature lists
- Per-scope emission mechanics — which files the author skill writes at which scope changes no
delegation decision
- Output-format detail ("Produces a compact findings report with Why and Fix per finding")
- Composition or architecture notes ("composes X rather than duplicating Y", "cross-cutting")
- Implementation detail ("Self-validates via a bundled deterministic script")
- Restating the same trigger twice in two registers — a verb list, then the same verbs re-quoted
as user phrasings. This is a FAIL, not a suggestion.
**Do not open with an action verb.** "Reviews…", "Analyzes…", "Generates…" was the old house rule
and ADR-0020 deleted it: the opener is `Use when`, matching every skill in this corpus, so one
router reads one shape.
**"Use proactively" is conditional.** Add it only where the runtime should delegate without the
user naming the agent — an agent invoked by name does not need it, and it costs activations
elsewhere when added by reflex. The same conditional governs indirect triggers ("even if the user
doesn't say X"): add one only where the user's natural phrasing genuinely omits the domain word.
**Boundary targets must resolve.** The name after the arrow is checked against real skills under
`plugins/*/.apm/skills/<name>/` and real agents under `plugins/*/.apm/agents/<name>.agent.md`. A
target that does not exist sends the router nowhere. Verify it before writing it — do not invent a
plausible sibling.
**Length.** 250 characters SUGGESTION, 400 characters FAIL, counting the frontmatter value only
with YAML folding resolved. Treat 250 as the target: the SUGGESTION tier is what moves the corpus
average, the FAIL tier only stops outliers.
## Body
Write the body as a direct role instruction, addressed to the agent:
````markdown
You are a <role>. When invoked, <primary action>.
## Inputs
<what the agent is given: files, context, parameters>
## Process
<ordered steps; be explicit where ordering matters>
## Output
<what it produces: format, location, structure>
````
One job per agent. An agent covering two jobs gets delegated to for the wrong one.
**Delegation discipline replaces the word gate.** A plugin/APM agent is a single file with no
sibling `references/` directory: it cannot disclose progressively to itself, so its only way to
stay short is to *invoke* rather than *restate*. A body that transcribes a procedure a skill it
can invoke already owns is an `agent-audit` FAIL, and the fix is one line — "invoke `<skill>`".
- Restating: "To commit, check the message against Conventional Commits: type, scope,
description; header under 100 chars; …"
- Delegating: "Author commits with `git-commits`."
The same holds for a procedure another agent owns. What belongs in the body is what no invocable
skill covers: the agent's role, its boundaries, the order it works in, and the format it returns.
**State a read-only boundary in prose, not only in frontmatter.** `disallowedTools` denies the
tools it names and nothing else — never `Bash`, which an agent with no `tools` field inherits — so
an agent fenced only in frontmatter can still write through a shell redirect.
## Invocation axis
Decide before writing the description whether the agent is model-delegated (the runtime picks it)
or reached only by name (`@agent-<name>`).
Only Copilot's cloud/IDE format expresses that in frontmatter: `disable-model-invocation: true`
requires explicit invocation, and `user-invocable: false` hides an agent from manual invocation.
Both live in `.github/copilot/agents/<name>.md` and are inert in the CLI format. Claude Code has
no equivalent field, and neither does the vendor-neutral plugin/APM file, so at those scopes a
name-invoked agent still needs a description precise enough not to steal delegations — the
boundary clause is doing that work.
## One gate, two measurements
| Gate | SUGGESTION | FAIL | Counts |
|---|---|---|---|
| description | 250 chars | 400 chars | the `description:` value only |
| body (Copilot limit) | 30,000 chars | — | the body only; content past it is truncated silently |
The 30,000-character Copilot ceiling is a runtime truncation limit, not a quality target, and it
applies to a plugin/APM file too — that file compiles into a real Copilot agent downstream. An
agent body long enough to approach it has a delegation defect, not a length problem.

View File

@@ -0,0 +1,93 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-subagents-docs
- github-plugins-creating
---
# Creating a new agent
Return to `SKILL.md` Step 4 once Step 3 below is done — validation, the version bump and commit
verification are shared with the improve flow and are not repeated here.
## Prerequisites
Before touching the filesystem, confirm you have:
- [ ] Agent name (kebab-case, e.g. `code-reviewer`)
- [ ] Root directory — a path inside a package for plugin/APM scope, a project root, or `~` for
user scope
- [ ] Agent purpose — one sentence describing the task this agent handles
- [ ] Trigger condition — when should the runtime delegate to this agent?
If any are missing, stop and ask before proceeding.
`agent-audit` runs the validation in `SKILL.md` Step 4. It ships with the kyberforge plugin and
is co-installed with this skill; if it is unavailable, stop and ask the user to install
kyberforge before continuing.
Design for one job per agent. An agent covering two jobs is delegated to for the wrong one.
## Step 1 — Scaffold
```bash
bash scripts/new-agent.sh <name> <root>
```
Examples:
```bash
bash scripts/new-agent.sh code-reviewer packages/my-package/ # plugin/APM scope if packages/my-package/apm.yml has a type: field
bash scripts/new-agent.sh deploy-assistant .
bash scripts/new-agent.sh security-reviewer ~
```
The script resolves scope itself and prints which one it used and every path it wrote — read that
output rather than predicting it. It walks up from `<root>` for the nearest ancestor `apm.yml`
carrying a top-level `type:` field (`instructions`/`skill`/`hybrid`/`prompts`), which marks a
package root and means plugin/APM scope. An `apm.yml` with no `type:` is a marketplace-only
manifest: the walk skips it and keeps going. With no such manifest found, `<root>` being exactly
`~` (checked directly, no walk-up) is user scope and anything else is project scope. A bare
`plugin.json` no longer signals plugin scope — that path was replaced outright, not made
dual-mode, and falls through to project scope.
The script is file-by-file no-op: it skips any file that already exists, so re-running it to
complete a partial pair is safe.
If the script or a template under `assets/templates/` has to change to support this agent — a new
scope, a new scaffolded field, different output — read `references/scripts.md` first. Its
conventions are asserted by `tests/new-agent.bats`, and an edit that ignores them fails the suite.
## Step 2 — Fill in the file(s)
Take the scope the script reported and read the matching reference — `SKILL.md` Step 2 has the
table. That file carries the field rules and the pre-audit checklist for this scope; the other one
describes fields this run cannot use.
Every scaffolded file, at every scope:
1. Replace each `FILL IN:` placeholder.
2. Delete every `<!-- ... -->` template comment from the frontmatter. `apm compile` copies plugin
frontmatter verbatim and HTML comments are not valid YAML, so a leftover comment breaks the
file downstream on both harnesses.
3. Write the `description` against `references/contract.md` and the system prompt body against its
Body section.
## Step 3 — Populate or delete `sources.md`
Plugin/APM scope only — skip at project and user scope, which have no package root to hold the
file.
The scaffold writes a commented `sources.md` skeleton at the package root, alongside `apm.yml` and
not inside `.apm/agents/`, so that tooling scanning that directory for agent definitions does not
treat it as an agent missing its frontmatter (ADR-0010).
If a research `sources.md` is present in the conversation context, filter it to entries with
`` `extracted` `` status, work out which agent file each one contributed to, and fill in the
skeleton following the commented format already in the file. Paths in `Contributing files:` are
relative to the package root. Each slug must match an H2 heading and must also appear in the
`source_keys` list of every file named under its `Contributing files:`.
If no research sources are in context, delete `sources.md`.
Then return to `SKILL.md` Step 4.

View File

@@ -22,13 +22,14 @@ Agent definitions deploy at three scopes and behave differently at each. The sco
When the same agent `name` appears at multiple scopes, **user scope wins over project scope wins over plugin scope** in Claude Code. In Copilot CLI, repo-level agents override enterprise and org-level; home-directory (user) agents override repo-level on name collision.
## Plugin scope restrictions
## Which fields exist where
Plugin/APM agents (`.apm/agents/<name>.agent.md`) carry only the fields in the `apm-agent-allowlist` section of `agent-audit`'s `references/field-inventory.md`. That section is the authoritative list — `agent-audit`'s `validate.sh` reads it from there as data, and it changes — so consult it rather than any restatement of it. `apm compile` copies this frontmatter verbatim to both the Claude Code and Copilot CLI compile targets with no per-target integrator, so a harness-specific value is guaranteed wrong on at least one target (ADR-0016).
**The rule is about a field's shape, not a fixed roster.** `tools` is an **allowlist** whose vocabulary differs per harness — Claude Code names its own tools, Copilot CLI uses aliases (`execute`/`read`/`edit`/`search`/`agent`/`web`) — so under verbatim copy one value is wrong on one target. It stays out. `disallowedTools` is a **denylist**, and denying by name has no such conflict: a name the other harness does not recognise denies nothing, so the worst case is that the fence is absent there, never that a capability is wrongly granted. That asymmetry is why the denylist is admitted where the allowlist is not (ADR-0016's 2026-08-14 amendment). Claude Code honours it for plugin subagents — `docs/research/docs/claude-code-plugins/agent-definition.md:99` names the three fields plugin agents silently ignore (`hooks`, `mcpServers`, `permissionMode`) and `disallowedTools` is not among them. It is a partial fence: it denies only the tools it names, not `Bash`, which a plugin-scope agent with no `tools` inherits — so state read-only intent in the body too.
This makes the old "silently ignored at plugin scope" framing moot for the excluded fields. It's not that `hooks`, `mcpServers`, `permissionMode`, `tools`, `isolation`, `maxTurns`, `effort`, `memory`, `skills`, `color`, `initialPrompt`, or `background` are merely ignored at this scope — they are never written to the file at all. Copy the agent to `.claude/agents/` (project scope) or `~/.claude/agents/` (user scope) to use any of them.
Field rules are per scope and live with the scope: `references/plugin-scope.md` for the single
vendor-neutral file, `references/project-user-scope.md` for the Claude Code / Copilot pair. Read
one, not both. The short version is that plugin/APM frontmatter is an allowlist read from
`agent-audit`'s `references/field-inventory.md`, narrow because `apm compile` copies frontmatter
verbatim to every target (ADR-0016), while project and user scope carry the full per-provider
field sets.
## Scoped identifiers (Claude Code plugin agents only)

View File

@@ -0,0 +1,76 @@
---
source_keys:
- claude-code-subagents-docs
---
# Improving an existing agent
Return to `SKILL.md` Step 4 once Step 4 below is done — validation, the version bump and commit
verification are shared with the create flow and are not repeated here.
## Step 1 — Verify inputs
Confirm the agent file (or, at project and user scope, the pair) exists and that at least one
improvement signal is present in the conversation or in a referenced file.
If no signals are present, stop: "This skill applies existing signals to an agent. For a blind
review, run `agent-audit` instead."
`agent-audit` runs the validation in `SKILL.md` Step 4 and is co-installed with this skill; if
it is unavailable, stop and ask the user to install the kyberforge plugin before continuing.
**Partial pair — project and user scope only.** If one provider file exists and the other does
not, scaffold the missing one with `bash scripts/new-agent.sh <name> <root>` (file-by-file no-op)
and continue. Plugin/APM scope is a single file and has no partial state.
## Step 2 — Gather and group signals
Read the current file(s), then collect every signal from the conversation and from any path the
user referenced.
Group signals by **root cause**, not by symptom. Patching per symptom is the default failure mode:
three complaints often trace to one missing instruction. Ask: "What single gap in this agent
causes this cluster?" One root cause, one fix.
```text
Example:
- User feedback: the agent keeps trying to push to the remote
- Session context: no scope boundary in the system prompt
→ Root cause: the system prompt has no git scope constraint → fix: add an explicit boundary
```
## Step 3 — Announce planned changes
Before editing, state which root causes were identified, what evidence supports each, and which
files will change. Then proceed — edits are reversible via git, so no approval checkpoint is
needed.
## Step 4 — Apply changes
Edit whichever file the signals point to.
**Generalize, do not patch.** Fix the underlying gap, not the one example that failed. A fix
scoped to the cases you have seen overfits and performs worse on new input.
**Delegate rather than grow.** An agent body has no word ceiling, but a body that restates a
procedure a skill it can invoke already owns is an `agent-audit` FAIL. When a signal reports a
missing procedure, check first whether an installed skill owns it and name that skill instead of
transcribing it. See `references/contract.md`.
**Explain the why.** Reasoning-based instructions outperform rigid directives. A rule written in
all caps (ALWAYS/NEVER) is usually better reframed as why the behaviour matters, so the agent can
apply judgment at the edges.
**Retrofit before extending.** Any agent predating ADR-0020 has to meet the description contract
before any other edit lands — the gates are hot and carry no baseline file, so a one-line fix to a
non-compliant agent cannot be committed until its description meets `references/contract.md`.
Treat that retrofit as part of the same change, not a follow-up.
**Re-check the scope rules.** Read the reference for the resolved scope (`SKILL.md` Step 2) and
confirm the edit introduced no field that scope forbids, and dropped no `disallowedTools` fence
that was already there.
If the edit adds or removes research-sourced content, update `source_keys` in the edited file and
the matching `sources.md` entry — the create flow's Step 3 has the rules.
Then return to `SKILL.md` Step 4.

View File

@@ -0,0 +1,67 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-plugins-docs
---
# Plugin/APM scope — the single vendor-neutral file
One file, no counterpart: `<package-root>/.apm/agents/<name>.agent.md`. `apm compile` emits it to
both the Claude Code and the Copilot CLI target. The `.agent.md` extension here is convention, not
a Copilot marker — the file is vendor-neutral.
## Frontmatter
The permitted keys are the `apm-agent-allowlist` section of `agent-audit`'s
`references/field-inventory.md`. Read them from there as data — that section is the single source
of truth, `agent-audit`'s `validate.sh` parses it at load time, and it changes. Any restatement of
the roster, here or in a template or in script output, goes stale one step further out than the
list itself.
- `name` — kebab-case, must equal the filename stem, unique within the scope.
- `description` — write it against `references/contract.md`.
- Everything else — check the allowlist section before adding a key. A key outside it fails the
audit.
**Why the list is narrow.** `apm compile` copies frontmatter verbatim to every target with no
per-target integrator, so a harness-specific value is wrong on at least one of them (ADR-0016).
The rule is about a field's *shape*, not a fixed roster:
- `tools` is an **allowlist** whose vocabulary differs per harness — Claude Code names its own
tools, Copilot CLI uses aliases (`execute`/`read`/`edit`/`search`/`agent`/`web`) — so one value
is wrong on one target. It stays out. Omitting it means inherit-all-tools on both, which is
never wrong.
- `disallowedTools` is a **denylist**, and denying by name cannot fail that way: a name the other
harness does not recognise denies nothing, so the worst case is a missing fence, never a wrongly
granted capability. That asymmetry is the whole exception (ADR-0016's 2026-08-14 amendment).
Claude Code honours it for plugin subagents; the three fields plugin agents do silently ignore
are `hooks`, `mcpServers` and `permissionMode`, and this is not one of them. Copilot's handling
of the key is unconfirmed, which ADR-0016 accepts as a stated risk.
- The Claude-only knobs (`isolation`, `maxTurns`, `effort`, `memory`, `permissionMode`, `skills`,
`color`, `initialPrompt`, `background`, `hooks`, `mcpServers`) have no Copilot equivalent and
are never written to this file at all. "Silently ignored at plugin scope" is the wrong framing:
they are absent, not tolerated. To use any of them, copy the agent to `.claude/agents/`
(project scope) or `~/.claude/agents/` (user scope).
Write `disallowedTools` on every read-only plugin-scope agent — and say the agent is read-only in
the body as well, because the fence does not cover the inherited `Bash` tool.
`source_keys` is provenance metadata, not a runtime field: both harnesses ignore it. Add it only
when research sources informed the agent, with slugs matching H2 headings in the package root's
`sources.md`.
## Body
Follow the Body section of `references/contract.md`: role instruction, one job, and delegation
to installed skills instead of transcribed procedure.
## Before invoking `agent-audit`
- [ ] `name` kebab-case, matching the filename stem, unique in scope
- [ ] `description` written to `references/contract.md`
- [ ] Every frontmatter key present in the `apm-agent-allowlist` section — in particular no `tools`
- [ ] No `FILL IN:` placeholder and no `<!-- ... -->` template comment anywhere in the file
- [ ] System prompt body non-empty, and a read-only agent says so in prose as well as in
`disallowedTools`
Then return to the flow reference you came from.

View File

@@ -0,0 +1,106 @@
---
source_keys:
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
- github-cli-plugin-reference
---
# Project and user scope — the Claude Code / Copilot pair
Two files per agent, written in one pass and kept in step: a Claude Code `.md` and a Copilot CLI
`.agent.md`. The system prompt body is the same in both — the agent's task does not change with
the provider. The frontmatter is not.
| Scope | Claude Code | Copilot CLI |
|---|---|---|
| Project | `.claude/agents/<name>.md` | `.github/agents/<name>.agent.md` |
| User | `~/.claude/agents/<name>.md` | `~/.copilot/agents/<name>.agent.md` |
## Claude Code file
**`name`** — lowercase letters and hyphens only, unique within the scope. Claude Code discards a
duplicate silently.
**`description`** — write it against `references/contract.md`. It is the primary signal for
autonomous delegation.
**`tools`** — an allowlist; omit it to inherit every tool from the parent. Use `Agent(type1,type2)`
to restrict which subagent types this agent may spawn, and omit `Agent` entirely to stop it
spawning any. Five tools reach no subagent whatever this field says — `AskUserQuestion`,
`EnterPlanMode`, `ExitPlanMode`, `ScheduleWakeup` and `WaitForMcpServers` — so listing one buys
nothing. The single exception is `ExitPlanMode`, available when the parent session runs
`permissionMode: plan`.
**`disallowedTools`** — a denylist, applied before `tools` and taking precedence over it. Supports
`mcp__<server>`, `mcp__<server>__*` and `mcp__*` globs. Both a YAML list and a delimited string
are accepted; this repo writes the comma-separated string form (`disallowedTools: Edit, Write,
NotebookEdit`) — match it.
**`model`** — set it when the agent needs a different capability tier (`haiku` for fast lookups,
`opus` for deep reasoning). Resolution order is `CLAUDE_CODE_SUBAGENT_MODEL` → the per-invocation
parameter → this field → the main session model, so the frontmatter value is a low-priority
default rather than a guarantee.
Optional fields worth considering, none of which exist at plugin/APM scope:
- `maxTurns` — cap agentic turns on a bounded task, to stop a runaway
- `effort` — `low` for a single lookup, `high` or above for multi-file analysis; omit to inherit
- `memory` — `user`, `project` or `local`; only when cross-session state is genuinely needed
- `isolation: worktree` — only when the agent modifies files and needs an isolated copy
- `skills` — skill names preloaded at agent startup; unrelated to the `source_keys` metadata field
- `color` — the UI tile colour (`red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`,
`cyan`)
- `background` — `true` forces background execution
- `initialPrompt` — auto-submitted as the first turn when the agent activates as the main session
thread; set it only for a main-thread agent, never for a subagent
`hooks`, `mcpServers` and `permissionMode` are honoured at these two scopes and nowhere else — a
plugin agent carrying them is ignored silently.
A subdirectory under `agents/` does not affect the agent's name at these scopes; it does at plugin
scope, which is one reason `references/deployment-modes.md` recommends keeping agents flat.
## Copilot file
Two Copilot formats exist, with different paths and different field sets. Pick one:
**CLI format** — what the scaffold writes.
- Path: `.github/agents/<name>.agent.md` (project) or `~/.copilot/agents/<name>.agent.md` (user)
- The `.agent.md` extension is mandatory: Copilot CLI does not pick up a plain `.md` file in
`agents/`, and fails silently rather than reporting it
- Fields: `name` (required, must equal the filename stem), `description` (required), `tools`
(optional)
- `tools` uses Copilot aliases, not Claude tool names: `execute` (shell), `read`, `edit`,
`search`, `agent`, `web`; MCP tools as `server-name/tool-name` or `server-name/*`
**Cloud/IDE format** — for Copilot Chat in VS Code or on GitHub.com.
- Path: `.github/copilot/agents/<name>.md` — a plain `.md`, in a different directory
- Adds `target` (`vscode`, `github-copilot`, or omit for both), `user-invocable`,
`disable-model-invocation` and `mcp-servers` (processed by the cloud runtime, ignored in VS
Code). These four are inert in the CLI format — do not write them there
- This is the only format that can express the invocation axis in frontmatter; see the Invocation
axis section of `references/contract.md`
Both formats truncate a body past **30,000 characters** silently.
Copilot has no `permissionMode`, `maxTurns`, `isolation`, `memory`, `effort`, `hooks` or
`mcpServers`. Never let those cross over from the Claude Code file.
## Before invoking `agent-audit`
Both files:
- [ ] `name` present and kebab-case; `description` written to `references/contract.md`
- [ ] System prompt body present, non-empty and equivalent across the pair
- [ ] No `FILL IN:` placeholder and no `<!-- ... -->` template comment left
Copilot file only:
- [ ] Extension is `.agent.md` (CLI format), and `name` matches the filename stem
- [ ] No Claude Code-only field present
- [ ] Body under 30,000 characters
Then return to the flow reference you came from.

View File

@@ -19,7 +19,7 @@ source_keys:
- **URL:** context7:/websites/code_claude
- **Research doc:** plugins/kyberforge/docs/research/docs/claude-code-plugins/sources.md
- **Description:** Official Claude Code documentation site indexed by Context7 — plugin manifest schema, subagent definition types, marketplace JSON format, agent markdown file format
- **Contributing files:** SKILL.md, references/deployment-modes.md
- **Contributing files:** SKILL.md, references/create.md, references/deployment-modes.md, references/plugin-scope.md
- **Status:** `extracted`
## claude-code-plugins-docs
@@ -27,7 +27,7 @@ source_keys:
- **URL:** https://code.claude.com/docs/en/plugins
- **Research doc:** plugins/kyberforge/docs/research/docs/claude-code-plugins/sources.md
- **Description:** Official Claude Code plugin authoring guide — plugin structure, manifest fields, loading methods, skill namespacing, agent activation, marketplace submission
- **Contributing files:** SKILL.md, references/deployment-modes.md
- **Contributing files:** SKILL.md, references/deployment-modes.md, references/plugin-scope.md
- **Status:** `extracted`
## claude-code-subagents-docs
@@ -35,7 +35,7 @@ source_keys:
- **URL:** https://code.claude.com/docs/en/sub-agents
- **Research doc:** plugins/kyberforge/docs/research/docs/claude-code-plugins/sources.md
- **Description:** Official Claude Code subagent reference — definition format, all frontmatter fields, scope priority, built-in agents, CLI flags, environment variables, known limitations
- **Contributing files:** SKILL.md, references/deployment-modes.md
- **Contributing files:** SKILL.md, references/create.md, references/improve.md, references/contract.md, references/deployment-modes.md, references/project-user-scope.md
- **Status:** `extracted`
## context7-github-en-copilot
@@ -43,7 +43,7 @@ source_keys:
- **URL:** context7:/websites/github_en_copilot
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** Official GitHub Copilot documentation indexed by Context7; covers CLI plugins, custom agents, SDK, and marketplace
- **Contributing files:** SKILL.md, references/deployment-modes.md
- **Contributing files:** references/deployment-modes.md, references/project-user-scope.md
- **Status:** `extracted`
## github-custom-agents-configuration
@@ -51,7 +51,7 @@ source_keys:
- **URL:** https://docs.github.com/en/copilot/reference/custom-agents-configuration
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** Reference for cloud and IDE custom agent definition format — frontmatter fields, tool aliases, MCP server config, secrets interpolation, scoping hierarchy
- **Contributing files:** SKILL.md, references/deployment-modes.md
- **Contributing files:** references/contract.md, references/deployment-modes.md, references/project-user-scope.md
- **Status:** `extracted`
## github-cli-plugin-reference
@@ -59,7 +59,7 @@ source_keys:
- **URL:** https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-plugin-reference
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** Full CLI plugin reference — plugin.json schema, marketplace.json schema, all CLI commands and flags, install specification formats, loading precedence, env vars, LSP config
- **Contributing files:** SKILL.md, references/deployment-modes.md
- **Contributing files:** references/deployment-modes.md, references/project-user-scope.md
- **Status:** `extracted`
## github-plugins-creating
@@ -67,7 +67,7 @@ source_keys:
- **URL:** https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-creating
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** How-to for creating Copilot CLI plugins — plugin structure, agent and skill authoring, hooks format, MCP config, development lifecycle
- **Contributing files:** SKILL.md
- **Contributing files:** references/create.md
- **Status:** `extracted`
## github-plugins-finding-installing

View File

@@ -157,9 +157,11 @@ find_package_root() {
done
}
# `read` consumes a single line, so kind and path are emitted on one
# space-separated line rather than two `echo`s — kind first (never contains
# spaces), path last (absorbs any spaces in the path safely).
# kind and path are emitted on one space-separated line rather than two
# `echo`s — kind first (never contains spaces), path last (absorbs any spaces
# in the path safely). `mapfile`/`readarray` would need bash 4.0+, which
# macOS's stock /bin/bash 3.2 is not; a here-string `read` splits the single
# line without it. Same form as skill-author's new-skill.sh, deliberately.
WALK_RESULT="$(find_package_root "$ROOT")"
read -r WALK_KIND WALK_ROOT <<< "$WALK_RESULT"