07 · Instructions, Rules, Skills & Custom Agents
Without customisation, an AI assistant treats every project like a stranger's. With it, the assistant follows your stack, conventions, commands and workflows every time. This page covers each customisation type, when to use it, and working examples.
By the end of this page you can
- Explain the difference between always-on instructions, scoped rules, prompt files, skills, custom agents, hooks and plugins.
- Write a high-quality
AGENTS.mdfor a Scala or Python project. - Create a simple Agent Skill (
SKILL.md) and a custom agent. - Know where each tool looks for these files.
The customisation toolbox
| Type | What it is | Use it for |
|---|---|---|
| Project instructions | A Markdown file automatically added to every request in this repo. | Stack, versions, build/test commands, architecture, conventions, "never do X". |
| Scoped rules | Instructions attached only for matching files or tasks. | "In *.scala, prefer Either." "In migrations/, never edit old files." |
| Prompt files / slash commands | Saved prompts you trigger by name. | Repeated tasks you start yourself: write tests, PR description, explain module. |
| Skills | A folder with SKILL.md (and optional scripts/references) that the agent loads when the task matches the description. | Detailed procedures: "how we add an HTTP endpoint", "release checklist", "Spark job tuning". |
| Custom agents | A named persona with its own instructions, allowed tools and sometimes a model. | Roles: Planner (read-only), Reviewer, Test-writer, Docs-writer. |
| Hooks | Shell commands that run automatically on events (before/after a tool call, at session start, on stop). | Deterministic guarantees: format code, block dangerous commands, run lint. |
| Plugins | Installable bundles of the above. | Sharing a team's whole setup in one install. |
| Memories | Facts the product saves and re-inserts. | Personal preferences. Review them regularly. |
Project instructions: AGENTS.md
AGENTS.md is an open, tool-neutral convention: a Markdown file at the repository root (and optionally in
sub-folders) that agents read for project guidance. Many tools read it directly, including Codex, Copilot in VS Code,
Xcode agents and others. Some tools prefer their own file name (CLAUDE.md,
.github/copilot-instructions.md, .junie/guidelines.md). A common practice is to keep the content in
AGENTS.md and make the tool-specific file point to it.
What to put in it
- One-paragraph project overview and architecture map.
- Exact commands: build, test, single test, lint, format, run.
- Languages and versions.
- Conventions the AI would not guess: error handling, naming, module boundaries, testing style.
- Boundaries: folders not to touch, dependencies that need approval, generated code.
- How to verify a change is done.
What NOT to put in it
- Generic advice the model already follows ("write clean code").
- Long tutorials. Move those to skills or docs and link to them.
- Secrets, tokens or internal URLs you would not want in git.
# AGENTS.md ## Project `orders-service`: HTTP service for order management. Scala 3.5, JDK 21, sbt 1.10. Stack: http4s (Ember), Cats Effect 3, Doobie + Postgres, Circe, MUnit + munit-cats-effect. ## Layout - `modules/domain` pure domain model & logic (no IO, no dependencies on other modules) - `modules/core` services, ports (traits), business workflows in IO - `modules/http` http4s routes, JSON codecs - `modules/db` Doobie repositories implementing ports - `modules/it` integration tests (need Docker) ## Commands - Compile: `sbt compile` - Unit tests: `sbt test` - One test: `sbt "core/testOnly *OrderServiceSuite"` - Format: `sbt scalafmtAll` (CI runs `scalafmtCheckAll`) - Integration: `sbt it/test` (requires Docker running) ## Conventions - Scala 3 syntax, significant indentation, `given`/`using` (no Scala 2 implicits). - Recoverable errors: `Either[DomainError, A]` or `EitherT`; never throw in domain code. - Prefer `opaque type` for IDs (`OrderId`, `CustomerId`). - New public functions need scaladoc and at least one MUnit test. - Don't add dependencies without asking. ## Done means `sbt scalafmtCheckAll compile test` passes and new behaviour has tests.
# AGENTS.md ## Project `pricing-lib`: Python 3.12 library for price calculations. Managed with uv. ## Commands - Install: `uv sync` - Tests: `uv run pytest -q` - One test: `uv run pytest tests/test_discounts.py::test_bulk -q` - Lint/fmt: `uv run ruff check . --fix && uv run ruff format .` - Types: `uv run mypy src` ## Conventions - Full type hints; `mypy --strict` must pass. - Money is `decimal.Decimal`, never float. - Pure functions in `src/pricing/core/`; I/O only in `src/pricing/adapters/`. - Tests: pytest, one test file per module, use `hypothesis` for numeric logic.
/init-style command that does this.Scoped rules
Scoped rules apply only to some files or tasks, so they don't cost tokens elsewhere. In VS Code, for example, a file in
.github/instructions/ with an applyTo glob:
--- description: Conventions for Scala test code applyTo: "**/src/test/**/*.scala" --- - Use MUnit (`munit.FunSuite`, or `munit.CatsEffectSuite` for IO). - One suite per production class, named `<ClassName>Suite`. - Prefer table-driven tests with a `List` of cases over copy-pasted tests. - Never use `Thread.sleep`; use `TestControl` from cats-effect-testkit for time.
Other tools have equivalents, such as rules folders with glob metadata, or AGENTS.md files in sub-folders
that apply to that sub-tree.
Prompt files (slash commands)
Prompt files are saved prompts you trigger by name, e.g. /write-tests. In VS Code they are
*.prompt.md files. Other tools call them commands. Note that some tools now recommend skills
instead, because a skill can be both invoked manually and discovered automatically.
--- description: Explain a module for a newcomer --- Explain the selected module to a developer new to this codebase: 1. Purpose in 2 sentences. 2. Key types and how data flows between them (include a small ASCII diagram). 3. Where it is called from. 4. The 3 things most likely to surprise a newcomer.
Agent Skills (SKILL.md)
Agent Skills are an open format for packaging know-how. A skill is a folder containing a
SKILL.md file with YAML front-matter (name, description) and Markdown instructions, plus optional
scripts/, references/ and assets/.
Progressive disclosure: why skills scale
Because only the description is visible up front, the description decides whether the skill is used.
Write it with clear trigger words: what the skill does and when to use it.
.agents/skills/add-http-endpoint/ # cross-tool location; some tools use their own (e.g. .github/skills, .claude/skills)
├── SKILL.md
├── references/
│ └── error-mapping.md
└── scripts/
└── check_routes.sh
--- name: add-http-endpoint description: Add a new REST endpoint to the orders-service (http4s + Cats Effect). Use when the user asks to add, expose or create an API route/endpoint, or wire a service method to HTTP. metadata: author: sanat version: "1.0" --- # Add an HTTP endpoint ## Steps 1. Define request/response case classes in `modules/http/.../dto/` with Circe codecs (`derives Codec.AsObject`). 2. Add or extend the service trait in `modules/core` and return `IO[Either[DomainError, A]]`. 3. Add the route in the matching `*Routes.scala`. Map errors with `ErrorMapping.toResponse` (see references/error-mapping.md for the status-code table). 4. Register the route in `HttpApp.scala`. 5. Tests: one `munit.CatsEffectSuite` for the route using `org.http4s.client.Client.fromHttpApp`, covering 200, 400 (validation) and 404. 6. Run `sbt "http/test"` and `scripts/check_routes.sh`. Both must pass. ## Don'ts - Don't put business logic in routes. - Don't return 500 for domain errors.
Skills work across many tools because they follow an open specification. The same skill folder can serve VS Code, terminal agents and other compatible products. Level 2 has a full chapter on writing excellent skills.
Custom agents
A custom agent bundles a role, instructions, a set of allowed tools and sometimes a preferred model. For example, a read-only planner that cannot edit files, or a reviewer that only reads diffs and comments.
--- name: reviewer description: Strict senior code reviewer. Reads the diff and reports issues; never edits files. tools: ['search', 'read', 'changes'] --- You are a strict senior Scala/Python reviewer. - Review only the current changes. - Report findings as [BLOCKER], [SHOULD], [NIT] with file:line. - Check correctness, error handling, concurrency, security, tests, naming. - Never modify files. If a fix is obvious, show it as a suggested snippet.
Sub-agents are custom agents that the main agent delegates to. They run in their own context and return a summary, which keeps the main context clean (page 08).
Hooks
Instructions are requests the model usually follows. Hooks are guarantees: real commands that run on events, whatever the model decides.
| Event (typical) | Example use |
|---|---|
| Before a tool call | Block git push --force or edits under secrets/. |
| After a file edit | Run scalafmt / ruff format on the changed file. |
| Session start | Print the current branch and failing tests into context. |
| On stop | Run the test suite and refuse to finish if it fails. |
Hook configuration formats differ by tool (JSON settings files). Check your tool's docs. Rule of thumb: if it must always happen, make it a hook. If it is judgement, make it an instruction.
Where each tool looks (quick reference)
| Tool | Always-on | Scoped / other |
|---|---|---|
| GitHub Copilot (VS Code) | .github/copilot-instructions.md, AGENTS.md | .github/instructions/*.instructions.md, *.prompt.md, *.agent.md, skills |
| OpenAI Codex | AGENTS.md (root + sub-folders) | Skills, config file |
| Claude Code | CLAUDE.md | .claude/rules, .claude/skills, .claude/agents, hooks in settings |
| JetBrains Junie | .junie/guidelines.md (AGENTS.md support varies by version) | IDE settings |
| Xcode agents | AGENTS.md / CLAUDE.md as used by the configured agent | Agent environment settings |
| Cross-tool skills | .agents/skills/<name>/SKILL.md (many tools also read their own skills folder) | |
Locations evolve. Check the docs of the tool you use, which usually have a "customisation" page.
Decision guide
| If you want… | Use |
|---|---|
| The AI to always know build commands and conventions | AGENTS.md |
| Rules only for tests / SQL / a folder | Scoped rules |
| A detailed multi-step procedure used sometimes | Skill |
| A shortcut you trigger yourself | Prompt file / command (or a skill) |
| A different "personality" with limited tools | Custom agent |
| Something that must happen every time | Hook |
| Access to an external system (tickets, DB, docs) | MCP server |
| To give your team all of the above | Plugin, or commit the files to the repo |
Writing instructions that work
- Be concrete: "Use
Either[DomainError, A]" beats "handle errors properly". - Give the reason: "Money is
BigDecimalbecause floating-point rounding causes billing errors". With the why, the model can generalise. - Keep always-on files short (aim for under ~200 lines) and move detail into skills.
- Test them: start a new session and give a task that should trigger the rule. Did it follow?
- Version them in git and review changes like code.
- Prune: outdated instructions are worse than none.
- In a real or sample repo, ask your agent to draft an
AGENTS.md. Edit it until it is accurate. - Create one skill for a procedure you repeat (e.g. "add a new MUnit suite" or "add a pytest fixture").
- New session: give a task that should trigger the skill without naming it. Did the agent load it? If not, improve the description.
Key takeaways
- Customisation types differ by when they load: always, scoped, on demand, manual, persona, event.
AGENTS.mdis the portable foundation. Put commands, versions, conventions and boundaries there.- Skills (
SKILL.md) carry detailed know-how cheaply through progressive disclosure, and the description triggers them. - Custom agents set roles and tool limits. Hooks give guarantees.
- Keep it short, concrete and versioned, and test it.