Custom Copilot agents: What 2,500 repositories teach us

GitHub Copilot now supports custom agents defined in agents.md files, letting you replace a single general assistant with a team of specialists: @docs-agent for technical writing, @test-agent for quality assurance, or @security-agent for security analysis. Each file defines an agent persona through frontmatter and custom instructions.

An analysis of over 2,500 public agents.md files shows a clear pattern separating effective agents from ineffective ones. The failures tend to be vague — "You are a helpful coding assistant" — while successes look more like "You are a test engineer who writes tests for React components, follows these examples, and never modifies source code." The best files give an agent a specific job, exact commands to run, well-defined boundaries, and concrete examples of good output.

What separates successful agent files

  • Commands go early: Put executable commands like npm test, npm run build, or pytest -v in an early section, including flags and options, not just tool names. Agents reference these frequently.
  • Show, don't tell: One real code snippet demonstrating your style is worth more than several paragraphs of description. Show what good output looks like.
  • Define boundaries: Tell the agent what it must never touch: secrets, vendor directories, production configs, or specific folders. "Never commit secrets" appeared as the most common helpful constraint.
  • Name your stack precisely: Say "React 18 with TypeScript, Vite, and Tailwind CSS," not "React project." Include versions and key dependencies.
  • Cover six areas: Files that hit commands, testing, project structure, code style, git workflow, and boundaries rank in the top tier.

A working docs-agent example

Here's a documentation agent stored at .github/agents/docs-agent.md:

---
name: docs_agent
description: Expert technical writer for this project
---

You are an expert technical writer for this project.

## Your role
- You are fluent in Markdown and can read TypeScript code
- You write for a developer audience, focusing on clarity and practical examples
- Your task: read code from `src/` and generate or update documentation in `docs/`

## Project knowledge
- **Tech Stack:** React 18, TypeScript, Vite, Tailwind CSS
- **File Structure:**
  - `src/` – Application source code (you READ from here)
  - `docs/` – All documentation (you WRITE to here)
  - `tests/` – Unit, Integration, and Playwright tests

## Commands you can use
Build docs: `npm run docs:build` (checks for broken links)
Lint markdown: `npx markdownlint docs/` (validates your work)

## Documentation practices
Be concise, specific, and value dense
Write so that a new developer to this codebase can understand your writing, don’t assume your audience are experts in the topic/area you are writing about.

## Boundaries
- ✅ **Always do:** Write new files to `docs/`, follow the style examples, run markdownlint
- ⚠️ **Ask first:** Before modifying existing documents in a major way
- 🚫 **Never do:** Modify code in `src/`, edit config files, commit secrets

Why this file performs well

  • Clear role: Defines an expert technical writer with Markdown and TypeScript skills who reads code and writes docs.
  • Executable commands first: Provides tools the agent can actually run — npm run docs:build and npx markdownlint docs/.
  • Specific project knowledge: Names the tech stack with versions (React 18, TypeScript, Vite, Tailwind CSS) and exact file locations.
  • Real examples: Shows actual code demonstrating good output instead of abstract descriptions.
  • Three-tier boundaries: Uses an always-do / ask-first / never-do structure to prevent destructive mistakes.

Creating your first agent

Start with one focused task rather than a general helper. Good candidates include writing function documentation, adding unit tests, or fixing linting errors.

A minimal start needs only three elements:

  • Agent name: test-agent, docs-agent, lint-agent
  • Description: "Writes unit tests for TypeScript functions"
  • Persona: "You are a quality software engineer who writes comprehensive tests"

Copilot can generate one for you. In your IDE, create a new file at .github/agents/test-agent.md and use this prompt:

Create a test agent for this repository. It should:
- Have the persona of a QA software engineer.
- Write tests for this codebase
- Run tests and analyzes results
- Write to “/tests/” directory only
- Never modify source code or remove failing tests
- Include specific examples of good test structure

Copilot will produce a complete agent.md with persona, commands, and boundaries tailored to your codebase. Review the output, add YAML frontmatter, adjust commands for your project, and @test-agent is ready.

Six agents worth building

Each of the following examples includes suggested commands and boundaries; adjust them to match your project's reality.

@docs-agent

This agent reads code and generates API docs, function references, and tutorials. Give it commands like npm run docs:build and markdownlint docs/ so it can validate its own work. Direct it to write to docs/ and never touch src/.

  • What it does: Turns code comments and function signatures into Markdown documentation
  • Example commands: npm run docs:build, markdownlint docs/
  • Example boundaries: Write to docs/, never modify source code

@test-agent

Point this agent at your test framework (Jest, PyTest, Playwright) and give it the command to run tests. The critical boundary: it may write to tests but must never remove a failing test unless the user authorizes it.

  • What it does: Writes unit tests, integration tests, and edge case coverage
  • Example commands: npm test, pytest -v, cargo test --coverage
  • Example boundaries: Write to tests/, never remove failing tests unless authorized by user

@lint-agent

A low-risk agent since linters are designed to be safe. It fixes code style and formatting without changing logic. Give it commands that let it auto-fix style issues.

  • What it does: Formats code, fixes import order, enforces naming conventions
  • Example commands: npm run lint --fix, prettier --write
  • Example boundaries: Only fix style, never change code logic

@api-agent

This agent builds API endpoints. It needs to know your framework (Express, FastAPI, Rails), where routes live, and commands to start the dev server and test endpoints. The key boundary: it can modify API routes but must ask before touching database schemas.

  • What it does: Creates REST endpoints, GraphQL resolvers, error handlers
  • Example commands: npm run dev, curl localhost:3000/api, pytest tests/api/
  • Example boundaries: Modify routes, ask before schema changes

@dev-deploy-agent

Handles builds and deployments to your local dev environment. Keep it locked down: only deploy to dev environments and require explicit approval for risky actions.

  • What it does: Runs local or dev builds, creates Docker images
  • Example commands: npm run test
  • Example boundaries: Only deploy to dev, require user approval for anything with risk

Starter template

---
name: your-agent-name
description: [One-sentence description of what this agent does]
---

You are an expert [technical writer/test engineer/security analyst] for this project.

## Persona
- You specialize in [writing documentation/creating tests/analyzing logs/building APIs]
- You understand [the codebase/test patterns/security risks] and translate that into [clear docs/comprehensive tests/actionable insights]
- Your output: [API documentation/unit tests/security reports] that [developers can understand/catch bugs early/prevent incidents]

## Project knowledge
- **Tech Stack:** [your technologies with versions]
- **File Structure:**
  - `src/` – [what's here]
  - `tests/` – [what's here]

## Tools you can use
- **Build:** `npm run build` (compiles TypeScript, outputs to dist/)
- **Test:** `npm test` (runs Jest, must pass before commits)
- **Lint:** `npm run lint --fix` (auto-fixes ESLint errors)

## Standards

Follow these rules for all code you write:

**Naming conventions:**
- Functions: camelCase (`getUserData`, `calculateTotal`)
- Classes: PascalCase (`UserService`, `DataController`)
- Constants: UPPER_SNAKE_CASE (`API_KEY`, `MAX_RETRIES`)

**Code style example:**
```typescript
// ✅ Good - descriptive names, proper error handling
async function fetchUserById(id: string): Promise<User> {
  if (!id) throw new Error('User ID required');
  
  const response = await api.get(`/users/${id}`);
  return response.data;
}

// ❌ Bad - vague names, no error handling
async function get(x) {
  return await api.get('/users/' + x).data;
}
Boundaries
- ✅ **Always:** Write to `src/` and `tests/`, run tests before commits, follow naming conventions
- ⚠️ **Ask first:** Database schema changes, adding dependencies, modifying CI/CD config
- 🚫 **Never:** Commit secrets or API keys, edit `node_modules/` or `vendor/`

Key takeaways

Effective custom agents come from specific personas and clear operating manuals, not vague prompts. Cover the six core areas — commands, testing, project structure, code style, git workflow, and boundaries. Start simple, test it, and add detail when the agent makes mistakes. The best agents.md files grow through iteration, not upfront planning.