Skip to main content

Tool Frontmatter Schemas

Managed-file marker — per format (single source of truth)​

Every file written by setup-agents carries a managed-file marker so upgrade and add can detect whether a file is safe to overwrite. Both the syntax and the line it sits on are format-dependent:

Target fileMarkerLine
.github/agents/*.agent.md# generated by platform-skills2 — inside the YAML frontmatter
.cursor/rules/*.mdc# generated by platform-skills2 — inside the YAML frontmatter
AGENTS.md, .windsurfrules<!-- generated by platform-skills -->1
agents/openai.yaml# generated by platform-skills1
.vscode/settings.json, .claude/settings.jsonNo marker — JSON has no comment syntax. These files are merge-only, never full-write. They never need an overwrite guard because the mode always merges into the existing document.—
CLAUDE.mdNo marker — append-only. Never overwrite.—

Why frontmatter formats put the marker on line 2​

.agent.md and .mdc are frontmatter formats: the --- delimiter must be the first bytes of the file. Standard frontmatter parsers stop looking once they see non-delimiter content, so an HTML comment above --- risks description, model, globs, and tools never being parsed — a generated agent that loads but is silently inert.

So for those two formats the marker moves inside the frontmatter as a YAML comment. YAML ignores # comments, so it round-trips safely and the file still starts at byte 0 with ---.

Overwrite guard (apply before writing any pre-existing agent file):

managed() { head -3 "$1" 2>/dev/null | grep -q 'generated by platform-skills'; }
# Usage: if [ -f "$target" ] && ! managed "$target"; then
# echo "⚠️ $target exists and is hand-authored — skipping. Inspect manually."
# fi

head -3, not head -1 — it must catch the line-1 markers (AGENTS.md, agents/openai.yaml) and the line-2 markers inside frontmatter. A head -1 guard misclassifies every generated .agent.md and .mdc as hand-authored, so upgrade and add silently skip them. The window stays tight at 3 lines so a stray mention deeper in a hand-authored file cannot trip it.

The grep matches both comment styles (<!-- and #) because it looks only for the common substring.

References: generate mode Step 7, add mode Step 3. The rule lives here — do not re-state it in mode files.


GitHub Copilot .agent.md​

Agent files go in .github/agents/<role>.agent.md.

VS Code custom agent (target: vscode)​

---
# generated by platform-skills
description: <one sentence — shown in agent picker and @mention tooltip>
model: <chosen in Step 6b — see generate mode>
target: vscode
tools:
- read
- execute
- edit
- search
---

--- must be the first line — see "Managed-file marker" above.

MCP servers for VS Code are configured in .vscode/settings.json (see MCP wiring section below), not in .agent.md frontmatter — mcp-servers is ignored by the VS Code Copilot Chat runtime for custom agents.

Copilot cloud agent (target: github-copilot)​

---
# generated by platform-skills
description: <one sentence — shown in agent picker and @mention tooltip>
model: <chosen in Step 6b — see generate mode>
target: github-copilot
tools:
- read
- execute
- edit
- search
mcp-servers:
github:
type: 'http'
url: 'https://api.githubcopilot.com/mcp/'
tools:
- github/create_pull_request
- github/get_file_contents
- github/list_commits
# Scope to only the tools this agent actually needs — avoid tools: ["*"]
---

mcp-servers is only used in cloud (worktree) agent profiles. Omit target entirely to generate a single file that applies to both VS Code and Copilot App — in that case, omit mcp-servers (VS Code ignores it, but it is dead config and confusing).

Built-in tool aliases: read (file reading), execute (shell), edit (file modification), search (codebase/text), web (URL/fetch). MCP server tools are referenced as <server-name>/<tool> or <server-name>/*. Read-only agents (reviewer, navigator): omit execute, edit from tools.

Cursor .mdc​

---
# generated by platform-skills
description: <one sentence — shown in Cursor UI>
globs: <e.g. "src/**/*.py,tests/**/*.py">
alwaysApply: false
---

--- must be the first line — Cursor skips rule files it cannot read description, globs, and alwaysApply from. See "Managed-file marker" above.

Coordinator: alwaysApply: true or broad globs. Navigator: globs: "**/*" with alwaysApply: false — broad coverage without forcing activation on every file open.

Windsurf .windsurfrules​

Add if .windsurfrules exists in the repo or developer uses Windsurf:

<!-- generated by platform-skills -->
# <repo> — Windsurf Rules

AGENTS.md is the source of truth. Read it first.

## Agents
| Agent | Owns | Invoke when |
|-------|------|-------------|
| coordinator | routing, planning | start of any multi-step task |
| [role] | [paths] | [trigger] |

## Off-limits
<from AGENTS.md off-limits section>

Add to verify.sh: test -f .windsurfrules && check "Windsurf rules present" "grep -q 'generated by platform-skills' .windsurfrules" || info "Windsurf rules"

Claude Code CLAUDE.md section​

Append — never replace existing content:

## Agent Context

> AGENTS.md is the source of truth. Start every session by reading it.

| Agent | Owns | Handoff trigger |
|-------|------|----------------|
| coordinator | routing, AGENTS.md | always first |
| app | src/, tests/ | code/test requests |
| reviewer | read-only | pre-merge reviews |
| navigator | read-only, any file | "help me understand" |

Codex — AGENTS.md is the whole integration​

Codex needs no generated config. It discovers AGENTS.override.md then AGENTS.md, walking from the project root (typically the Git root) down to the working directory, taking at most one instruction file per directory and concatenating them root-first so deeper files override shallower ones. The combined size is capped by project_doc_max_bytes — 32 KiB by default.

There is no repo-level YAML roster and no $-prefix activation. Do not write either claim into AGENTS.md; the template's Codex subsection states the real behaviour and always stays (see build mode Step 7).

agents/openai.yaml — setup-agents tooling metadata​

This file is not read by Codex. It is setup-agents' own machine-readable record of the roster and the per-agent model choices, consumed by:

  • scripts/verify-agents.sh — a presence check only (test -f agents/openai.yaml) when the manifest carries the codex token. It does not parse this file. Roster completeness comes from the ## Agent roster table in AGENTS.md, so deleting or corrupting openai.yaml fails one presence check and weakens no per-agent completeness check
  • upgrade mode — re-surfacing the model selections from the previous run

State that in the file's header comment (the asset template already does) so nobody mistakes it for Codex config. Generate it when the codex manifest token is present; a repo that skips it loses those two features and nothing else.

The file must preserve the interface: and policy: top-level keys — tests/validate-skill.sh checks them.

# generated by platform-skills
# setup-agents tooling metadata — not a Codex-discovered config file.
interface:
display_name: "<repo display name>"
short_description: "<one sentence>"
default_prompt: "<default prompt>"

policy:
allow_implicit_invocation: true

agents:
coordinator:
description: Lead orchestrator. Source of truth is AGENTS.md.
model: <model chosen in Step 6b>
app:
description: App agent — src/, tests/, Dockerfile
model: <model chosen in Step 6b>
navigator:
description: Read-only guide — helps understand the codebase
model: <model chosen in Step 6b>

Do not hardcode a model name — use the placeholder and populate from Step 6b. Stale model IDs (o3-mini, gpt-4o) rot silently.

copilot-setup-steps.yml​

Generated when Copilot App detected. Use the asset template — do not regenerate inline:

bash assets/render.sh assets/copilot-setup-steps.template.yml \
CHECKOUT_SHA="<fetch>" CHECKOUT_VERSION="4" \
SETUP_TERRAFORM_SHA="<fetch>" SETUP_TERRAFORM_VERSION="3" TERRAFORM_VERSION="<detected>" \
CONFIGURE_AWS_SHA="<fetch>" CONFIGURE_AWS_VERSION="4" \
> .github/workflows/copilot-setup-steps.yml

Remove blocks for runtimes not present in the repo (Node, Python, Java/Kotlin). Keep only what the repo actually uses.

SHA pins: fetch the commit SHA for the release tag — never use heads/main.

gh api repos/actions/checkout/git/ref/tags/v4 --jq '.object.sha'
gh api repos/hashicorp/setup-terraform/git/ref/tags/v3 --jq '.object.sha'

If the tag is annotated (object.type == "tag"), follow the dereference URL to get the commit SHA.

MCP wiring​

VS Code — merge, do not overwrite​

Use https://api.githubcopilot.com/mcp/ for the GitHub MCP server in VS Code. This endpoint authenticates via the developer's existing Copilot OAuth session — no PAT to create, rotate, or store. The old npx @modelcontextprotocol/server-github + GITHUB_PERSONAL_ACCESS_TOKEN approach is deprecated in favour of this.

.vscode/mcp.json (current VS Code-native format):

{
"servers": {
"filesystem": { "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] },
"github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/" }
}
}

.vscode/settings.json (older Copilot-specific key — kept for compatibility):

{
"github.copilot.chat.mcpServers": {
"filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] },
"github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/" }
}
}

Claude Code (.claude/settings.json)​

Claude Code has no Copilot OAuth session, so api.githubcopilot.com/mcp/ does not work here. Reference a token from the environment instead of storing one:

{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" }
}
}
}

${GITHUB_TOKEN} resolves from the shell environment. The developer exports a short-lived token in their own shell profile; setup-agents never reads, writes or creates it, and no secret lands in settings.json.