From Manual Commands to Consistent Workflows with Copilot CLI
I have been living inside a terminal for most of a decade, and the thing I keep relearning is that the terminal is fast and the team is slow. Every new session I re-explain my stack to a fresh shell. Every teammate gets a slightly different answer when they ask how to run a security audit on the same repo. Every pull request review starts with the same comment about formatting. None of this is hard. All of it is friction. And friction compounds.
GitHub Copilot CLI is one of the better answers to this kind of friction, but only if you stop using it as a fancy command generator. The real power is the custom agent: a Markdown file (a plain text file with the .md extension, written in lightweight formatting) that lives in your repository, encodes your team’s playbook, and turns ad-hoc prompting into a repeatable workflow. Once you have one, you stop re-explaining context every single session. The tool already knows.
This article is the version I wish I had read before I wrote my first custom agent. There are concrete examples, real trade-offs, and a checklist at the end. If you only have ten minutes, skip to the bottom and run one of the agents against your own repo.
What a custom agent actually is
A custom agent is a Markdown file with a small block of YAML frontmatter (machine-readable metadata placed between two --- lines at the top of the file) that tells Copilot CLI (GitHub’s command-line AI assistant) how to behave. The frontmatter describes the agent’s role, the tools it is allowed to use, and the model that should run it. The body of the file is the system prompt (the instructions that shape the AI’s tone, scope, and rules) for that agent.
You write one of these files per workflow. One for security audits. One for accessibility reviews. One for onboarding new engineers. Each agent is a separate, focused profile that you select with the /agent slash command in the CLI (a command you type starting with / to invoke a built-in tool, in this case a menu for picking which agent to load).
A real example, lifted from one of my repos, for a security audit agent:
---
name: Security audit
description: Run our standard security checks across repositories and produce a PR-ready checklist grouped by severity.
tools:
- gh
- git
- semgrep
- trivy
- gitleaks
- jq
---
## Instructions
You are the Security audit agent for this organization.
<aside class="edljx-related-tools" style="float:right;clear:right;width:320px;max-width:38%;margin:0 0 1.5rem 1.5rem;padding:1.25rem 1.5rem;background:var(--brand-surface,#ffffff);border:1px solid var(--brand-rule,#e6e1dc);border-radius:0.75rem;box-shadow:0 2px 8px rgba(107,33,128,0.06);font-size:0.9rem;color:var(--brand-ink,#1a1a1a);" aria-label="Related tools">
<ul class="edljx-related-tools__list" style="list-style:none;padding:0;margin:0;">
<li class="edljx-related-tools__item" style="margin-bottom:0.85rem;padding-bottom:0.85rem;border-bottom:1px solid var(--brand-rule,#e6e1dc);line-height:1.4;list-style:none;">
<a class="edljx-related-tools__item-name" style="display:block;color:var(--brand-accent,#ff8c42);text-decoration:none;font-weight:600;font-size:0.95rem;margin-bottom:0.15rem;" href="https://actualbudget.org" target="_blank" rel="noopener">Actual</a>
<span class="edljx-related-tools__item-desc" style="display:block;font-size:0.78rem;color:var(--brand-muted,#5c5c66);line-height:1.35;">Local-first personal finance tool based on zero-sum budgeting, supporting synchronization across dev...</span>
</li>
<li class="edljx-related-tools__item" style="margin-bottom:0.85rem;padding-bottom:0.85rem;border-bottom:1px solid var(--brand-rule,#e6e1dc);line-height:1.4;list-style:none;">
<a class="edljx-related-tools__item-name" style="display:block;color:var(--brand-accent,#ff8c42);text-decoration:none;font-weight:600;font-size:0.95rem;margin-bottom:0.15rem;" href="https://mailinabox.email/" target="_blank" rel="noopener">Mail-in-a-Box</a>
<span class="edljx-related-tools__item-desc" style="display:block;font-size:0.78rem;color:var(--brand-muted,#5c5c66);line-height:1.35;">Turns any Ubuntu server into a fully functional mail server with one command.</span>
</li>
<li class="edljx-related-tools__item" style="margin-bottom:0.85rem;padding-bottom:0.85rem;border-bottom:1px solid var(--brand-rule,#e6e1dc);line-height:1.4;list-style:none;">
<a class="edljx-related-tools__item-name" style="display:block;color:var(--brand-accent,#ff8c42);text-decoration:none;font-weight:600;font-size:0.95rem;margin-bottom:0.15rem;" href="https://evidence.dev" target="_blank" rel="noopener">Evidence</a>
<span class="edljx-related-tools__item-desc" style="display:block;font-size:0.78rem;color:var(--brand-muted,#5c5c66);line-height:1.35;">Code-based BI tool. Write reports using SQL and markdown and they render as a website.</span>
</li>
<li class="edljx-related-tools__item" style="margin-bottom:0.85rem;padding-bottom:0.85rem;border-bottom:1px solid var(--brand-rule,#e6e1dc);line-height:1.4;list-style:none;">
<a class="edljx-related-tools__item-name" style="display:block;color:var(--brand-accent,#ff8c42);text-decoration:none;font-weight:600;font-size:0.95rem;margin-bottom:0.15rem;" href="https://www.dokuwiki.org/DokuWiki" target="_blank" rel="noopener">Dokuwiki</a>
<span class="edljx-related-tools__item-desc" style="display:block;font-size:0.78rem;color:var(--brand-muted,#5c5c66);line-height:1.35;">Easy to use, lightweight, standards-compliant wiki engine with a simple syntax allowing reading the ...</span>
</li>
<li class="edljx-related-tools__item" style="margin-bottom:0.85rem;padding-bottom:0.85rem;border-bottom:1px solid var(--brand-rule,#e6e1dc);line-height:1.4;list-style:none;">
<a class="edljx-related-tools__item-name" style="display:block;color:var(--brand-accent,#ff8c42);text-decoration:none;font-weight:600;font-size:0.95rem;margin-bottom:0.15rem;" href="https://docker-mailserver.github.io/docker-mailserver/edge/" target="_blank" rel="noopener">docker-mailserver</a>
<span class="edljx-related-tools__item-desc" style="display:block;font-size:0.78rem;color:var(--brand-muted,#5c5c66);line-height:1.35;">Production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) runn...</span>
</li>
</ul>
<p class="edljx-related-tools__footer" style="margin:0.75rem 0 0;padding-top:0.5rem;border-top:1px solid var(--brand-rule,#e6e1dc);font-size:0.7rem;color:var(--brand-muted,#5c5c66);font-style:italic;text-align:center;">Curated by <a href="https://edljx.com" target="_blank" rel="noopener" style="color:var(--brand-accent,#ff8c42);text-decoration:none;font-style:normal;font-weight:500;">edljx.com</a></p>
</aside>
### Goal
For the repositories provided, run the team's standard security checks, summarize findings by severity (Critical, High, Medium, Low), and output a PR-ready checklist with owners and next steps.
### Operating Rules
- Prefer existing security tooling and config files (.semgrep.yml, .trivyignore, .gitleaks.toml)
- If a tool is missing, note it as a High severity coverage gap
- Redact tokens and credentials in output
- Use inclusive language (allowlist/denylist)
- Reference dates as "March 23, 2026"
### Standard Checks
1. Secret scanning: gitleaks detect --redact --no-git --source .
2. Container scanning: trivy fs . (if Dockerfile exists)
3. SAST (Static Application Security Testing, automated scanning of source code for known vulnerability patterns): semgrep scan --config .semgrep.yml (if config exists)
4. Dependency review: Confirm enabled via gh or record gap
This file is around 30 lines. It lives in .github/agents/ (a directory GitHub reserves for agent profiles, committed to the repo) with a .agent.md extension. That is the whole setup. From this point forward, every teammate who types /agent and picks “Security audit” gets the same checklist, the same severity grouping, the same output format. The agent runs your workflow the same way every time, on every machine, in every session.
The reason this is a real feature and not a demo is that the file is version-controlled. It is in the repo. It is reviewed in pull requests. It is changed when your tooling changes. It is the kind of documentation that actually runs.
Three agents worth writing first
Start with workflows your team already repeats. The candidates that pay off fastest are the ones that have been tribal knowledge for a year, where the answer to “how do we do X” is in someone’s head and not in a wiki page.
Security audit agent
Run the team’s standard secret scan, dependency review, and static analysis. Group findings by severity. Output a checklist that maps to owners. The example above is the one I use. The thing that surprised me is how much the “output format” section matters: without it, every run produces a slightly different report, and reviewers stop reading them. With it, the reports become a stream of consistent, comparable artifacts. Coverage gaps are flagged, not hidden. Critical findings get a section heading. Your compliance team gets an audit trail.
Accessibility review agent
A WCAG (Web Content Accessibility Guidelines, the international standard for accessible web design) review agent runs the same set of checks against every pull request that touches frontend code. Color contrast, keyboard navigation, semantic HTML (using HTML elements according to their meaning, like <button> for actions and <h1> for top-level headings) instead of <div> for everything, ARIA (Accessible Rich Internet Applications, extra markup that helps screen readers interpret complex widgets) usage, and screen reader compatibility. Without an agent, the developer fixes the issue they noticed. With an agent, the developer fixes the issue that the team has decided matters. Both are valid; only the second is consistent.
- Validates against WCAG 2.1/2.2 AA standards automatically
- Checks color contrast ratios and keyboard navigation paths
- Reviews semantic HTML and ARIA usage
- Provides practical fixes, not just violations
- Generates reports for design and QA handoffs
Onboarding agent
New engineers hit the same setup walls on the same day two. Most teams have a “first day” doc that links to 14 different pages. The onboarding agent encodes the actual environment setup, the dependency installation, and the local configuration into a single, repeatable workflow. The new engineer runs /agent onboarding and the agent walks them through it. When the toolchain changes, you update the agent once, and every new hire gets the new process. The amount of “it works on my machine” incident tickets drops measurably.
Where the file should live
Two conventions are worth following from day one.
The first is naming. Use the workflow as the name: security-audit.agent.md, a11y-review.agent.md, onboarding.agent.md. The name appears in the agent picker. A name like agent1.agent.md is worse than useless; it forces your teammates to open the file to figure out what it does, which is exactly the friction you are trying to remove.
The second is directory layout. The conventional location is .github/agents/ at the root of your repository. GitHub’s tooling already looks there. If you have a monorepo (a single repository holding many projects), you can keep the directory at the root and use prefixes (frontend-a11y.agent.md, backend-security.agent.md) to keep the picker short. If you have many small repos, each repo gets its own .github/agents/ and you copy or symlink the files you need.
.github/agents/is the conventional directory- Name the file after the workflow, not the model
- One agent per file, focused scope
- Commit the file in the same pull request that introduces the workflow
- Review agent changes the same way you review CI changes
Trade-offs
Custom agents are powerful, but they are not free. Maintenance is the first cost. The file is code, and code rots. When your team upgrades from gitleaks v8 to v9, when you add a new scanner to the security stack, when your WCAG target moves from AA to AAA, the agent needs to be updated. Outdated agents produce outdated results, and outdated results are worse than no results because they are confidently wrong.
A second cost is the learning curve. Writing effective agent profiles is a skill. The first few profiles I wrote were too vague, too broad, and tried to handle every scenario. The output was a wall of text that the user had to re-read three times to extract the one paragraph they needed. Focused agents with clear responsibilities produce better output. The rule I landed on: if the description of the agent is more than two sentences, the scope is too broad.
A third cost is scope creep. The temptation to make one agent that does everything is strong. Resist it. Kitchen-sink agents produce kitchen-sink output.
- Profiles require maintenance as tools and standards evolve
- Writing effective agents takes practice and iteration
- Overly broad agents produce inconsistent, verbose results
- Team buy-in is required for adoption
- Version control is essential for tracking changes
In our case, the agents that stuck were the ones I wrote in response to a real complaint. “Why does the security report look different every time?” led to the audit agent. “Why does every new hire spend three days on setup?” led to the onboarding agent. The agents I wrote speculatively, before anyone had asked for them, were deleted within a month.
Getting started without overthinking it
Do not boil the ocean. Pick one workflow your team repeats weekly. Document the actual steps you take, not the idealized version. Encode it. Commit it. Iterate.
- Pick your most repeated terminal task
- Write down the exact steps and standards you follow
- Create an agent profile in
.github/agents/ - Test it locally with Copilot CLI
- Refine based on actual output
- Share with the team and gather feedback
A working agent that produces reliable output beats a perfect agent that never gets committed. The goal is consistency, not perfection.
What I would tell past me
If I could send a message back to the version of me that wrote the first custom agent, I would say three things.
- Start with the workflow that is causing the loudest complaint. The agent that pays for itself fastest is the one that fixes a problem someone has actually raised. Speculative agents get deleted.
- Keep the description to two sentences. If you cannot describe the agent in two sentences, the scope is too broad. Split it into two agents.
- Review the agent file in the same pull request as the workflow change. Agent files drift when they live in a “tools” repository that nobody owns. Co-locate them with the workflow they encode.
Bottom line: if you are typing the same context into Copilot CLI more than twice a week, write an agent for it. The file is 30 lines. The maintenance is real but small. The payoff is that your terminal becomes the place where your team’s standards actually run.