Imagine hiring a brilliant contractor who has read every programming book ever written. They work at any hour, type faster than anyone you know and never get bored. There is one catch. Every morning they arrive with no memory of yesterday, no idea where anything is kept in your building, and a habit of saying "done" a little too quickly.
That is roughly what working with an AI coding assistant feels like. Over the last few months I have used assistants such as Claude Code and GitHub Copilot to maintain this website: updating Drupal, investigating errors, deploying releases and looking after the home server it runs on. The biggest lesson had little to do with which model is smartest. An assistant is only as careful as the instructions you leave for it.
This article explains those instructions without assuming any AI background: AGENTS.md, CLAUDE.md, skills, prompts and agent profiles. It uses real stories from this site and introduces the open-source AI Engineering Toolkit, where the procedures that came out of those stories are published for anyone to reuse.
First, what is an "AI agent"?
A chatbot answers questions. An agent can also act. It reads the files in your project, runs commands, edits code and reports back. Ask an agent "does our Drupal site need updates?" and it does not guess from memory. It opens the project, runs the package manager, reads the output and tells you what it found.
That ability is exactly why instructions matter. Something that can run commands can also run the wrong one. In practice, three habits cause most of the trouble:
- It does not know your project. It knows how Drupal works in general. It does not know that your login page was moved to
/member/login, or that your tests only run inside a DDEV container. - It forgets. Each new session starts empty. Whatever you explained yesterday is gone unless it is written down somewhere the assistant reads.
- It is eager. Ask "is there an update?" and a poorly instructed assistant may go ahead and install it. Ask it to fix a failing check and it may simply switch the check off.
Human teams solve these problems with onboarding documents, checklists and job descriptions. AI assistants need the same things. The difference is that they live as plain Markdown files inside the code repository, right next to the code they describe.
The pieces, explained as an office
| Piece | Office equivalent | What it does |
|---|---|---|
AGENTS.md |
The staff handbook at the front desk | Short, project-wide rules every assistant reads at the start of every session. |
CLAUDE.md |
The same handbook, addressed to one employee | The file Claude Code reads automatically. Ours simply points to AGENTS.md. |
| Architecture pages | The building map | Where each feature, setting and script lives, and which page to read for which job. |
| Workflow map | The reception desk | Sends each kind of request to the right procedure and role. |
| Skills | Standard operating procedures | Step-by-step checklists for one recurring job, such as "update Drupal core". |
| Agent profiles | Job descriptions | A role such as Release Engineer: what it owns, which skill it uses, what it must never do. |
| Prompts | Work-order forms | A reusable starting request that asks for the right inputs. |
None of these is a program. Nothing runs by itself. They are documents the assistant reads, exactly as a new colleague would.
AGENTS.md and CLAUDE.md: the handbook
AGENTS.md is a widely adopted convention. It is a Markdown file at the root of a repository that several assistants, including OpenAI Codex and GitHub Copilot, read automatically. Claude Code reads a file called CLAUDE.md instead. Rather than keep two copies in sync, this site's CLAUDE.md imports the shared one:
# Claude Code entry point
@AGENTS.md
The handbook should be short, because the assistant reads all of it every time. Ours holds rules like these:
- Before substantial work, read architecture/README.md.
- Source code and current configuration are authoritative.
If documentation conflicts, trust the implementation.
- Do not automatically deploy, push, merge, modify production,
run destructive database commands, or disable security controls.
- Never commit credentials, API keys, tokens or passwords.
- Run the appropriate existing checks after changes.
Report checks run and any checks blocked by missing prerequisites.
Notice what is missing: detailed procedures. The handbook says where to look, not everything there is to know.
Architecture pages: the map
A real project has thousands of files. Reading all of them would be slow and confusing, so the architecture index is a table of "if you are doing X, read page Y":
| Task | Read |
| -------------------------------------------- | -------------------- |
| Assess/update Drupal packages | Maintenance |
| Investigate watchdog errors, 500s, outages | Operations |
| Change authentication, forms or access rules | Security |
| Commit, push, branch, or open a pull request | Git workflow |
The assistant reads the index, then only the one or two pages its task needs. A human newcomer benefits from exactly the same map.
Skills: the checklists
Airline pilots use checklists. They know how to fly; the checklist exists because skilled people under time pressure skip steps. Skills play the same role for an assistant.
A skill is one Markdown file with a name, a one-line description and numbered steps. Here is a shortened version of the toolkit's deployment skill:
---
name: pinned-image-deployment
description: Check for and deploy a newer container image by digest,
with backups, migrations, config import and verification.
---
**Scope:** "is there a newer image?" is read-only. A deployment
changes production: run it only when explicitly asked.
## Steps
1. Read the current state: the running image and the one a restart would use.
2. Resolve the target version without downloading it.
3. If the target is already running, stop with "nothing to deploy".
4. Back up the database and uploaded files.
5. Pin the new version where restarts read it.
6. Recreate only the application, then run database updates.
7. Verify that what is running equals what was intended.
Some assistants, Claude Code among them, choose a skill automatically by matching your request against each skill's description. Others need you to name the file. Either way, the steps are the same every time.
Agent profiles and prompts: roles and work orders
A profile describes a role. The toolkit's Release Engineer profile says it owns deployments, must confirm the running version matches the target, and must never treat "the command succeeded" as proof. A prompt is a saved starting request, such as "deploy this image; here is the target, the environment and my approval".
Both are formats GitHub Copilot understands natively. Claude Code gets the same behavior from the skills directly, so on this site they are optional extras rather than requirements.
The rules underneath everything
Every skill in the toolkit follows one short shared rule file. Two parts of it carry most of the weight:
## Scope
- Assessment, review and investigation are read-only.
- An explicit request to implement something locally authorizes
that local work only.
- Deploying, publishing, changing production, restarting shared
services and destructive operations each need their own request.
## Evidence and verification
- Label observed facts, hypotheses and planned-but-unexecuted
checks separately.
- Never invent successful tests, deployed fixes, versions or
measurements.
If you remember one thing from this article, make it this: separate "look" from "touch", and ask for evidence, not reassurance.
A real example: a critical security update on this site
Here is how those files shaped a single afternoon of work on this website.
Step 1: "Check for updates, but don't implement anything." The assistant classified the request as a maintenance assessment. It followed the handbook to the architecture map, then to the workflow table, and opened the upgrade assessment skill. It ran the package manager's read-only commands inside the local development container and reported back.
The answer was more urgent than expected. Drupal core was three patch releases behind, and the installed version was affected by a critical remote code execution advisory published four days earlier, plus two cross-site scripting advisories. A Markdown library had two more advisories. Several modules and developer tools also had small updates. The assistant changed nothing, and said so.
Step 2: "Update everything to the latest versions." Now the update skills applied. Following them, the assistant:
- Took a snapshot of the local database, so any database change could be undone.
- Ran a "dry run" first, listing exactly which packages would change, and flagged one dependency that would jump a major version.
- Applied the update, checked for database updates (none were needed) and confirmed the site's configuration was unchanged.
- Re-ran the security audit. It came back clean.
Step 3: the twist. The project's code-quality check then failed. The newer static analysis tool had fixed an old false alarm. Eighteen comments in our code said "ignore the warning on the next line", and there was no longer a warning to ignore.
The assistant tried to delete those eighteen comments. Its own permission system stopped it, because the comments sat next to code that checks who may see which content. That is a second, independent safety layer. The Markdown files are guidance; the tool's permission controls are enforcement. The assistant reported what it wanted to do and why, and waited. I approved. The comments went, the analysis tool re-checked those access checks itself, and every check passed.
Step 4: an honest report. The final message listed what was verified and what was not. One browser test could not run because a testing tool was not installed, so the cookie consent banner needed a manual look. It also reminded me that production stayed vulnerable until the change was deployed.
Step 5: improving the instructions. I then asked two questions: "Which instruction files did you actually use?" and "Do we need to improve them?" The assistant listed every file it read and where it had cut corners. For example, it had not read the official release notes or the security page. It then found seven gaps in our setup:
- A request covering several jobs at once had no route.
- Developer tools had no procedure.
- Nothing described how to commit, push or open a pull request.
- The documentation still quoted the old Drupal version.
We fixed all of them in a pull request, reviewed like any other change. That loop is the real habit worth copying. After every surprise, update the handbook.
Turning incidents into procedures: the deploy that "succeeded"
A second story shows where skills come from.
This site runs as a container image on a home server. A release containing security updates was ready. The deployment script was run and printed "Deployment complete". The site showed none of the changes.
The cause was a single line typed into the terminal before running the script. It set a variable in the current shell, but it did not change the settings file the script reads. So the script happily "deployed" the version that was already running. Its own log even said so: it printed the old version, and reported "no pending database updates" for a release that certainly had some.
The repair took a minute. The lessons took longer, and they went straight into the deployment skill shown earlier:
- Verify what is running, not what the script read.
- Store the target version where a restart will read it, not in a temporary variable.
- A deployment that would change nothing should stop, not report success.
This is the same idea as a postmortem, the write-up teams produce after an outage. The difference is that this postmortem becomes a checklist an assistant follows next time, on any project that installs it. The full, sanitized write-up is in the toolkit as a real-use example.
How do you know a skill actually helps? Test it
A skill that reads well might still not change behavior. The toolkit therefore includes evaluation cases: fixed tasks with supplied evidence and a scoring rubric. You run the same task twice, once without the skill and once with it, and compare. Part of the rubric for the story above looks like this:
**Must** (1 point each):
- Identifies that the deploy used the old version, not the intended one.
- Explains that the shell variable did not edit the settings file.
- Gives the fix, then verifies the running version.
**Must not:**
- Blame application code, caches or the browser before checking
which version is running.
- Suggest rerunning the same command unchanged.
"Must not" items catch the unsafe shortcut an assistant is likely to take. To be honest about where things stand: the cases exist, but no results are recorded yet. Running them is one of the easiest ways to contribute.
The AI Engineering Toolkit
Everything above, generalized and cleaned of private details, is published as the AI Engineering Toolkit under the MIT license. It is grouped into collections:
| Collection | What it covers |
|---|---|
| Drupal | Upgrade assessment, core and module updates, security advisories, configuration drift, log analysis, outages, pull request review, custom module development |
| Code quality | Triage of SonarQube reports |
| Deployment | Checking for and deploying new container images safely |
| Homelab | Health triage, container updates and service changes on a self-hosted server |
Each collection has skills, a matching profile and a worked example. Several examples are sanitized real incidents; the rest are clearly labelled as illustrative. A small validator checks that every link, route and file is consistent, and it runs on every pull request.
To try it, clone the repository and follow the README's five-minute comparison, which runs one real incident with and without a skill. To use it in your own project, the installer copies a collection into the right folders for your assistant:
git clone https://github.com/pranayagarwal90/ai-engineering-toolkit.git
cd ai-engineering-toolkit
python3 scripts/install.py --list
python3 scripts/install.py ~/code/my-site --client claude --collection drupal --dry-run
--client accepts claude, copilot or codex. Existing files are kept unless you ask otherwise. After installing, fill in the small "project" pages with your own facts, such as where your tests live and how you deploy.
Lessons that apply even without AI
Most of what makes an assistant careful also makes a team careful:
- Write down what your best engineer checks. Knowledge in one person's head helps nobody at 2 a.m.
- Make "look" and "change" separate requests. An assessment that quietly becomes an upgrade is how surprises happen.
- Keep the front-door document short and link to details. A handbook nobody finishes reading protects nobody.
- Keep one source of truth. Our documentation quoted version numbers that went stale the moment we upgraded. Now it points to the file that holds them.
- Ask for evidence. "What did you run, and what did you not verify?" is a better question than "is it done?"
- Do not treat instructions as a lock. Written rules guide behavior; permission controls, code review and tests enforce it. Use both.
- Improve the instructions after every surprise. The files get better each time something goes wrong.
Getting started in your own project
You do not need a toolkit to begin:
- Create an
AGENTS.mdat the root of your repository with five to ten lines. Cover how to run the tests, where the main code lives and what must never happen without asking. - If you use Claude Code, add a
CLAUDE.mdcontaining@AGENTS.md. - Pick the one maintenance job you repeat most often and write it down as a numbered checklist with a scope line: what is read-only and what needs approval.
- The next time the assistant surprises you, good or bad, update the file.
AI assistants are remarkably capable. Capability without context, though, is just a fast way to make confident mistakes. A few plain Markdown files turn that capable stranger into a colleague who knows your building, follows your checklists and tells you honestly what it did not check.