Skip to content

Instructions and agents

These two primitives pair naturally. An instruction is a scope-attached rule: a coding standard, naming convention, or review checklist that fires when the agent touches files matching a glob. An agent is a persona scoping module: a named specialist (security reviewer, migration assistant, on-call SRE) the user invokes explicitly. Instructions shape how the model behaves on any given file. Agents shape who the model becomes when summoned.

Reach across harnesses differs and matters when you choose. See Primitives and targets for the full matrix; the gist is below.

A unit of policy that travels with a glob. Authors write one rule; APM compiles it to whatever frontmatter and directory the harness expects.

my-package/
apm.yml
.apm/
instructions/
python-style.instructions.md
pr-review-checklist.instructions.md

File names end in .instructions.md. The basename (minus the double extension) becomes the deployed filename stem.

---
description: Python style rules enforced on src/ and tests/
applyTo: "**/*.py"
---
- Use `pathlib.Path`, never `os.path`.
- Tests live next to the module under `tests/<module>/`.
- ...
KeyRequiredPurpose
descriptionyesOne-line summary; used in compiled context indexes
applyToyes for instructionsGlob (or comma-separated globs) the rule binds to

applyTo is the load-bearing field. Without it the rule is treated as unconditional and gets folded into compiled context files (AGENTS.md, GEMINI.md) instead of a per-file rule directory. With it, each harness wraps the body in its own scoping syntax.

applyTo accepts either a single glob or a comma-separated list of globs. Commas inside brace alternation (**/*.{css,scss}) are part of the glob and are NOT treated as list separators — only top-level commas split the list.

A YAML sequence is also accepted (generated by VS Code and some editors):

applyTo:
- "**/*.py"

When a YAML sequence contains multiple patterns, APM normalizes every non-null entry into the same comma-separated OR expression used by distributed compilation and target-native installation. Use a sequence when its source readability matters. To match a literal comma in a filename, escape it as \,.

---
description: Frontend style rules
applyTo: "**/*.{css,scss},**/*.tsx"
---

On Copilot the comma-list is preserved verbatim (Copilot splits it natively). Other targets use their own native instruction format; the target matrix below records the generated shape.

During distributed compilation, an explicitly scoped pattern may match files under supported top-level harness directories: .agents, .apm, .claude, .codex, .cursor, .gemini, .github, .kiro, .opencode, and .windsurf. Other hidden directories remain excluded.

  • Lead with bullets, not prose. Instructions are read by an agent mid-task.
  • One topic per file. Split python-style and python-testing; do not co-mingle.
  • Cite paths inside the repo with backticks; do not assume any other context is loaded.
  • Skip greetings and meta (“In this file we will…”). State the rule.
TargetOutput pathTransform
copilot.github/instructions/<name>.instructions.mdverbatim; applyTo preserved (comma-lists split natively by Copilot)
claude.claude/rules/<name>.mdapplyTo -> paths: list (comma-lists expanded to YAML array)
grok-build.grok/rules/<name>.md and folded into AGENTS.mdnative rule plus compiled root context
cursor.cursor/rules/<name>.mdcapplyTo -> globs: (scalar for single glob, YAML array for comma-lists); description auto-derived if missing
windsurf.windsurf/rules/<name>.mdapplyTo -> trigger: glob + globs: (scalar or YAML array); missing applyTo -> trigger: always_on
kiro.kiro/steering/<name>.mdapplyTo -> inclusion: fileMatch + fileMatchPattern:; missing applyTo -> inclusion: always
antigravity.agents/rules/<name>.mdapplyTo -> trigger: glob + globs: (scalar or YAML array); missing applyTo -> no frontmatter (unconditional rule)
codexfolded into AGENTS.mdcompile-only, no per-file deploy
geminifolded into GEMINI.mdcompile-only, no per-file deploy
opencodefolded into AGENTS.mdcompile-only, no per-file deploy

Source: src/apm_cli/integration/instruction_integrator.py, src/apm_cli/integration/targets.py.

A specialist persona invoked by name, with optional model and tool constraints. Think of it as a callable role — the user types @security-review and the harness loads the body as system context.

my-package/
apm.yml
.apm/
agents/
security-review.agent.md
migration-assistant.agent.md

File names end in .agent.md and live under .apm/agents/.

---
name: security-review
description: Reviews diffs for OWASP top-10 issues and missing input validation.
model: gpt-5
tools:
Read: true
Grep: true
---
You are a security reviewer. Your job is to inspect the working diff
for...
KeyRequiredPurpose
namerecommendedDisplay name; defaults to filename stem
descriptionyesUsed by Cascade and Copilot to decide when to surface the agent
modeloptionalPinned model the harness should switch to when invoked
toolsoptionalWhitelist of tools the persona may call
coloroptionalDisplay color for harnesses that render it (Copilot, Claude, OpenCode). OpenCode requires a #rgb/#rrggbb hex literal or one of its theme names; see “Common pitfalls” below
handoffsoptionalList of agent names (or VS Code structured handoff objects) this agent can hand off to

model and tools reach Copilot, Claude, Grok Build, Cursor, and OpenCode verbatim. Kiro receives description, model, and tools only; unknown frontmatter fields (including name) are stripped because Kiro derives agent identity from the deployed path, not from a name field. Tools are permission-bearing for Kiro: each value must be one of the supported capability tags (read, write, shell, web, subagent, knowledge, context, todo_list, @mcp, @builtin, *). If any unsupported tag is present, the agent is not deployed at all — APM fails closed. Kiro may warn and fall back if the specified model is unavailable; APM passes the value through without validation. Codex translates only name, description, and the Markdown body; APM does not yet generate the complete per-agent MCP transport definitions needed to preserve model or tools. When tools is present, apm install warns that the generated agent may inherit every project or session MCP server. Remove tools if unrestricted access is intentional; otherwise, do not use the generated agent with Codex. Windsurf and Gemini do not receive .agent.md files at all — use skills for Windsurf personas; Gemini CLI has no agents primitive.

OpenCode is the strictest of the verbatim targets: it requires tools as a tool-name: boolean mapping (not a list, not a string) and color to be either a #rrggbb hex literal or one of its theme names (primary, secondary, accent, success, warning, error, info). apm install -t opencode warns at install time when an agent ships shapes OpenCode would reject at load time — the file is still deployed, but the warning names the offending package and field so you can fix the source.

  • Open with role and scope in two sentences. The harness uses this as the system prompt.
  • Define what the persona will and will not do. Boundaries make agents useful.
  • List the artifacts it expects (“the open PR diff”, “the failing test name”) and what it returns (“a markdown review with file:line citations”).
  • Keep the body under 300 lines. Long agents drown the harness’s context window before the user’s task even loads.
TargetOutput pathTransform
copilot.github/agents/<name>.agent.mdverbatim
claude.claude/agents/<name>.mdverbatim
grok-build.grok/agents/<name>.mdverbatim
cursor.cursor/agents/<name>.mdverbatim
opencode.opencode/agents/<name>.mdverbatim
codex.codex/agents/<name>.tomlname and description -> TOML; body becomes developer_instructions; unsupported tools emits a warning
kiro.kiro/agents/<relative-stem>.mddescription, model, tools kept; name and unknown fields stripped; identity from path; fail closed on unsupported tools (ref: kiro.dev/docs/custom-agents, accessed 2026-08-03)
grok-build.grok/agents/<name>.mdverbatim
windsurfnot deployedWindsurf has no agents primitive — author personas as skills (Cascade auto-invokes by description)
gemininot deployedGemini CLI has no agents primitive

Source: src/apm_cli/integration/agent_integrator.py, src/apm_cli/integration/targets.py.

Pick instructions when:

  • The rule applies to a file pattern, not a workflow.
  • You want the agent to follow it implicitly, without being summoned.
  • The content is short, declarative, and reviewable as policy.

Pick agents when:

  • A user needs to invoke a specialist on demand.
  • The behaviour involves a sequence of steps, decisions, or model switches, not a static rule.
  • You want to scope tool access (e.g. read-only review persona).

Many packages ship both: instructions for the always-on guardrails, plus one or two agents for the deeper workflows that warrant a dedicated persona.

  • Missing applyTo. An instruction without applyTo stops being scope-attached and gets folded into the compiled context file. If you wanted Cursor or Copilot to scope it to **/*.ts, the rule will not bind.
  • Agent named default or start. These collide with script resolution in apm run. Pick a descriptive name.
  • Targeting an agent at Windsurf or Gemini. Neither harness has an agents primitive. Cascade auto-invokes skills by description and Gemini folds context into GEMINI.md. If a persona must reach those targets, author it as a skill under .apm/skills/<name>/SKILL.md.
  • tools: as a list, or a named color, on an OpenCode-targeted agent. OpenCode’s loader rejects tools: [Read, Grep] and colors like cyan. Use the mapping form (tools: {Read: true}) and either a #rrggbb hex literal or one of OpenCode’s theme names (primary, secondary, accent, success, warning, error, info). apm install -t opencode will warn at install time when it detects either shape; the file still deploys but OpenCode will refuse to load it.
  • Agent body that re-states global instructions. Agents inherit the workspace’s compiled context. Restate only what the persona needs to override or add; do not duplicate python-style inside code-reviewer.agent.md.
  • Co-mingling rules and persona. A 600-line .agent.md that contains style rules, review checklist, and persona prompt is two primitives in a trench coat. Split it.
Terminal window
apm compile --validate # frontmatter + structure check, no writes
apm install --dry-run --target cursor # preview agent deployment
apm preview <script> # if the agent is wired to a script

For the full primitive catalogue and target matrix, see Primitives and targets. For prompts and slash-commands, see Prompts. For packing and publishing, see Pack a bundle.