What to Do When Your AI Coding Session Goes Off Track
An AI coding session can begin with a small task and gradually become difficult to control.
You ask the assistant to add a filter. It changes the rendering function, rewrites the data model, adds a utility file, modifies the CSS, and suggests installing a package. You then ask it to fix one unexpected result, but the correction creates another problem.
After several prompts, the project may still run, but you no longer know which changes are necessary or which version was last reliable.
This is not unusual in AI-assisted development.
The correct response is not to keep sending increasingly urgent prompts. Stop the session, inspect the repository, preserve the work you trust, and return the project to a state you can explain.
This article shows how to recognize a session that has gone off track and recover without losing verified progress.
- Previous article: A Beginner’s Guide to Debugging AI-Generated Code
What You Will Learn
By the end of this guide, you should be able to:
- recognize early signs of context drift;
- distinguish a code bug from a broken development session;
- stop an AI tool before the scope expands further;
- inspect the repository without relying on the AI summary;
- preserve verified changes while discarding unwanted ones;
- restore individual files safely;
- recover from uncommitted and committed changes;
- restart the task with a smaller prompt;
- decide when to continue, revert, or begin from a clean checkpoint;
- prevent future sessions from drifting as quickly.
What It Means for a Session to Go Off Track
A session has gone off track when the conversation and repository no longer have a clear relationship to the original task.
Suppose the task was:
Add status filtering to the Personal Reading List Tracker.
Requirements:
- Filter by All, Want to Read, Reading, and Finished.
- Do not modify stored books.
- Do not add dependencies.
- Modify only app.js.A controlled session should produce a focused change in app.js.
An off-track session may instead produce:
modified: app.js
modified: index.html
modified: styles.css
modified: package.json
modified: package-lock.json
untracked: src/filter-manager.js
untracked: src/state-store.jsThe AI may explain that the additional architecture will “make future features easier.”
That may or may not be true. It does not match the agreed task.
The central problem is no longer just whether filtering works. The problem is that the change boundary has disappeared.
Common Signs of Context Drift
Context drift occurs when the AI’s working assumptions gradually move away from the current project state or original requirement.
Watch for these signs.
The AI Refers to Files That Do Not Exist
For example:
I updated BookList.jsx and the Zustand store.Your project uses plain HTML, CSS, and JavaScript. There is no React component or state-management library.
The assistant may be carrying assumptions from another common project pattern.
The Same Requirement Is Interpreted Differently Over Time
Early in the session, the status values are:
want-to-read
reading
finishedLater, the AI begins using:
to-read
in-progress
completedBoth sets may seem reasonable, but mixing them creates bugs.
Fixes Become Broader Than the Original Feature
You report that one filter does not work.
The AI proposes to:
- replace the rendering system;
- rename all status values;
- convert the app to modules;
- move state into a class;
- add a package;
- rewrite the HTML.
A broad rewrite may be appropriate in some projects, but it should not happen automatically during a small bug fix.
The AI Repeats a Disproven Explanation
You confirm that the selector exists, but the assistant continues claiming the selector is missing.
This suggests it is reasoning from old or incomplete context.
The Assistant Changes Files After Being Told Not To
The prompt says:
Modify only app.js.The tool also changes index.html and styles.css.
One accidental change can be reviewed. Repeated boundary violations indicate the session should stop.
You No Longer Understand the Current Diff
This is the most important warning sign.
Even when the project appears to work, stop if you cannot explain:
- which files changed;
- why each change was necessary;
- which behavior was verified;
- which version was last stable.
A working demo is not enough when the path to that demo is unclear.
A Bug Is Not Always a Broken Session
One failing feature does not automatically mean the session is lost.
A normal bug may have:
- clear reproduction steps;
- one likely cause;
- a small relevant diff;
- a known starting checkpoint;
- a focused proposed fix.
A broken session usually has several of these problems:
- multiple unrelated edits;
- changing assumptions;
- several speculative fixes;
- unexplained files;
- unclear package changes;
- no reliable test result;
- no known good state;
- a conversation that references outdated code.
The distinction matters.
A bug should be debugged.
A broken session should first be stabilized.
Step 1: Stop Generating More Changes
When the session drifts, do not send:
Try again and fix everything.That adds another layer of assumptions.
Instead, stop editing.
Tell the AI:
Stop making changes. Do not edit files or run commands. Summarize the original task, list every file you believe you changed, and identify any unresolved issues.Treat the response as a clue, not as the official record.
The actual repository state must be checked with Git.
If the coding tool is currently requesting permission to run another command or modify another file, deny the request until you understand the current state.
Step 2: Inspect the Repository Yourself
Run:
git statusRecord:
- modified tracked files;
- staged files;
- untracked files;
- deleted files;
- the current branch.
Then run:
git diff --statThis gives a summary of how many files and lines changed.
For example:
app.js | 86 +++++++++++++++++++++++------------
index.html | 14 ++++++
styles.css | 42 +++++++++++++++++
package.json | 6 +++
package-lock.json | 93 +++++++++++++++++++++++++++++++++++++
5 files changed, 196 insertions(+), 45 deletions(-)A filtering feature that changes nearly two hundred lines across five files deserves careful review.
Now inspect the full diff:
git diffFor specific files:
git diff app.js
git diff index.html
git diff styles.css
git diff package.jsonDo not begin deciding what to keep until you know what changed.
Step 3: Compare the Repository with the Original Task
Return to the original prompt and project brief.
Create a small comparison table in your notes:
Original task:
Add status filtering.
Allowed files:
app.js
Required behavior:
- All
- Want to Read
- Reading
- Finished
- Do not modify stored data
Prohibited:
- No dependencies
- No data-model changes
- No unrelated stylingNow compare each changed file.
app.js
Potentially relevant because filtering belongs here.
index.html
Possibly relevant only if the filter control did not already exist.
styles.css
May be unnecessary unless visible filter-state styling was explicitly requested.
package.json
Likely unrelated because filtering a JavaScript array requires no package.
package-lock.json
Likely created because a dependency was installed.
This comparison helps separate necessary work from session drift.
Step 4: Identify the Last Known Good State
Run:
git log --oneline -5For example:
2ac7e31 Add book removal
fd81b26 Validate book titles
c5a4d77 Add books through the form
1ee7aa2 Add book list renderingIf the working tree was clean before the filtering task, the latest commit is your recovery point.
Confirm what that version contained:
git show --stat 2ac7e31You may also inspect the previous version of a file:
git show HEAD:app.jsThis prints the committed version of app.js without changing the working tree.
You now have two states:
HEAD:
Last committed and verified version
Working tree:
Current uncommitted AI-generated changesThe goal is to decide which parts of the working tree deserve to survive.
Step 5: Preserve Anything You Trust
Do not discard all changes automatically if part of the work is correct and understandable.
Suppose the AI added this focused filtering function:
function getVisibleBooks() {
if (activeFilter === "all") {
return books;
}
return books.filter((book) => book.status === activeFilter);
}The function matches the project brief and is easy to test.
The same session also added a package and rewrote the styles.
You may want to preserve only the relevant JavaScript.
There are several ways to do this.
Save a Temporary Patch
Create a patch of the current changes:
git diff > ai-session-changes.patchThis creates a text record of the diff.
Do not commit the patch to the project unless you have a specific reason. It is a temporary recovery aid.
Copy a Small Verified Section into Notes
For a very small change, copy the exact function into a temporary note outside the repository.
Do not copy secrets or private data.
Stage Only the Trusted Part
Interactive staging allows you to choose sections of a file:
git add -p app.jsGit will show one section at a time and ask whether to stage it.
Common responses include:
y = stage this section
n = do not stage this section
s = split into smaller sections
q = stopInteractive staging is powerful, but review every section carefully.
After staging the trusted portion:
git diff --stagedThe staged diff should contain only the work you intend to keep.
Step 6: Restore Unwanted Tracked Changes
For a tracked file whose changes are entirely unwanted:
git restore styles.cssThis restores the working copy from the current committed version.
For package changes:
git restore package.json package-lock.jsonReview the diff before restoring because uncommitted changes will be discarded.
For a file containing both useful and unwanted edits, use interactive restore:
git restore -p app.jsGit will let you choose which change sections to discard.
This is useful when one AI session mixed valid filtering logic with unrelated refactoring.
Step 7: Remove Unwanted Untracked Files Carefully
Untracked files are not restored by Git because Git has never recorded them.
List them with:
git statusInspect each one before removal:
cat src/filter-manager.jsFor a longer source file, open it in the editor instead.
When you are certain the file is unnecessary:
rm src/filter-manager.jsIf a newly created directory contains several files, inspect the directory first:
find src -maxdepth 2 -type fDo not run broad deletion commands unless you understand exactly what they will remove.
Avoid using cleanup commands merely because the AI recommends them.
Step 8: Decide Whether to Keep a Partial Change
A partial change is worth keeping when:
- it directly supports the original task;
- you can explain it;
- it follows the project brief;
- it does not depend on discarded code;
- it can be tested independently;
- it produces a focused diff.
For the reading list filter, a safe partial result might include:
let activeFilter = "all";
function getVisibleBooks() {
if (activeFilter === "all") {
return books;
}
return books.filter((book) => book.status === activeFilter);
}It may also update renderBooks() to render the result of getVisibleBooks().
That can be tested without keeping a package, new architecture, or unrelated design changes.
Reject a partial change when it depends on missing pieces or remains difficult to explain.
Step 9: Test the Recovered State
After removing unwanted changes, run:
git status
git diffThe remaining diff should be small and intentional.
Now test the application.
For status filtering:
1. Add one Want to Read book.
2. Add one Reading book.
3. Add one Finished book.
4. Select each filter.
5. Confirm only matching books appear.
6. Select All.
7. Confirm all books appear.
8. Confirm filtering does not delete any book.Also test existing behavior:
- adding books;
- rejecting blank titles;
- removing books;
- showing the empty state.
A recovered change is not ready merely because the diff is smaller. It still needs verification.
Step 10: Commit the Verified Recovery
If the remaining work is correct, stage it specifically:
git add app.jsReview:
git diff --stagedCommit:
git commit -m "Filter books by reading status"Then confirm:
git statusThe working tree should be clean.
You have now converted a confused AI session into a focused, verified project change.
When to Discard the Entire Session
Sometimes none of the generated work is worth preserving.
Discard the session when:
- the intended feature does not work;
- the changes are too interconnected to separate;
- the AI replaced the project architecture;
- new dependencies are unexplained;
- you cannot identify which part is correct;
- the current diff is larger than rebuilding the feature;
- multiple files contain contradictory versions;
- the session introduced security or privacy concerns.
For uncommitted tracked changes, inspect first:
git diffThen restore the tracked files:
git restore app.js index.html styles.css package.json package-lock.jsonRemove unwanted untracked files individually after inspection.
Finally:
git statusThe repository should return to the last committed checkpoint.
Starting again from a clean state is often faster than repairing code you do not trust.
Recovering from a Bad Commit
The session may have been committed before you realized it was off track.
The safest response depends on whether the commit has been shared.
When the Commit Has Not Been Shared
You may still choose to create a new reversing commit rather than rewriting history, especially as a beginner.
The clear and generally safe option is:
git revert <commit-hash>This creates a new commit that reverses the selected commit.
For example:
git revert a81c5d2Git may open an editor for the revert commit message.
Afterward, inspect:
git log --oneline -5
git statusWhen the Commit Has Already Been Pushed
Use git revert rather than casually rewriting shared history.
The commit remains visible in history, and the new revert commit records that its changes were undone.
This is useful for collaboration because other repositories can follow the same history.
Avoid Destructive Reset Commands as a Default
A command such as:
git reset --hardcan discard local work.
Do not use it casually during a confusing session.
Prefer targeted restoration or a revert commit when possible.
Example Recovery: The Filtering Session Expanded Too Far
Consider this scenario.
Original Task
Add status filtering in app.js.
AI Session Result
The AI:
- changed
app.js; - rewrote the filter markup in
index.html; - redesigned controls in
styles.css; - installed a state-management package;
- created
src/store.js; - renamed status values;
- modified the README.
Step 1: Stop
No more edits or commands are approved.
Step 2: Inspect
git status
git diff --stat
git diffStep 3: Compare with the Brief
The project brief requires plain JavaScript and no new dependency.
The package and store file violate those constraints.
Step 4: Preserve Useful Logic
The filtering function in app.js is understandable and matches the original status values.
Use:
git add -p app.jsto stage only the relevant sections.
Step 5: Restore Unwanted Changes
git restore index.html styles.css package.json package-lock.json README.md
rm src/store.jsStep 6: Review Staged Work
git diff --stagedThe staged diff now contains only:
activeFilter;- the filtering function;
- the filter event handler;
- the renderer update.
Step 7: Test
Confirm all four filter options and existing Add and Remove behavior.
Step 8: Commit
git commit -m "Filter books by reading status"The project keeps the useful result while rejecting the uncontrolled expansion.
Restart with a Fresh Prompt
After stabilizing the repository, do not continue the same confused conversation automatically.
Start a fresh AI session when the prior context contains:
- outdated file names;
- discarded architecture;
- failed theories;
- changed requirements;
- instructions that no longer apply.
A fresh prompt might be:
Project:
Personal Reading List Tracker using plain HTML, CSS, and JavaScript.
Current state:
- The working tree is clean.
- Add, validate, render, and remove behaviors are working.
- The filter control already exists in index.html.
- Status values are want-to-read, reading, and finished.
Task:
Implement status filtering in app.js.
Expected behavior:
- All shows every book.
- Each status filter shows only matching books.
- Filtering must not modify the books array.
- The active filter remains effective after a book is added or removed.
Constraints:
- Modify only app.js.
- Do not add dependencies.
- Do not change the data model.
- Do not rename status values.
- Do not refactor unrelated functions.
Process:
1. Inspect app.js and PROJECT_BRIEF.md.
2. Do not edit yet.
3. Show the smallest implementation plan.
4. Identify the exact functions that need changes.This prompt provides current facts without carrying the entire failed conversation forward.
Ask for a Plan That Names Files and Functions
Before approving new edits, require a concrete plan.
A useful plan should say something like:
1. Add an activeFilter variable in app.js.
2. Add getVisibleBooks() to return filtered data without modifying books.
3. Update renderBooks() to use getVisibleBooks().
4. Add a change listener to the existing filter control.
5. Test all filter states after add and remove actions.A weak plan might say:
I will improve the filtering architecture and make the app scalable.The first plan is reviewable.
The second leaves the scope undefined.
Use a Session Boundary Checklist
Before starting a new AI coding session, record:
Current branch:
main
Working tree:
clean
Latest verified commit:
2ac7e31 Add book removal
Current task:
Add status filtering
Allowed files:
app.js
Required behavior:
All, Want to Read, Reading, Finished
Excluded:
Dependencies, data-model changes, styling, editing
Verification:
Manual filter tests plus existing add and remove testsThis note protects the session from drifting away from the project state.
It also gives you a clear point for deciding when the task is complete.
Limit the Number of Corrections in One Session
There is no universal maximum number of prompts.
However, repeated corrections are a warning.
A typical pattern may be:
Prompt 1:
Implement the feature.
Prompt 2:
Correct one missed requirement.
Prompt 3:
Fix a specific verified bug.That can be reasonable.
A more concerning pattern is:
Prompt 1:
Build the feature.
Prompt 2:
Undo part of it.
Prompt 3:
Restore the old data model.
Prompt 4:
Fix the new error.
Prompt 5:
Remove the package.
Prompt 6:
Recreate the deleted function.
Prompt 7:
Make everything work again.At that point, stop and inspect Git.
The issue is no longer one missing requirement. The session has lost a stable direction.
Avoid Emotional Prompt Escalation
When a tool repeatedly fails, users often write prompts such as:
You broke it again. Fix everything now and do not make any mistakes.The frustration is understandable, but the prompt does not provide better technical evidence.
A more useful response is:
Stop editing. The current result does not match the task. List the files changed and explain which change implements each acceptance criterion. Do not propose or apply a fix.Then verify the response with Git.
Precise boundaries are more useful than stronger wording.
Protect Secrets and Private Data During Recovery
A drifting session may create logs, environment files, or copied configuration.
Check for:
.env
.env.local
debug.log
request.json
config.backupInspect files carefully without exposing their contents in a public prompt.
Do not paste:
- API keys;
- passwords;
- access tokens;
- private URLs;
- company source code;
- customer information.
If a secret was committed, deleting the line in a later commit may not remove it from existing history or external systems. The credential should be treated as exposed and rotated through the relevant provider.
For the reading list project, the initial version should not require secrets at all.
Prevent Future Sessions from Going Off Track
Recovery is useful, but prevention is better.
Start from a Clean State
Run:
git statusbefore each feature.
Keep One Task per Session
Do not combine filtering, editing, persistence, and deployment.
Name Allowed Files
For example:
Modify only app.js.Name Prohibited Changes
For example:
Do not add packages, rename status values, or change the data model.Ask for Inspection Before Editing
Require the AI to identify the relevant files and functions first.
Review Immediately After One Change
Run:
git status
git diffbefore sending the next implementation prompt.
Commit Verified Features
A clean checkpoint makes recovery much easier.
Start a Fresh Session When Context Changes
Do not keep an old conversation merely because it contains many messages.
Current, accurate context is more valuable than long context.
A Recovery Decision Framework
When a session goes off track, choose among three actions.
Continue
Continue when:
- the diff is still focused;
- the issue is clearly understood;
- only one acceptance criterion is missing;
- the next correction is small;
- you still understand the project state.
Preserve Part and Restore Part
Use partial recovery when:
- some changes are correct;
- useful and unwanted edits can be separated;
- the valid portion can be tested independently;
- the remaining diff can become one focused commit.
Discard and Restart
Discard the session when:
- the architecture changed unexpectedly;
- dependencies were added without approval;
- the AI mixed several features;
- the diff is difficult to explain;
- the project no longer runs reliably;
- recovery costs more than rebuilding the feature.
This can be summarized as:
Understandable and focused
→ Continue
Mixed but separable
→ Preserve and restore
Unclear and interconnected
→ Discard and restartPractical Advice from AI-Assisted Development
Long coding sessions often create the illusion of progress because many files are changing.
File activity is not the same as verified progress.
A useful development state has three qualities:
- the current behavior is known;
- the current diff is understood;
- the next task is limited.
When one of those qualities disappears, pause.
In my experience reviewing AI-assisted changes, the costliest mistakes often happen after the first warning sign. The developer notices that the scope expanded but continues because the AI seems close to finishing.
A better habit is to stop early.
Git makes stopping practical because verified work can be preserved while untrusted work is rejected.
The goal is not to save every generated line.
The goal is to protect the project.
A Reusable Session-Recovery Checklist
Stop
- Do not approve more edits.
- Do not request a broad fix.
- Ask the AI to summarize without changing files.
Inspect
- Run
git status. - Run
git diff --stat. - Run
git diff. - Inspect untracked files.
- Check dependency and configuration changes.
Compare
- Reopen the original prompt.
- Reopen the project brief.
- Identify allowed files.
- Identify excluded features.
- Match each change to a requirement.
Recover
- Find the last verified commit.
- Save a temporary patch when useful.
- Stage trusted sections selectively.
- Restore unwanted tracked changes.
- remove untracked files only after inspection.
Verify
- Test the recovered feature.
- Test existing related behavior.
- Review the remaining diff.
- Check for secrets and debugging leftovers.
Commit or Restart
- Commit the verified partial result, or
- discard the session and return to the last checkpoint.
Begin Again
- Start a fresh AI session.
- State the current project state.
- Define one task.
- Set file boundaries.
- Ask for a plan before editing.
Conclusion
An AI coding session has gone off track when the original task, conversation, and repository no longer align.
The safest response is to stop generating changes and inspect the actual project state. Use Git to identify modified and untracked files, compare the diff with the original requirement, find the last verified checkpoint, preserve only the work you understand, and restore everything else.
Do not measure success by how much generated code you manage to save.
A smaller verified change is more valuable than a large result built on unclear assumptions.
The next article will focus on Git checkpoints during AI-assisted development. We will examine where to create checkpoints, how often to commit, how to separate experimental work, and how a clear history makes both recovery and review easier.
Frequently Asked Questions
Should I always discard an AI session after it makes one unrelated change?
No.
Inspect the change first. A small accidental edit may be easy to restore while preserving the valid work. Stop the session when unrelated changes continue or the overall state becomes unclear.
Can I keep only part of an AI-generated file?
Yes.
You can manually preserve a small verified section or use Git’s interactive staging and restore features. Review the result carefully because partial changes may depend on code you removed.
Is starting a fresh AI conversation better than correcting the old one?
Often, yes.
A fresh conversation is useful when the old session contains outdated assumptions, failed approaches, or references to code that no longer exists. Provide the current repository state and one focused task.
- Next article: Using Git Checkpoints During AI-Assisted Development
