# Customizing your coding agent

> Source: https://codelearningdojo.com/customizing-harnesses/
> Part of Code Learning Dojo, free to read.

Out of the box, a coding agent is general. The value comes from shaping it to *your* codebase and *your* workflow, and modern harnesses give you six distinct mechanisms to do that.

The mistake people make is reaching for the powerful ones first — writing a subagent when a sentence in an instructions file would do, or a plugin when a five-line command would. Each mechanism has a job, and using the wrong one is how you end up with a configuration nobody understands and an agent that is slower rather than smarter.

Here is the whole map, and the rule for choosing.

## The six mechanisms

| Mechanism | Answers | Reach for it when |
|---|---|---|
| **Instructions** (`AGENTS.md`) | "how should you always behave here?" | a standing fact or rule about this repo |
| **Slash commands** | "do this specific task on demand" | you type the same multi-step request repeatedly |
| **Subagents** | "do this in a separate context" | a task pollutes or overflows the main context |
| **Skills** | "here's expertise for a kind of task" | a task needs procedure or reference the model lacks |
| **Output styles / modes** | "how should you present work?" | you want a different voice or format persistently |
| **Hooks** | "run my code at this point in the loop" | you need enforcement, not a request |

:::verdict The rule
Reach for the **lowest-powered mechanism that does the job.** A rule → a line in the instructions file. A repeated task → a command. A context problem → a subagent. Enforcement → a hook. Escalate only when the simpler thing genuinely cannot express what you need. Every mechanism you add is context the agent carries and complexity you maintain.
:::

Configuration lives at three scopes almost everywhere: **user** (`~/.claude/…`, applies to all your projects), **project** (`.claude/…`, committed, shared with the team), and **local** (gitignored, personal overrides for one project). Put team conventions in project scope so they are reviewed like code; keep personal preferences in user scope.

## 1. Instructions — the foundation

`AGENTS.md` (and `CLAUDE.md`, which most tools now treat as the same thing) is where standing behaviour lives. It is prepended to every request, so it is the highest-leverage and the easiest to overuse.

This has a page per language because the substance differs — [Python](https://learn-python.com/ai/agents-md/), [Go](https://learn-go.org/ai/agents-md/), [TypeScript](https://learn-typescript.org/ai/agents-md/), and the rest. The cross-cutting rules:

- **Under 100 lines.** It competes for attention with your actual code; a 400-line file dilutes the twelve rules that matter.
- **Facts about *this* repo, not general advice.** The model knows the language. It does not know that `legacy_sync.py` is called by a cron in another repo.
- **The two-strike rule.** Add a line only after you have corrected the same thing twice. This keeps it short and evidence-backed.

If you only ever use one customization mechanism, this is the one.

## 2. Slash commands — repeatable tasks

When you find yourself typing the same multi-step request — "run the tests, and if they pass, commit with a conventional message" — that is a command. It is a Markdown file with a prompt in it, invoked by name.

```markdown .claude/commands/ship.md
---
description: Run checks, then commit and open a PR
allowed-tools: Bash(git add:*), Bash(git commit:*), Bash(git push:*), Bash(gh pr create:*), Bash(make check)
---

## Context
- Status: !`git status`
- Diff: !`git diff HEAD`
- Branch: !`git branch --show-current`

## Task
1. Run `make check`. If it fails, stop and report — do not commit.
2. Stage the changes and write a conventional-commits message describing them.
3. Push and open a PR whose body explains the *why*, not just the diff.
Arguments: $ARGUMENTS
```

Now `/ship` runs the whole flow. Three features do the work:

- **`!`command`` injects live output** into the prompt, so the agent starts with the actual git state rather than having to go fetch it.
- **`allowed-tools`** scopes what the command may run — a small, per-command permission grant, which is itself a guardrail.
- **`$ARGUMENTS`** (and `$1`, `$2`) pass what you type after the command name.

Commands are the highest return-per-effort customization after the instructions file. They are shareable (commit them to `.claude/commands/`), they encode a workflow once, and they are trivial to write. Start here before you consider anything more elaborate.

## 3. Subagents — for context, not just delegation

A subagent is a separate agent with its own context window, its own tool permissions, and often a cheaper or more focused model. The main agent hands it a task and gets back only the result.

```markdown .claude/agents/test-writer.md
---
name: test-writer
description: Writes and runs tests for a given module. Dispatch when new code needs coverage.
tools: Read, Grep, Glob, Bash
model: sonnet
---

You write focused tests for the module you are pointed at. Cover the boundary
cases and one negative case per behaviour. Run them, iterate until green, and
report only: what you covered, what you deliberately did not, and any behaviour
that looked wrong. Do not modify source outside the test files.
```

The reason to reach for one is usually **context economy**, which people underrate. A task that reads twenty files to answer one question — "where is this flow wired up?" — pollutes the main context with twenty files' worth of tokens that are irrelevant once answered. A subagent does that reading in its own window and returns three sentences. The main agent stays focused and cheaper — which is a [cost lever](/token-economics/) as much as a quality one.

The three good reasons for a subagent:

1. **Context isolation** — a noisy exploration or a large read that should not bloat the main thread.
2. **Restricted permissions** — a read-only explorer that *cannot* write, used for anything touching untrusted input ([prompt injection](/prompt-injection/) territory).
3. **A different model** — a cheap model for mechanical work, an expensive one reserved for reasoning.

The bad reason: "it feels more organised." A subagent adds a round trip and a context boundary that information has to cross. If the task fits in the main context and needs the main context's knowledge, keep it there.

## 4. Skills — packaged expertise

A skill is reference material and procedure the model loads *when a task calls for it*. Where an instructions file is always present, a skill is present only when relevant — which is what makes it the right home for anything large or specialised.

```markdown .claude/skills/our-migrations/SKILL.md
---
name: our-migrations
description: How to write a database migration in this project. Use whenever a
  schema change, a new table, or an ALTER is needed. Covers our naming, our
  reversibility rule, and the review gate migrations must pass.
---

# Writing a migration here

Migrations live in `db/migrations/`, named `NNNN_verb_subject.sql`...
[the actual procedure, checklists, examples, links to reference files]
```

The `description` is the whole interface — it is what the model reads to decide whether to pull the skill in, so it must say *when* to use it, not just what it is. A skill can bundle multiple files (reference tables, scripts, templates) that load only when the skill activates.

Use a skill when a class of task needs knowledge the model does not have and that is too large for the instructions file: your deploy procedure, your house style for a kind of document, a domain the model gets wrong by default. It is the mechanism for "expertise", where a command is for "a task" and instructions are for "always".

## 5. Output styles and modes — how work is presented

Sometimes you do not want to change *what* the agent does, only how it presents it — a terser voice, a teaching tone that explains each step, a specific report format. Output styles (and the plan/ask modes most harnesses have) cover this.

This is the mechanism people over-reach past — they write a subagent to get "shorter answers" when a one-line style setting does it. If the only thing you want to change is register or format, this is the tool, and it is nearly free.

## 6. Hooks and plugins — enforcement and packaging

**Hooks** are the enforcement layer, and they are different in kind from everything above: instructions, commands and skills are all *requests the model can weigh*, while a hook is *your code running whether or not the model cooperates*. Anything that must happen — run the linter after every edit, refuse a dangerous command, inject standing context into every prompt — is a hook, not an instruction. That is its own deep dive: [harness hooks](/harness-hooks/).

**Plugins** are packaging, not a new capability. A plugin bundles commands, subagents, skills, hooks and MCP servers into one installable unit with a manifest:

```json .claude-plugin/plugin.json
{ "name": "our-backend-workflow", "description": "Commands, agents and hooks for the API team",
  "author": { "name": "Platform Team" } }
```

```text
our-backend-workflow/
  .claude-plugin/plugin.json
  commands/    ship.md  migrate.md
  agents/      test-writer.md  reviewer.md
  skills/      our-migrations/SKILL.md
  hooks/       hooks.json
```

Reach for a plugin when you have accumulated enough customization that it is worth distributing as a set — across a team, or across your own projects. It is the answer to "how do I make everyone's agent work like ours", installed from a marketplace or a git repo rather than copied by hand. For one project, the loose files in `.claude/` are simpler; a plugin earns its manifest at the point of *sharing*.

## MCP servers, briefly

The seventh thing, adjacent to this list: [MCP servers](https://learn-python.com/ai/mcp/) give the agent new *tools* (read your database schema, query your error tracker) rather than shaping how it uses the tools it has. They are the answer when the agent keeps guessing at something that exists in a system it cannot see — and, like everything here, they cost context, so a few well-chosen ones beat a dozen.

## A sensible progression

Most teams do well to adopt these in order, stopping when the returns level off:

1. **A short `AGENTS.md`.** Almost all of the value, an hour of work.
2. **Two or three slash commands** for your most-repeated workflows.
3. **A post-edit hook** running your linter and type checker. The biggest quality jump.
4. **A read-only explorer subagent**, once context bloat or untrusted input makes it worth it.
5. **A skill** for the one procedure the model keeps getting wrong.
6. **A plugin**, only when you want to share the above as a set.

Stop whenever the next mechanism does not clearly earn its complexity. A team running well on the first three has not fallen short of anything.

:::verdict The through-line
Match the mechanism to the need. *Always* → instructions. *On demand* → command. *Separate context* → subagent. *Loadable expertise* → skill. *Presentation* → output style. *Enforcement* → hook. *Distribution* → plugin. *New tools* → MCP. Reaching past the simple answer is the most common way agent setups get worse instead of better.
:::

## Common questions

### Command or skill — how do I tell them apart?

A command is something *you* invoke by name to run a task now (`/ship`). A skill is expertise the *model* pulls in on its own when a task matches its description. If you want to trigger it deliberately, it is a command; if you want it to apply automatically whenever relevant, it is a skill.

### When is a subagent actually worth it?

When a task would otherwise flood the main context (a broad codebase search, a large file read), when it should run with fewer permissions than the main agent (anything reading untrusted content), or when a cheaper model would do. If none of those apply, keep the work in the main thread — the subagent boundary has a real cost.

### Do these transfer between Claude Code and Codex?

The concepts transfer; the specifics do not. Both read `AGENTS.md`, both have custom-command and MCP mechanisms, and both have a permission/sandbox model — but the file formats and exact capabilities differ, and hooks in particular are richest in Claude Code. Keep the substance in `AGENTS.md` and symlink the tool-specific files to it.

### Isn't more customization always better?

No, and this is the central point. Every mechanism you add is context the agent carries, a tool definition it must consider, or a rule competing for its attention — and past a point it makes the agent slower and less focused, not more capable. The best setups are small, deliberate, and mostly a good instructions file plus a couple of commands and a hook.
