skip to content

cat ./blog/ai-orchestration-and-engineering.mdx

AI orchestration and engineering

13 min readaiagentsmcpskillstoolingplugins

AI orchestration and engineering

AI coding agents are only as good as the context you hand them. After a couple of years of running Claude Code or GitHub Copilot daily on production TypeScript codebases, I've learned that the difference between an agent that ships and an agent that flails isn't the model — it's the scaffolding around it. This article covers that scaffolding in the order I'd build it: instruction files (AGENTS.md and CLAUDE.md), harness fundamentals, MCP servers, and skills/plugins.

Where to start: AGENTS.md (and optionally CLAUDE.md)

Software vendors, harnesses, and agentic tooling have converged on an AGENTS.md file as the standard place for agent instructions. It's an open format — plain Markdown, no required fields, no frontmatter — originally driven by OpenAI, Google, Cursor, Amp, and Factory, and now stewarded by the Agentic AI Foundation under the Linux Foundation. Over 60,000 open-source repositories use it, and it's read natively by Codex, Cursor, Gemini CLI, GitHub Copilot's coding agent, Windsurf, Zed, Warp, Devin, Aider, JetBrains Junie, and more.

Think of it as a README for agents: your README explains the project to humans; AGENTS.md gives agents the operational details — build commands, test procedures, conventions, boundaries — that would clutter a README.

Three placement rules to know:

  1. Global instructions live in a tool-specific home directory location. The proposal to standardize this location has been made, and that's where I put my global AGENTS.md file, referencing it from files like ~/.claude/CLAUDE.md and other agents, so that it gets picked up by the tooling of my choice. There is no single cross-tool global path yet. Use these instructions for personal preferences that apply to every project on your machine.
  2. Project instructions live in AGENTS.md at the repository root. This is the one your team shares through version control.
  3. Nested instructions live in additional AGENTS.md files inside subdirectories. Agents read the nearest file in the directory tree, so the closest one takes precedence, and every package in a monorepo can ship tailored guidance. (Explicit chat prompts override everything.)

Finally, if you're using the Claude Code plugin in Visual Studio Code like I do, note that Claude Code reads CLAUDE.md, not AGENTS.md. The fix is one line: create a CLAUDE.md that imports your AGENTS.md with @AGENTS.md, then add any Claude-specific instructions below it. Both tools now read the same source of truth without duplication.

Below are four examples. The first lives in your tool's global config directory. The second lives in your project's root. The third could sit in a TypeScript hooks directory. The fourth is CLAUDE.md-specific, but uses AGENTS.md to inform Claude Code how to work in the project.

1. Global instructions (machine-level)

For Codex CLI this is ~/.codex/AGENTS.md; for Claude Code, ~/.claude/CLAUDE.md. The content strategy is the same — keep it short and universal:


md
# Personal preferences

- Package manager: pnpm. Never run npm or yarn commands.
- TypeScript strict mode always. No `any` without a `// justification:` comment.
- Prefer named exports. No default exports except Next.js pages/layouts.
- Conventional Commits for all commit messages.
- Never commit directly to main; always work on a feature branch.


2. AGENTS.md in a project root directory

This is the file your whole team benefits from. Be ruthless about what goes in — every line competes for the agent's attention with the actual task:

md
# AGENTS.md  
  
Next.js 15 app (App Router) with Prisma ORM on MongoDB Atlas,  
TailwindCSS v4, and TanStack Query.  
  
## Setup commands  
  
- Install deps: `pnpm install`  
- Dev server: `pnpm dev`  
- Typecheck: `pnpm typecheck`  
- Tests: `pnpm test` (Vitest)  
  
## Conventions  
  
- Server actions return discriminated unions: `{ ok: true, data } | { ok: false, error }`.  
- Validate all external input with Zod at the trust boundary.  
- After editing `prisma/schema.prisma`, run `pnpm prisma generate` before typechecking.  
- MongoDB has no migrations here — use `pnpm prisma db push` in dev only.  
  
## Boundaries  
  
- Never edit files in `src/generated/`.  
- Never touch `.env*` files; ask for the variable name instead.  
  
## PR instructions  
  
- Run `pnpm lint && pnpm typecheck && pnpm format && pnpm test` before committing.

Notice what's not here: no directory-tree diagram, no dependency list, no architecture essay. Agents can derive those from the codebase, and file paths documented in prose go stale the moment someone refactors. Document capabilities and conventions, not structure.

3. AGENTS.md in a project sub-directory

Nested files let you scope instructions to where they matter. Here's one for src/hooks/:

md
# AGENTS.md — src/hooks

- Every hook lives in its own file named `use-<thing>.ts` with a named export.
- Data-fetching hooks wrap TanStack Query. Query keys come from
`src/lib/query-keys.ts` — never inline a query key array.
- Mutations must invalidate their related query keys in `onSettled`.
- Each hook gets a colocated `use-<thing>.test.ts` using `renderHook`
from Testing Library.

Because agents read the nearest AGENTS.md, these rules apply when the agent works in src/hooks/ and stay out of context everywhere else — which keeps your root file lean.

4. (Optional) CLAUDE.md in your project directory

Claude Code loads CLAUDE.md at session start and supports @path imports, so the pattern is: import the shared standard, then append Claude-specific behavior.

md
@AGENTS.md

## Claude Code

- Use plan mode for any change touching `prisma/schema.prisma`.
- Use the `pr-description` skill when preparing pull requests.
- Prefer path-scoped rules in `.claude/rules/` over growing this file.


A symlink (ln -s AGENTS.md CLAUDE.md) also works if you have nothing Claude-specific to add — though on Windows symlinks require Administrator privileges or Developer Mode, so the import is the safer default. Either way, run /context in your next session and confirm the file appears under Memory files.

Two sizing rules from Anthropic's docs worth tattooing somewhere: target under 200 lines per file, and remember these are context, not configuration — Claude treats instructions as strong guidance, not enforced policy. Anything that must happen deterministically (lint before commit, block edits to a path) belongs in a hook or a permissions rule, not in Markdown.

Agentic CLI tool and harness usage

The instruction files above are static context. Day-to-day effectiveness comes from how you drive the harness itself. Four things matter most:

Prompting

Prompt an agent the way you'd brief a capable contractor on day one: state the goal, the constraints, and the definition of done. "Add rate limiting to the API" is a wish; "Add rate limiting to POST /api/checkout using our existing Upstash client, 10 req/min per user, return 429 with a Retry-After header, and add a Vitest test for the limit boundary" is a task. For anything non-trivial, ask for a plan first (Claude Code's plan mode exists for exactly this) and review it before letting the agent touch files. Course-correcting a plan costs seconds; course-correcting a 40-file diff costs an afternoon.

Context

Context is a budget, and everything spends it: your instruction files, every file the agent reads, every tool result. Manage it deliberately. Keep AGENTS.md lean and push detail into nested files and path-scoped rules so it loads only when relevant. Start fresh sessions for fresh tasks rather than letting one conversation absorb three unrelated problems. In Claude Code, /compact summarizes the conversation when you're deep in a long task — your project-root CLAUDE.md survives compaction and gets re-injected, which is one more reason durable instructions belong in the file, not in chat.

Tools

A harness is a loop: the model proposes an action, a tool executes it, the result feeds back in. The tools you expose define what the agent can actually do — file edits, shell commands, web fetches, and whatever MCP servers you've wired up (next section). The discipline is subtractive: every enabled tool costs context (its definition is in the prompt) and adds a way for the agent to wander. Enable what the current work needs; turn the rest off. And keep the permission model honest — auto-approving reads is fine, but anything destructive or external (deploys, DB writes, git push) should stay behind a confirmation.

Lessons

The highest-leverage habit I've built: when the agent makes the same mistake twice, that's not a prompting failure — it's a missing instruction. Stop, write the correction into AGENTS.md (or a nested file, or a rule), and it's fixed for every future session and every teammate. Claude Code's auto memory does some of this automatically — it saves learnings from your corrections into ~/.claude/projects/<project>/memory/ — but the durable, team-shared stuff belongs in the repo. Treat your instruction files as living documentation with a feedback loop, and review them when something goes wrong, the same way you'd review a runbook after an incident.

MCP servers

Model Context Protocol (MCP) is the open standard — originally from Anthropic, now also under Linux Foundation stewardship alongside AGENTS.md — for connecting agents to external systems: databases, issue trackers, browsers, design tools, your company's internal APIs. An MCP server exposes tools and resources over a standard protocol; any MCP-capable client (Claude Code, VS Code, Cursor, Codex, and dozens more) can use it without custom integration work.

Where to get an MCP server

Start with the official servers repository at github.com/modelcontextprotocol/servers, which includes reference servers (filesystem, fetch, memory, git) and links out to hundreds of community and vendor-maintained servers. Most major vendors now ship their own first-party servers — GitHub, Stripe, Sentry, Notion, Playwright, Context7 for library docs, and so on. Treat third-party servers with the same suspicion you'd give an npm package with 12 downloads: an MCP server runs with your credentials and feeds text directly into your agent's context, which makes it both a supply-chain risk and a prompt-injection vector. Prefer official vendor servers, pin versions, and read the source of anything obscure.

How to configure an MCP server in VS Code

There are two configurations to know about if you work in VS Code, because VS Code's native agent mode and the Claude Code extension read different files.

For VS Code / Copilot agent mode, create .vscode/mcp.json in your workspace:

ts
{
	 "servers": {
		  "context7": {
		   "type": "http",
			  "url": "https://mcp.context7.com/mcp"
		  },
		  "playwright": {
			   "type": "stdio",
			   "command": "npx",
			   "args": ["@playwright/mcp@latest"]
		  }
	}
}

For Claude Code (including the VS Code extension), servers live in .mcp.json at the project root — shared with your team via version control — or in user scope for personal servers. The CLI manages it for you:

ts
# Project scope (checked in, shared with the team)

claude mcp add --scope project context7 --transport http https://mcp.context7.com/mcp

# User scope (all your projects, just you)
claude mcp add --scope user playwright -- npx @playwright/mcp@latest

Run /mcp inside a session to see connected servers, their tools, and auth status.

Activating or turning on MCP servers (and why to turn them off)

Configured is not the same as free. Every enabled server injects its tool definitions into your context window on every request — a chatty server with 40 tools can burn thousands of tokens before you've typed a word, and a large tool surface measurably degrades tool-selection accuracy. My rule: configure broadly, enable narrowly. In Claude Code, use /mcp to toggle servers per session; in VS Code, the tools picker in agent mode does the same. If you haven't used a server in a week, disable it. You can always flip it back on when the task calls for it.

The other reason to turn servers off is security. Tool results are untrusted input — a malicious web page fetched through a browser server, or a poisoned issue description pulled from a tracker, can contain instructions aimed at your agent. Fewer live servers means a smaller injection surface, and the ones that remain should be ones whose data sources you trust.

Build your own MCP server

This is where MCP goes from convenience to superpower — wrapping your internal APIs, database queries, or deployment tooling so your agent can operate your systems directly.

The Ultimate MCP Crash Course - Build From Scratch — I recommend it because it walks the full arc from empty directory to a working server registered in Claude Code, which is exactly the path you'll follow for your first internal server. After watching, your next steps: scaffold a TypeScript server with the official SDK, expose one read-only tool against a real system you use daily, register it with claude mcp add, and only then add write operations behind explicit confirmation.

The protocol itself is specified at spec.modelcontextprotocol.io, with approachable docs at modelcontextprotocol.io. For libraries:

  • TypeScript: @modelcontextprotocol/sdk — the official SDK, and the natural choice for our stack. A tool is a Zod schema plus an async handler; if you've written a validated server action, you already know how to write an MCP tool.
  • Python: the official Python SDK, or FastMCP for a higher-level, decorator-driven developer experience.
  • Community SDKs exist for Go, Kotlin, C#, Java, Rust, and more — see the SDK list on the MCP site.

Skills and plugins

Skills are the newest layer of the stack and, for repeatable workflows, the most useful. A skill is a folder with a SKILL.md file — instructions, optionally bundled with scripts and reference documents — that loads on demand when it's relevant, instead of sitting in context permanently the way AGENTS.md does. Plugins are the distribution format: a plugin bundles skills (plus optional hooks, subagents, and MCP server configs) into something installable in one command.

Where to get skills and plugins

Anthropic's official marketplace, claude-plugins-official, is registered automatically in Claude Code — run /plugin to browse it. Community marketplaces are just git repos; add one with /plugin marketplace add <owner>/<repo> and its plugins appear alongside the official set. Anthropic also publishes open-source skills at github.com/anthropics/skills. The same security posture as MCP servers applies: a skill is instructions your model will follow, and a plugin can bundle hooks that execute shell commands. The official marketplace is reviewed; most community ones are not. Read before you install.

A short list of my favorites

  • Superpowers (obra/superpowers-marketplace) — a battle-tested collection covering planning, TDD-style implementation loops, and debugging workflows. The best example I've seen of encoding an engineering process, not just knowledge, into skills.
  • https://github.com/mattpocock/skills - Skills for Real Engineers. "...instead of a framework that owns your workflow, these are small, composable, model-agnostic skills based on classic engineering literature"
  • Anthropic's official skills (anthropics/skills) — the document skills (docx/xlsx/pptx/pdf) and frontend-design are the ones I reach for; frontend-design noticeably raises the floor on UI output.
  • My own — the highest-value skills in my setup are ones I wrote: PR description generation, commit messages, and docs generation, living in .claude/skills/ and shared with the repo. Your team's conventions are the one skill nobody else can publish.

Should my skill belong in AGENTS.md?

The research on this is more interesting than the folklore. Augment Code's eval work found that the same AGENTS.md content improved a routine bug-fix task by 25% and degraded a complex feature task by 30% — always-loaded reference material helped when it matched the task and actively pulled the agent off course when it didn't. That's the argument for skills in one sentence: AGENTS.md is unconditional context, skills are conditional context.

My heuristic:

  • AGENTS.md: facts and rules that apply to every session — build commands, conventions, boundaries. If it's not true for all tasks, it doesn't belong.
  • .claude/rules/ with a paths: scope: rules that apply to a slice of the codebase.
  • A skill: multi-step procedures invoked occasionally — release process, PR prep, a migration playbook. If you're describing "how to do X" rather than "what is always true," it's a skill.

If your AGENTS.md is creeping past 200 lines, that's usually a sign procedures have snuck in. Extract them.

Using skills in Claude Code

Project skills live in .claude/skills/<skill-name>/SKILL.md (checked in, shared with the team); personal skills live in ~/.claude/skills/. The SKILL.md frontmatter — name and description — is what Claude uses to decide when to load a skill, so write the description like a trigger condition ("Use when preparing a pull request description"), not a summary. Invoke one explicitly with /skill-name, or just describe the task and let Claude load it when the description matches. Plugin-provided skills are namespaced (/my-plugin:review) so authors never collide.

Links and References