a-handoff-is-not-a-sta…
AgentAt the end of each session your agent writes a paragraph that says what it did. The next session still spends its first half hour…
The task given to the agent was to fix one login bug. The diff changes the login route, an email helper, the database driver, the README and the release script. The transcript gives a plausible reason for each change. The reviewer rejects the pull request and asks you what went
Claude Code
$ npx -y skills add rohitg00/ai-engineering-from-scratch --agent claude-code
Cursor
Cursor also loads subagents from .claude/agents, so copy this file there to use it in Cursor.
id: a-login-fix-touched-five-files title: A login fix touched five files card: agents kind: debug level: 2 roles: [agentic-ai-engineer, forward-deployed-ai-engineer, ai-evaluation-reliability-engineer] rounds: [debugging, design-review] tags: [scope-contract, scope-creep, diff-check, forbidden-files, globs] minutes: 10 lessons: [phases/14-agent-engineering/36-scope-contracts] manuals: [] practice: [] cheatsheet: [agent-workbench-ops] related: [agents/tests-passed-but-nothing-ran] updated: 2026-11-03
The task given to the agent was to fix one login bug. The diff changes the login route, an email helper, the database driver, the README and the release script. The transcript gives a plausible reason for each change. The reviewer rejects the pull request and asks you what went wrong and how to stop it. What do you say?
This is scope creep, and it is hard to see because the agent explains each step in good faith. The fix is not a stricter prompt. It is a contract on disk that lists the files the task may change and the files it must never change, plus a check that compares the final diff with that contract. The check runs before the gate, and a write to a forbidden path blocks the task.
Each change had a local reason. The model does not know where the task ends, so it extends the task every time it finds something related. "Stay in scope" in a prompt is a wish. A file that says what in scope means is a check.
| Field | Purpose | |---|---| | `task_id` | Points at the task on the board | | `goal` | One sentence that a reviewer can verify | | `allowed_files` | Globs the agent may write | | `forbidden_files` | Globs the agent must not touch, even by accident | | `acceptance_criteria` | Commands or assertion lines that prove done | | `rollback_plan` | One paragraph an operator can run if the task must be halted | | `approvals_required` | Actions outside scope that need a human sign-off |
Two rules about the fields. First, a contract without `forbidden_files` is incomplete, because the negative space is half the contract. Second, use globs and not raw paths, so that a file move between sessions does not void the contract.
The checker reads the diff, the allowed globs and the forbidden globs, and returns the violations, the in-scope files and the off-scope files. For this pull request it reports the release script as a forbidden write and the README, the email helper and the driver as off-scope writes. Severity differs by path family: an off-scope write under `docs/**` is a warning, and a write under `scripts/**`, `migrations/**` or production config is always a block. That asymmetry lives in the contract, because it changes per project and per task.
A gate that fails on every small slip gets switched off. Give each task a violation budget so that minor slips surface as warnings, and only a budget overrun blocks the merge. One practitioner who wrote scope contracts before each run reported that the rabbit-hole rate fell from 52 percent to 21 percent in three weeks, with the same agent.
A contract bounds one task, not the project. An agent can respect the login contract and then start a settings page on the next turn. A `feature_list.json` with at most one feature `in_progress` closes that gap. The task contract's allowed files must sit inside what the active feature touches.
The [scope contracts lesson](../../../phases/14-agent-engineering/36-scope-contracts/) builds the contract, the diff checker and the feature list.
At the end of each session your agent writes a paragraph that says what it did. The next session still spends its first half hour…
Read this part of the harness loop. A subscriber on `before_tool_call` raises `HookAbort` on the second step of a three-step…
The product team wants a single maximum number of turns that applies to every run of your agent. The agent handles one-line…
Read this run method from the toy agent loop. A caller shows the returned string to the user as the answer. What is wrong with…
A long coding session has used most of its context window. The runtime offers to summarize the older turns and keep going. Your…
A tool is registered with this schema, and the model sends the four argument sets below. For each one, say what the registry…
Reviews the repository's shared Claude Code configuration (.claude/settings.json, CLAUDE.md, .claude/rules/, .mcp.json and the…
Generate comprehensive API documentation by scanning Express route files.
Advisor to a busy principal. Optimizes for the user's time, attention, and decision quality. One of the starter-kit council…