Agent Skills in Claude Code and Visual Studio Code: Setup, Benefits, Risks, and a Step-by-Step Example
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.
By the end of this guide, you should be able to:
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.
Context drift occurs when the AI’s working assumptions gradually move away from the current project state or original requirement.
Watch for these signs.
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.
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.
You report that one filter does not work.
The AI proposes to:
A broad rewrite may be appropriate in some projects, but it should not happen automatically during a small bug fix.
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 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.
This is the most important warning sign.
Even when the project appears to work, stop if you cannot explain:
A working demo is not enough when the path to that demo is unclear.
One failing feature does not automatically mean the session is lost.
A normal bug may have:
A broken session usually has several of these problems:
The distinction matters.
A bug should be debugged.
A broken session should first be stabilized.
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.
Run:
git statusRecord:
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.
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.jsPotentially relevant because filtering belongs here.
index.htmlPossibly relevant only if the filter control did not already exist.
styles.cssMay be unnecessary unless visible filter-state styling was explicitly requested.
package.jsonLikely unrelated because filtering a JavaScript array requires no package.
package-lock.jsonLikely created because a dependency was installed.
This comparison helps separate necessary work from session drift.
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.
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.
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.
For a very small change, copy the exact function into a temporary note outside the repository.
Do not copy secrets or private data.
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.
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.
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.
A partial change is worth keeping when:
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.
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:
A recovered change is not ready merely because the diff is smaller. It still needs verification.
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.
Sometimes none of the generated work is worth preserving.
Discard the session when:
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.
The session may have been committed before you realized it was off track.
The safest response depends on whether the commit has 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 statusUse 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.
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.
Consider this scenario.
Add status filtering in app.js.
The AI:
app.js;index.html;styles.css;src/store.js;No more edits or commands are approved.
git status
git diff --stat
git diffThe project brief requires plain JavaScript and no new dependency.
The package and store file violate those constraints.
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.
git restore index.html styles.css package.json package-lock.json README.md
rm src/store.jsgit diff --stagedThe staged diff now contains only:
activeFilter;Confirm all four filter options and existing Add and Remove behavior.
git commit -m "Filter books by reading status"The project keeps the useful result while rejecting the uncontrolled expansion.
After stabilizing the repository, do not continue the same confused conversation automatically.
Start a fresh AI session when the prior context contains:
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.
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.
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.
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.
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.
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:
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.
Recovery is useful, but prevention is better.
Run:
git statusbefore each feature.
Do not combine filtering, editing, persistence, and deployment.
For example:
Modify only app.js.For example:
Do not add packages, rename status values, or change the data model.Require the AI to identify the relevant files and functions first.
Run:
git status
git diffbefore sending the next implementation prompt.
A clean checkpoint makes recovery much easier.
Do not keep an old conversation merely because it contains many messages.
Current, accurate context is more valuable than long context.
When a session goes off track, choose among three actions.
Continue when:
Use partial recovery when:
Discard the session when:
This can be summarized as:
Understandable and focused
→ Continue
Mixed but separable
→ Preserve and restore
Unclear and interconnected
→ Discard and restartLong 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:
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.
git status.git diff --stat.git diff.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.
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.
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.
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.
Comments
Post a Comment