Engineering AI Coding Assistants for Controlled, Auditable Changes

    AI coding assistants can read code, edit files, run commands, and explain errors, but their default stateless operation often leads to scope creep, inconsistent changes, and lost constraints. This article presents an engineering approach for making assistant behavior predictable and auditable through project-level rule files, controlled working modes, lifecycle hooks, reusable skill modules, review subagents, least-privilege permissions, externalized state, and a verification loop. It also provides practical templates, permission boundaries, and a phased team adoption path.

    Engineering AI Coding Assistants for Controlled, Auditable Changes

    Introduction: Tools Are Not Plug-and-Play

    Many developers are first attracted by demos of AI coding assistants: they can read code, edit files, run commands, and explain errors. But once placed in a real project, the experience quickly changes:

    • Ask it to change three files and it changes a dozen.
    • Ask it to add one feature and it refactors a core module.
    • Emphasize coding standards repeatedly, and by the tenth round it starts using inconsistent patterns again.
    • Explicitly say not to touch dependency manifests, and it still produces a large “optimization” diff.
    • As the session grows, earlier constraints are compressed away and it begins to improvise.

    These symptoms are not simply because the model is “not smart enough.” They come from a lack of engineering constraints in how the assistant is used. The default operating mode of an AI coding assistant is usually stateless: each new session starts with a clean context, and the assistant knows nothing about project structure, team conventions, forbidden files, or testing requirements. It can only decide its next action from the code it currently reads and the current conversation. Without rules, “read whatever is nearby and change it” almost inevitably leads to scope creep.

    This article does not focus on tips for a specific product. Instead, it abstracts a general method: constrain the AI coding assistant from “changing code by feel” to “making controlled changes within project rules.” The core consists of four layers: persistent context, working modes, extension mechanisms, and a verification loop.

    1. Understand the Operating Mechanism First: Minimal Loop and Stateless Sessions

    Many AI coding assistants use a minimal loop underneath: call the model, execute a tool, feed the tool result back into context, and call the model again. There is no complex prebuilt pipeline. Decision logic is only a small part; much of the engineering capability sits in runtime “armor,” such as permission control, context compression, tool invocation, and safety restrictions.

    This loop usually follows the ReAct pattern, alternating reasoning and action. Each round roughly includes:

    1. Observe the current context and tool results.
    2. Reason about the next step.
    3. Choose a tool action, such as reading a file, searching, writing a file, or running a command.
    4. Feed the action result back and enter the next round.

    The problem is that this loop does not guarantee cross-session memory. When a new session starts, the context window is clean. Without any project-level rule injection, the assistant can only understand the project through ad hoc exploration. It does not know team conventions, which directories must not be touched, what the test command is, or how large the change budget should be. As a result, loss of control is not an accident; it is the default state.

    The solution is not to repeatedly “ask it to behave” in the chat box. Instead, move constraints forward: load rules before the session starts, set checkpoints before and after tool calls, and maintain verifiable change boundaries during task execution.

    2. Project-Level Rule Files: Make the Assistant Understand the Project from the First Message

    2.1 What Rule Files Do

    A project-level rule file is configuration loaded into the system prompt during session startup. It works like a “project manual.” It takes effect before the user’s first message and gives the assistant persistent knowledge: project map, build commands, coding standards, forbidden areas, acceptance criteria, and collaboration protocols.

    A key insight is that after context compression, rule files are usually re-read from disk and re-injected, while temporary instructions given verbally in the chat box may be lost after compression. Therefore, important rules must be fixed in files rather than repeated in reminders.

    2.2 Rule Files Should Be Layered

    At least three layers are recommended:

    • Global layer: personal general preferences, such as output language, commit message format, and risk warning requirements.
    • Project layer: project architecture, directory responsibilities, commands, testing requirements, and dependency management rules.
    • Directory layer: additional constraints for submodules or special directories, such as generated code directories being read-only or migration scripts requiring manual confirmation.

    Layering prevents a single giant file from getting out of control and makes it easier for different teams to maintain their own boundaries.

    2.3 Rule File Content Template

    A rule file does not need to be a long document, but it must be executable and checkable. The following structure can be used:

    1. # Project Rules (Example)
    2. ## Project Map
    3. - Entry layer: src/app
    4. - Domain layer: src/domain
    5. - Infrastructure layer: src/infra
    6. - Generated code: generated/, read-only, no manual edits
    7. - Dependency manifest: maintained by designated owners, changes forbidden by default
    8. ## Common Commands
    9. - Install dependencies: make install
    10. - Unit tests: make test
    11. - Type checking: make typecheck
    12. - Lint: make lint
    13. ## Coding Standards
    14. - New logic must include corresponding unit tests
    15. - Public interface changes must describe compatibility impact
    16. - Error handling must preserve context and must not swallow exceptions
    17. ## Forbidden Areas
    18. - Do not modify any file under generated/
    19. - Do not upgrade dependency versions unless the task explicitly requires it
    20. - Do not delete existing test cases just to make tests pass
    21. ## Acceptance Criteria
    22. - After changes, tests, type checking, and lint must be run
    23. - Final output must include: change summary, risk points, verification results

    2.4 Maintenance Principles

    Rule files should be short and hard. Every rule should answer “how will this be checked?” Vague statements such as “pay attention to code quality” have no binding force. Executable statements such as “public interface changes must list compatibility impact” are effective. Rules should also be cleaned up regularly; outdated constraints increase misjudgment by the assistant.

    3. Controlled Working Mode: Read Before Write, Plan Before Execute

    A rule file alone is not enough. The working mode must also constrain the order of actions. A task can be split into four stages:

    1. Read-only exploration: searching, reading files, and viewing directories are allowed; writing files is not.
    2. Plan confirmation: output the change plan, affected files, and test plan, then wait for confirmation.
    3. Controlled execution: modify only files in the plan and set a diff budget.
    4. Review and acceptance: run checks and output a change summary and risk notes.

    The value of this mode is to turn “think while changing” into “evidence first, action second.” In the exploration stage, the assistant should list relevant files and call chains. In the planning stage, it should specify which files to change, why, and which files not to change. In the execution stage, if it finds dependencies outside the plan, it must pause and explain rather than expanding scope on its own.

    The assistant can be given a “task card”:

    1. Task goal: Fix an exception in an interface when parameters are empty
    2. Allowed to modify: src/domain/order/*, tests/order/*
    3. Forbidden to modify: generated/, dependency manifests, shared configuration
    4. Change budget: at most 5 files, no more than 300 lines of diff
    5. Acceptance commands: make test, make typecheck, make lint
    6. Output requirements: change summary, risk points, verification results

    A task card is more stable than a long natural-language instruction and is easier for teams to reuse.

    4. Extension Mechanisms: Hooks, Skills, and Subagents

    4.1 Lifecycle Hooks: Automate Checkpoints

    Hooks insert checks before and after key lifecycle events. For example, before writing a file, check whether the path is on a whitelist; before running a command, check whether it is on an allowlist; after writing a file, automatically run formatting or tests; after a task ends, generate an audit log.

    Pseudo-code example:

    1. on_before_write:
    2. - if: path matches "generated/**"
    3. action: deny
    4. - if: path not in allowed_paths
    5. action: require_approval
    6. on_after_write:
    7. - run: make lint
    8. - if: failed
    9. action: stop_and_report
    10. on_before_command:
    11. - if: command not in allowlist
    12. action: require_approval

    The principle for hooks is “few but critical.” Do not put every process into hooks, or tasks will slow down and misjudgments will increase. Prioritize intercepting three types of risk: out-of-bounds writes, dangerous commands, and unverified changes.

    4.2 Skill Modules: Fix Reusable Processes

    Skill modules are suitable for capturing repeated processes, such as “add an interface,” “fix a defect,” “generate a migration script,” or “add unit tests.” Each skill includes steps, inputs, outputs, a checklist, and failure handling. This way the assistant does not have to reason from scratch every time; it follows a team-validated process.

    Skill modules should not be too granular. Too granular becomes a rigid script; too coarse has no binding force. A good skill module should state: applicable scenarios, preconditions, allowed modification scope, required checks, and output format.

    4.3 Subagent Orchestration: Isolate Context and Cross-Review

    Subagents are suitable for tasks that need an independent perspective, such as code review, test gap analysis, and documentation consistency checks. The main agent executes changes, while the review subagent only reads the changes and outputs a list of issues, avoiding the blind spot of “reviewing your own changes.”

    Subagent prompts should limit responsibilities:

    1. You are a review subagent. Check only the current change.
    2. Input: list of changed files and diff.
    3. Check items: out-of-bounds changes, compatibility risks, test gaps, standard violations.
    4. Output: issue list sorted by high/medium/low risk, with suggested verification commands.
    5. Do not modify files directly.

    More subagents are not always better. Two or three subagents with clear responsibilities are usually enough: one for correctness, one for tests, and one for standards and safety.

    5. Permissions and Boundaries: Least Privilege and Diff Budgets

    AI coding assistants need tool permissions, but permissions must be minimized. Recommended configuration:

    • Directory whitelist: only business code and test directories may be modified.
    • File blacklist: generated code, dependency manifests, secret configuration, and production configuration are read-only by default.
    • Command allowlist: tests, formatting, and type checking can run; dangerous commands require approval.
    • Diff budget: limit the number of files and lines per task; exceeding the limit requires a pause and explanation.
    • Change description: explain the purpose before each write and output a summary after writing.

    Diff budgets are especially important. Many “loss of control” incidents manifest as scope expansion: a defect fix ends with half a module refactored. Limiting file count and line count forces the assistant to explain necessity first instead of optimizing along the way.

    6. Context Compression and Recovery: Preserve Decisions, Not Chatter

    Long sessions inevitably trigger context compression. After compression, temporary verbal instructions are easily lost, so key state must be externalized:

    • Rule files: store long-term constraints.
    • Task cards: store the current goal, scope, and acceptance criteria.
    • Decision records: store confirmed plans and rejected plans.
    • Change logs: store modified files, unfinished items, and verification results.

    This way, even when context is compressed, the assistant can re-read key state from disk instead of guessing from memory. Teams can place task cards and decision records in fixed directories to form auditable process assets.

    7. Verification Loop: An Unverified Change Is Not Complete

    The output of an AI coding assistant must be verified. A fixed acceptance chain is recommended:

    1. Lint: unify style and reduce unrelated diffs.
    2. Type checking: find interface and contract issues.
    3. Unit tests: verify whether behavior meets expectations.
    4. Integration tests: verify cross-module impact.
    5. Change review: check out-of-bounds modifications, compatibility, and test gaps.
    6. Output summary: change content, risk points, verification results, and rollback method.

    If verification fails, the assistant should stop expanding the change and locate the cause first. It must not “make the result green” by deleting tests, loosening assertions, or skipping checks. This rule should be written into the project rule file and enforced by hooks.

    8. Team Adoption Path: From Templates to Metrics

    Adoption does not need to happen all at once. It can proceed in the following order:

    • Week 1: Create project rule files and define the project map, commands, forbidden areas, and acceptance criteria.
    • Week 2: Introduce task cards and the controlled working mode, requiring planning before execution.
    • Week 3: Add key hooks to intercept out-of-bounds writes and dangerous commands.
    • Week 4: Capture two or three high-frequency skill modules to reduce repeated reasoning.
    • Later: Introduce review subagents and metrics such as first-pass rate, number of out-of-bounds modifications, average verification time, and rollback count.

    Metrics are not meant to evaluate the assistant, but to find gaps in the rules. If out-of-bounds modifications are frequent, the forbidden areas and diff budgets are unclear. If the verification failure rate is high, task cards lack acceptance criteria. If review subagents keep repeating the same issues, the rule file needs to be supplemented.

    Conclusion

    The value of an AI coding assistant is not that it is “invincible out of the box,” but whether it can be constrained by engineering practices. Stateless sessions mean it does not understand the project by default; the minimal loop means it acts based on the current context. Only by combining project rules, working modes, extension mechanisms, permission boundaries, and a verification loop can it move from “uncontrolled” to “controllable,” and then from “controllable” to “efficient.”

    Effective practice is not repeated reminders in the chat box. It is writing team standards into files, putting checkpoints into the process, and treating verification results as the completion standard. Only then will an AI coding assistant become a collaborator that understands the project, respects boundaries, and can be audited.