Guides
Use AI pair-programming without wrecking your repo architecture
AI pair-programming is useful when you treat the model like a fast junior who needs clear boundaries. It is harmful when you paste a vague goal, accept a large diff, and discover a week later that half your domain logic now lives in random helpers. This guide is a working loop you can reuse on real repos: constrain the task, generate in small slices, review against architecture rules, then merge.
At a glance

Constraint set before prompting: allowed, forbidden, done.

Small slice loop: prompt → diff → review gate → merge.

Touch only allowed surfaces; keep core architecture off-limits.
Start with a written constraint set
Before the first prompt, write three short notes in the chat or in a project skill file:
- Allowed surfaces — which packages, folders, or modules the agent may touch.
- Forbidden moves — for example “do not add a new state library,” “do not invent HTTP clients,” “do not move shared types out of
src/domain.” - Definition of done — tests to run, files that must change, files that must not change.
These notes matter more than clever prompting. Models optimize for completing the stated task. If you do not state the architecture, they invent one that fits the local request.
Keep the constraint set short enough that you will actually reuse it. A 40-line manifesto gets ignored. Six bullets get followed.
Slice work into reviewable units
Ask for one vertical or one concern per turn:
- “Add validation for this form field and wire the existing error component.”
- “Extract the duplicate date formatting into the shared util we already use.”
- “Write a failing test for the bug in
InvoiceService, then implement the fix.”
Avoid mega-prompts such as “refactor auth and add OAuth and clean up the API layer.” Those prompts produce coherent-looking patches that cross module boundaries and are expensive to reverse.
A useful size heuristic: if you cannot skim the diff in two minutes and still know whether architecture was respected, the slice was too large. Split again.
Give the model the map, not the whole city
Paste or @-mention:
- the nearest interfaces and call sites
- the folder that owns the concern
- one or two examples of the local pattern (naming, error handling, logging)
Do not dump the entire repository into context by default. Extra files increase the chance the model “helpfully” rewrites distant code to match a new style. Prefer explicit pointers: “follow the pattern in payments/CheckoutForm.tsx; do not touch billing.”
When the task spans layers (UI → API → persistence), still constrain each layer in sequence. Get the domain change stable before asking for UI polish.
Review gates that catch architecture damage
Human review should answer specific questions, not only “does it compile?”
Boundary check. Did new code import across layers that were previously isolated? Did a UI file start talking to the database client? Did a shared package grow a feature-specific dependency?
Duplication check. Did the model reimplement something that already exists under a slightly different name? Search for sibling helpers before accepting “new util” files.
API surface check. Were public types, routes, or exported functions expanded casually? Prefer internal helpers until the shape is proven.
Test check. Are tests asserting behavior you care about, or only asserting that mocks were called? Prefer one real path test over five brittle interaction spies.
Diff hygiene. Reject drive-by renames, comment rewrites, and formatting churn mixed into a feature change. Ask the agent to revert noise and restate the patch.
A practical gate sequence:
- Read the file list first. Reject unexpected paths immediately.
- Skim imports and exports.
- Read the core logic.
- Run the narrowest tests for that area.
- Only then consider broader formatting or docs.
Prompt patterns that keep architecture intact
Constraint-first prompt
In
src/billingonly. ReuseMoneyandInvoiceStatus. Do not add libraries. Add a function that marks an invoice overdue afterdueDateand returns the existing error union. Show the plan in five bullets, then wait.
Planning before code reduces surprise file creation. If the plan already violates your rules, correct it before generation.
Diff-limited prompt
Change at most three files. If you need more, stop and explain why.
Pattern-match prompt
Match error handling to
createSubscription.ts. Same Result type, same logging helper.
Repair prompt (after a bad patch)
Revert the new
utils/date2.ts. UseformatDatefromsrc/lib/date.ts. Keep behavior identical.
Repair prompts should be as specific as feature prompts. “Clean this up” invites a second architectural swing.
Use tests as the contract, not as afterthought
Ask for the failing test first when fixing bugs. For features, ask for tests that lock the public behavior you intend to keep. This does two things: it forces a clearer interface, and it makes it obvious when the model solved a different problem than the one you stated.
If your repo lacks tests in the target area, write a thin characterization test yourself before inviting large AI edits. Uncovered modules are where agents invent structure most aggressively.
When to switch tools mid-task
Chat UIs are fine for design discussion, API sketching, and reviewing pasted snippets. IDE agents are better when the task needs multi-file navigation with project rules attached. Neither replaces a human who owns the module map.
Switch away from the agent when:
- the next step needs a product decision, not a code decision
- you are about to accept a fourth consecutive “small fix” on the same files
- the model starts renaming symbols to “clarify” without a request
At that point, stop generating. Write the decision down. Resume with a narrower prompt.
A repeatable daily loop
- Pick one outcome that fits in a short PR.
- Paste constraints and relevant examples.
- Require a brief plan; approve or correct it.
- Generate the smallest patch.
- Run local gates: file list, imports, tests.
- Commit with a message that states the intent, not the tool used.
- Update your constraint note if you learned a new “do not.”
Over a few weeks, your constraint notes become a lightweight architecture guide. That guide is more valuable than any single generated function, because it teaches every future session how not to wreck the repo.
Team habits that scale the same rules
If more than one person uses agents on the same repo, share the constraint notes in version control—AGENTS.md, Cursor skills, or a short architecture postcard in the wiki. Agree on PR size expectations: agent-assisted work should still be reviewable by a human who did not sit through the chat. Prefer linking the prompt plan in the PR description when the change is non-obvious; that context helps reviewers spot intent drift.
Do not treat “the AI wrote it” as either a badge or an excuse. Ownership stays with the merge author. The workflow above is how you keep that ownership honest without giving up the speed win.
What “good” looks like after a month
You should see smaller PRs, fewer surprise modules, and less time undoing clever abstractions. The model will still make mistakes. The difference is that mistakes stay local, reversible, and reviewable—because you never handed it the whole architecture as an open prompt. When something does go wrong, add one new bullet to the constraint set and move on. That compounding list is the real product of AI pair-programming done carefully.