Files
holocron/plugins/kyberforge/.apm/skills/agent-author/SKILL.md
Defame1297 f4bb1cf4e5 docs: finish reconciling the agent write fence across the toolchain
The previous round taught agent-audit's validator to permit disallowedTools but
left the skill that writes agents still forbidding it, in six places. Running
agent-author on any of the three fenced orchestrators would have stripped the
fence, and nothing would have caught it: the validator's allowlist is a permit
list, so an absent field passes. The template was the worst of them, since its
comment is copied verbatim into every new plugin-scope agent.

Where a list had to be restated it is now a pointer to field-inventory.md's
apm-agent-allowlist instead -- the same data validate.sh reads -- because a
roster copied into a template goes stale one step further out than the roster
itself. Where the text has to teach something it teaches the shape rule rather
than the exception: tools is an allowlist whose vocabulary differs per harness,
so verbatim copy makes one value wrong on one target; disallowedTools is a
denylist, where an unrecognised name denies nothing, so the worst case is a
missing fence rather than a wrongly granted capability.

ADR-0016's amendment claimed an unrecognised key is inert on Copilot while the
same ADR's Context says that behaviour is unconfirmed by research -- asserting
as settled the exact thing it flags as unknown, and justifying it with apm's
compile-time behaviour, which says nothing about Copilot's runtime. It is
rewritten into labelled tiers: confirmed for Claude Code with citations,
inferred by analogy for Copilot with the analogy's limits stated, unverified
where it is unverified, and the residual risk accepted explicitly with its
blast radius. It also no longer claims to restore a write sandbox: the denylist
does not deny Bash, which these agents inherit and legitimately need.

docs/hooks.md called the old root hooks.json a stale sync artifact -- it was
added in the plugin's creating commit and pointed at by main's Copilot manifest
-- and claimed both ecosystems now resolve hooks/hooks.json. Copilot does not:
its hooks field has no default and no compiled manifest declares one, so it
resolves nothing. Recorded as the gap it is, with re-injection noted as a
follow-up rather than asserted away. Its event list is marked partial.

Also: new-agent.bats asserted a hardcoded four-field allowlist and would have
rejected a scaffolded agent carrying the field the ADR now blesses; it reads
field-inventory.md too. And ADR-0016's premise that Claude's tools: is
space-separated was wrong -- it takes a comma-separated string or a YAML list.
The incompatibility with Copilot is the vocabulary, not the punctuation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
2026-08-14 12:30:30 +00:00

19 KiB

name, description, allowed-tools, metadata
name description allowed-tools metadata
agent-author 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. Bash Read Write Edit
category source_keys
factory
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.

Route

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.

Determine which flow before touching the filesystem:

  • 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?"

Signals: grill session output, inline user feedback, session context describing what went wrong.

Creating a new agent

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, 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. Then capture git log --oneline -1 before touching the filesystem — Step 5 needs it to verify a real commit landed.

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.

Step 1 — Scaffold

Run the scaffold script with the agent name and root directory:

bash scripts/new-agent.sh <name> <root>

Examples:

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 ~

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

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.

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.
# 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.

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.