Configuring and Extending AI Coding Harnesses
Updated October 2026
These notes are adapted from a lunch-and-learn at the office, intended to socialize terminology and some lessons learned in recent months.
This field is moving so fast that these notes will surely be stale in six months.
Glossary
- AI Coding Harness: LLM + specialized instructions, procedures, and behaviors. GitHub Copilot, Claude Code, Cursor, etc.
- Instructions: Standing context — project overview, conventions, rules. Loaded automatically at session start.
- Skills: Procedural knowledge for specific tasks. Matched to user requests automatically.
- Hooks: Unconditional automation at workflow events. Triggered by the harness at defined lifecycle points.
- Agents: Autonomous workers. Explicitly invoked by the user or an orchestrating skill.
Instructions
Instruction Files
Instruction files — "AGENTS.md" and the like — are always loaded at startup. They should contain instructions that the coding agent won't discover on its own or that would be expensive to rediscover each time. Keep the file small! Ideally, each line is based on a real failure that you want to avoid in the future.
| Harness / File | copilot-instructions.md | CLAUDE.md | AGENTS.md |
|---|---|---|---|
| GitHub Copilot | X | X | X |
| Claude Code | X | X | |
| Open AI Codex | X | ||
| Gemini | Customizable | Customizable | Customizable |
| Cursor | X |
/init can create a file for you, but it is verbose; you should refine to
simplify it and add what the agent cannot figure out on its own. Better yet:
write it based on actual experience of missteps taken by the agent(s). When
using multiple tools, you may need different instructions for each tool.
Update, October 2026: Claude Code now reads AGENTS.md natively.
Config and Instruction Locations
Each tool has its own customization. GitHub Copilot has the most overlap with other tools, but even there it has limitations. For example, Copilot reads a root CLAUDE.md file, but not one in a sub-directory — but it will read AGENTS.md in a sub-directory (as of May 2026).
├─ ~/.claude/ # Copilot does not read, use ~/.copilot
├── <same as below>
├── <your-repo>/
├── .claude/
│ ├── agents/ # Copilot reads
│ ├── rules/ # Copilot reads
│ │ ├── coding-style.md
│ │ ├── testing.md
│ │ └── ...
│ ├── skills/ # Copilot reads
│ ├── CLAUDE.md # Copilot reads
│ ├── settings.json # No copilot
│ └── settings.local.json # No copilot; gitignore it
├── src/
│ ├── AGENTS.md # Copilot will load this
│ ├── CLAUDE.md # Copilot ignores
│ ├── CLAUDE.local.md # No copilot; gitignore it
│ └── .claude/ # No copilot
│ └── <etc>
├── CLAUDE.md # Copilot reads
└── CLAUDE.local.md # Copilot reads; gitignore it
Example: Adding a License Header
At work we have VS Code instructions that automatically add a license header on new files, but the coding harnesses ignore that.
When creating a new JavaScript file, always start with the following license header, or equivalent if the file is YAML or Dockerfile.
```javascript
// SPDX-License-Identifier: Apache-2.0
// Licensed to the Ed-Fi Alliance under one or more agreements.
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.
```
In retrospect, the javascript language marker is a waste of a few tokens.
An aside: that license header seemed valuable when we first went open source. But now every single file has about 59 tokens of boilerplate before getting to the real file text. Small change, but every bit counts... perhaps stop using them? Need to rethink that.
Example: The Agent Would Never Guess This
This comes from a TypeScript project. The agent is safe to run eslint and
jest without wasting time on expensive transpilation.
NEVER run npm run build, it transpiles which is only needed for package publishing.
Example: An Early Effort
With continued advancement of the tools, these instructions are probably not
necessary any more. Except perhaps the .editorconfig setting.
## General
* Make only high confidence suggestions when reviewing code changes.
* Never change pyproject.toml or poetry.lock files unless explicitly asked to.
## Formatting
* Apply code-formatting style defined in `.editorconfig`.
* Do not change the formatting of code unless explicitly asked to.
Denying Access to .env Files
It is a good idea to keep your coding agent away from sensitive data.
And this can be very hard to do.
Adding an instruction to "NEVER READ .env" is insufficient; remember, the agents follow these instructions probabilistically. Furthermore, merely denying access to read the file does not mean the agent won't act on your behalf: it could run the code that uses the .env file, which might not be what you want.
Instead of denying read access this way, try using available settings and hooks, or run your agent in a worktree that does not have your environment configuration file(s).
Next Steps for Instructions
Standardize and continue learning.
Encourage dev teams to standardize their practices and share with each other. Continue reading best practice guidance from your products' documentation. Experiment by simplifying and running A/B comparisons, if you have the tokens to spare for such.
Agent Skills
When building an agent skill, ask your agent to help you. It probably has a built-in skill for building skills!
Frontmatter
Each skill declares itself via a YAML frontmatter block at the top of its
SKILL.md. Example, with added comments:
---
name: jira # Unique identifier
description: > # Natural-language trigger — the AI reads this
Use when working with Jira via the acli jira CLI — viewing, creating,
editing, transitioning, searching, and commenting on issues. Triggers on tasks
like "create a Jira issue", "transition ticket to In Progress", "search Jira
for open bugs", "add a comment to PROJ-123".
allowed-tools: # Optional: restrict which tools the skill may use
- Bash(acli jira *)
---
<body of the skill>
The allowed-tools above works in Claude Code, not in GitHub Copilot. The
latter does support the allowed-tools key, but the command list is very
different.
Note that the description always loads into context on every session. Therefore it is important to keep the description short but sufficient to the task. And it needs clear trigger keywords.
This and other custom skills developed by my team is available in AI-Tools-for-Ed-Fi-SDLC.
Sample Prompt Invoking the Jira Skill
Review https://github.com/Ed-Fi-Alliance-OSS/ed-fi-alliance-oss.github.io/security/dependabot/96 then create a Jira issue for it in the DOCS project
Superpowers
“An agentic skills framework & software development methodology that works.”
obra/superpowers is a collection of skills that aid in planning and executing development tasks. They work with most coding harnesses.
- Philosophy: test-driven, systematic, aims for simplicity, verification of output
- Skills: brainstorming, writing-plans, executing-plans, writing-skills, and much more
Also, I’m eager to compare Addy Osmani’s newer agent-skills.
Thoughts on Unit Tests
Superpowers follows a test-driven approach — even when using it to write
new skills! It has an "Iron Law": NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST. I like this philosophy. Although I admit that I go back and forth in
using true test-driven development, because sometimes I need to explore what I
am trying to achieve before I know how to write a test for it.
In my experience, this iron law means that Superpowers appears to consume more tokens. In theory, it also means it will do a better job of getting to done.
Next Steps for Agent Skills
Same word: standardize. Build some re-usable skills, and/or install some third-party skills. If using online agents, add the skills directly to the repository. This also makes them available to everyone else using the repository, so you may want to discuss as a team before committing.
What about standardization across teams? I recommend socializing the practices, but avoid mandate which skills to adopt until they have proven their absolute value over other options.
Hooks
Hooks are defined in a settings file, which means they are unique to the coding agent. These hooks define deterministic actions that will take place at certain times in the lifecycle of work.
Example: Markdown Linting
The following example was developed for Claude Code. It runs both
markdownlint-cli2 and prettier on writing (new) or editing (existing) file.
It assumes that these tools, and jq, are available on the path.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path // empty' | { read -r f || exit 0; case \"$f\" in *.md) npx markdownlint-cli2 --fix \"$f\" 2>/dev/null || true ;; *.mdx) npx prettier --write \"$f\" 2>/dev/null || true ;; esac; }",
"timeout": 30,
"statusMessage": "Linting markdown..."
}
]
}
]
}
}
GitHub Copilot Version
Copilot docs say that Claude Code hooks will work, but GitHub Copilot CLI tells me that it needs a different format. Interestingly, the hook works in the VS Code extension for GitHub Copilot.
At this time, I have not been successful adapting the hook above to work in GitHub Copilot CLI, and I did not test in Cloud Agent.
Next Steps for Hooks
This is still quite the new area for me. The linter idea is useful in many languages. One could add test execution, but in practice the coding agents are already pretty good at running appropriate tests.
Dev teams should look at their workflows and brainstorm appropriate hooks for their repositories.
Custom Agents
An agent is similar to a skill — and in fact can use skills. A custom subagent is useful when you need to run the same task frequently; it runs in its own context with its own allowed tooling.
I am even newer to agents (or subagents?) than hooks. The syntax is not as standardized across tools as Agent Skills, which is frustrating.
Below is a first attempt at a subagent for Claude Code; I do not think it is a good agent. This is better as a Skill. But it was a useful trial run for learning the syntax.
---
name: update-dependencies
description: >
Autonomously update package dependencies in .NET, Python, or JavaScript
projects. Requires a mode: --security-only, --minor, or --all.
permissionMode: bypassPermissions # Agent acts without per-action approval
tools: # Explicit allowlist of permitted tools
- Bash(npm *)
- Bash(dotnet *)
- Bash(git *)
- Bash(gh *)
- Read
- Write
- Edit
skills:
- update-dependencies # Skills to load into the agent's context
---
<agent body – similar to a skill>
GitHub Copilot has a different tools list, as seen below. In GitHub Copilot Coding Agent (online), you can assign this and other custom agents to an Issue, something you can't do with a skill.
---
name: update-dependencies
description: >
Autonomously update package dependencies in .NET, Python, or JavaScript
projects. Requires a mode: --security-only, --minor, or --all.
tools: ["execute", "read", "edit", "search"]
---
<agent body – almost identical to Claude Code version>
The real value will come when running on the cloud and auto-assigning work. For example, one could setup a trigger process to look for new GitHub Issues and assign them to a "Triage Agent." If the agent determines determines that the Issue is a legitimate bug, then it could in turn trigger a "Bugfix Agent."
Next
Keep learning, experimenting, and sharing!
