Agent Skills in Claude Code and Visual Studio Code: Setup, Benefits, Risks, and a Step-by-Step Example
AI coding tools make it tempting to ask for the entire application in one prompt.
You already have a project brief, a list of features, and a clear idea of the final result. It may seem efficient to give the whole document to Claude Code or GitHub Copilot and ask the tool to build everything at once.
That approach can produce a large amount of code quickly.
It can also produce a large amount of code that is difficult to understand, test, or repair.
A safer approach is to divide the application into small features that each create one visible result. You implement one feature, review the change, test it, commit it, and then move to the next feature.
This article explains how to break the Personal Reading List Tracker into manageable implementation steps.
By the end of this guide, you should be able to:
Consider this prompt:
Build a complete personal reading list application with a responsive interface, form validation, status filtering, localStorage, editing, deletion, tests, and deployment configuration.The request is understandable, but it contains many independent decisions.
The AI must decide:
If the finished result contains a problem, identifying the source becomes difficult.
A filtering bug may come from:
A smaller task gives you fewer possible causes.
An AI coding assistant may respond to one large prompt by changing:
index.html
styles.css
app.js
package.json
package-lock.json
README.md
test/app.test.js
deployment-config.jsonThat creates a wide Git diff.
You now need to review:
Even when every file is relevant to the final application, they may not belong in one review or commit.
A smaller task might change only:
index.htmlFor example:
Create the accessible HTML structure for the book form and empty list state.
That diff is much easier to inspect.
You can check:
The review has a clear focus.
A useful development loop is:
Choose one feature
→ Define expected behavior
→ Ask the AI
→ Review the diff
→ Test the result
→ CommitEach cycle produces information.
You learn:
A large one-shot build delays this feedback until many decisions have already been made.
Small steps reveal problems earlier.
A vertical slice is a small piece of functionality that produces a visible or testable result.
For example:
The user can submit a valid book title and see it appear in the list.
That slice may include a small amount of:
It crosses more than one technical layer, but it creates one complete behavior.
A horizontal task focuses on one technical layer without necessarily creating a usable result.
For example:
Create every JavaScript utility function the application may need.
That may produce many functions before the interface is ready to use them.
For a beginner project, vertical slices are usually easier to verify because each one answers a user-facing question.
Examples include:
Can the user see the form?
Can the user add a valid book?
Can the user see an error for a blank title?
Can the user remove a book?
Can the list survive a page refresh?Each question has a visible answer.
The first implementation should prove the main workflow with as little complexity as possible.
For the reading list project, the main workflow is:
Enter book details
→ Submit the form
→ See the book in the listYou do not need filtering, storage, editing, or an API to prove this workflow.
A practical first version can store books only in memory.
That means the list disappears after a page refresh.
This is acceptable temporarily because persistence is a separate feature.
The first goal is not to complete the final product.
It is to prove that the user can add and view a book.
Some features depend on earlier features.
For example, you cannot meaningfully add status filtering before books can be rendered.
You also cannot test persistence before the application has data worth saving.
A dependency sequence might look like:
Page structure
→ Basic styling
→ In-memory book state
→ Add Book behavior
→ Rendering
→ Validation
→ Removal
→ Filtering
→ Local storage
→ Final polishThis sequence avoids building features against missing foundations.
The JavaScript needs:
Those elements should exist before event handlers depend on them.
Filtering changes which books are rendered.
The app therefore needs a reliable rendering function before filter logic is introduced.
Either order can work.
However, if removal is implemented before persistence, you can test the core behavior without storage complexity.
Then persistence can be connected to both addition and removal in one later feature.
Local storage should preserve an already working application.
It should not be used to hide unclear state management.
Build the core behavior first, then persist it.
The Personal Reading List Tracker can be divided into the following implementation stages.
Create the semantic HTML needed for the application.
index.htmlThe page displays:
Create reading list page structureMake the existing interface readable and usable.
styles.cssThe page has:
Add responsive base stylesDefine an in-memory books array and display its contents.
app.jsThe application can render a small sample list or an empty state.
Add book list renderingAllow the user to submit a book and see it in the list.
app.jsThe HTML may need a small correction only if a required selector or ID is missing.
A valid submission creates a book object with:
id
title
author
status
createdAtThe new book appears immediately.
Add books through the formReject invalid titles without changing the list.
Validate book titlesThis feature is separate from basic form submission because validation introduces its own behavior and edge cases.
Allow one selected book to be removed.
Add book removalShow books matching the selected status.
The user can view:
Filtering must not modify the underlying data.
Filter books by reading statusPreserve the reading list across page refreshes.
Persist books in local storageMake the interface explain what is happening.
Improve empty and validation statesImprove the finished interface without changing the application scope.
Improve accessibility and mobile layoutA feature task is small enough when you can describe its outcome in one sentence.
Examples:
The user can add one valid book.
The user can remove one selected book.
The user can filter books by status.
The list remains after a page refresh.A task may still require more than one file.
The goal is not “one file per feature.”
The goal is one coherent result per feature.
For example, adding validation may require:
Those changes still belong together because they produce one user-visible behavior.
Acceptance criteria help determine whether a feature is focused.
For “Remove a Book”:
- Every book has a remove action.
- Removing one book leaves the others unchanged.
- The list updates immediately.
- The empty state appears when no books remain.That is a manageable feature.
Now compare it with:
- Remove books.
- Edit books.
- Undo removal.
- Restore deleted books after login.
- Synchronize deletion across devices.The second set describes several different systems.
Split it.
A useful question is:
Can I verify this feature with one short test checklist?
If the checklist becomes long or includes unrelated workflows, the feature may be too large.
A feature plan becomes useful when each feature maps to a focused AI request.
For example:
Feature:
Add book removal.
Prompt goal:
Add one remove action to each rendered book and update the in-memory books array when selected.
Allowed files:
app.js
Acceptance criteria:
- One selected book is removed.
- Other books remain.
- The empty state returns when needed.
Excluded:
- Editing
- Undo
- Local storage
- Confirmation dialogThis prompt is easier to reason about than:
Make the book cards fully interactive.A useful feature usually creates a natural commit boundary.
For example:
Prompt:
Add status filtering.
Review:
Check filter values and rendering behavior.
Test:
Select each status and confirm the correct books appear.
Commit:
Filter books by reading status.This relationship is valuable:
One feature
→ One focused prompt
→ One reviewable diff
→ One test checklist
→ One meaningful commitNot every task must produce exactly one commit.
A complicated feature may need more than one.
The important point is that unrelated work should not be grouped together only because it occurred in the same AI session.
Once the current feature meets its acceptance criteria, stop.
Do not immediately ask:
Now improve everything else.Instead:
git status.This creates a stable checkpoint.
If the next feature fails, you still have a known working state.
AI tools often notice opportunities to reorganize code.
After one or two features, the assistant may propose:
Some refactoring may eventually be useful.
Early refactoring can create complexity before the project’s real patterns are visible.
For a small beginner app, a simple app.js file may be easier to understand than a six-folder architecture.
Refactor when there is a concrete reason, such as:
Do not refactor only because the AI prefers a more elaborate structure.
While building one feature, you may discover another issue.
For example, while adding removal, you may notice that duplicate book IDs are possible.
Do not automatically add a full ID-management system inside the same task.
Record the discovery:
Follow-up task:
Review ID generation and duplicate handling.Then finish the current feature if it remains safe to do so.
This practice keeps the current diff focused.
It also prevents one problem from turning into a chain of unrelated changes.
Small tasks are useful, but a task can be divided so far that the workflow becomes inefficient.
For example:
Task 1: Add opening form tag.
Task 2: Add closing form tag.
Task 3: Add title label.
Task 4: Add title input.These steps belong to one coherent page-structure feature.
A useful feature should create a meaningful result.
The page structure feature can include all required form controls because they are reviewed together and do not introduce complex behavior.
The goal is not the smallest possible change.
It is the smallest useful and reviewable change.
Before sending a prompt, ask:
When most answers are yes, the feature is probably small enough.
“Add local storage” may still be too broad if the current application is unstable.
Break the work into a sequence.
When a valid book is added, save the current books array under one storage key.When the page loads, read the saved array and render it.After removing a book, update the stored array.If the saved value contains invalid JSON, recover with an empty list and show a concise warning in the console.These may be separate prompts or one focused persistence feature, depending on the size of the current codebase.
The decision should be based on reviewability.
In real projects, small changes are easier to review because the reviewer can keep the intended behavior in mind while reading the diff.
That principle becomes even more important with AI-generated code.
An AI assistant may produce correct-looking code very quickly, but the human review speed does not increase at the same rate.
Keeping each task small balances that difference.
When I review an AI-assisted change, I want to understand:
A large mixed-purpose change makes those questions harder to answer.
Incremental development is therefore not only a beginner technique. It is a practical risk-control method.
For the Personal Reading List Tracker, use this sequence:
1. Create the page structure.
2. Add basic responsive styling.
3. Create book state and rendering.
4. Add valid books through the form.
5. Validate titles.
6. Remove books.
7. Filter by status.
8. Add local storage.
9. Improve empty and error states.
10. Review accessibility and mobile behavior.
11. Add tests where appropriate.
12. Prepare deployment.Each step should begin from a clean or understood Git state.
Each completed step should end with:
git status
git diffThen test, stage, review, and commit.
Before beginning implementation, confirm that your plan:
The reading list project now has a practical path from an empty repository to a working application.
Building one small feature at a time makes vibe coding easier to control.
Small tasks produce clearer prompts, smaller Git diffs, more focused tests, and safer commits. They also make it easier to identify which change introduced a bug and return to a known working state.
For the Personal Reading List Tracker, we will not ask the AI to build the complete application in one step.
We will move through page structure, styling, rendering, form behavior, validation, removal, filtering, persistence, and final review as separate features.
The next article will focus on reviewing AI-generated code even when you are not an expert in the language. We will use file scope, behavior, naming, dependencies, error handling, Git diffs, and testing to decide whether a generated change is safe to keep.
Comments
Post a Comment