Agent Skills in Claude Code and Visual Studio Code: Setup, Benefits, Risks, and a Step-by-Step Example
Reaching the point where an application appears to work on your computer is an important milestone.
It is not the same as being ready to publish.
A vibe-coded application may behave correctly during one successful demonstration while still containing broken edge cases, missing files, exposed development data, incorrect paths, or behavior that changes after deployment.
Testing and deployment should therefore be treated as separate stages.
Testing asks:
Does the application behave as intended under normal and unexpected conditions?
Deployment asks:
Can other people access the verified version in an environment outside my computer?
This article walks through a complete release process for the Personal Reading List Tracker. We will test its primary workflows, inspect the repository, prepare a release checkpoint, deploy it as a static website, verify the live version, and create a recovery plan.
Version note: Hosting dashboards, deployment settings, branch controls, and platform features can change. Verify current platform-specific instructions in the provider’s official documentation before publishing. The testing and release principles in this guide remain applicable across static hosting providers.
By the end of this guide, you should be able to:
Deployment does not make an application correct.
It only moves the current version into another environment.
If the local version contains a bug, deployment usually publishes that bug.
A weak release process looks like:
The app seems to work
→ Push files
→ Publish
→ Discover problems laterA stronger process looks like:
Freeze the scope
→ Define the expected behavior
→ Test locally
→ Review the repository
→ Create a release checkpoint
→ Deploy
→ Test the live version
→ Monitor and record issuesThe important difference is that deployment happens only after the application has passed a defined set of checks.
A release candidate is the exact version you are considering for publication.
It should not keep changing while you test it.
Suppose the reading list currently supports:
These features form the release scope.
Once testing begins, avoid adding unrelated improvements such as:
Record those ideas separately.
A release candidate becomes difficult to verify when the code keeps changing during testing.
Start with:
git statusIdeally, the result should show a clean working tree.
Then review recent history:
git log --oneline -8You should recognize the commits that created the current application.
For example:
c731ae2 Improve empty and validation states
a96c503 Persist book additions and removals
4f2a0bc Filter books by reading status
2ac7e31 Add book removal
fd81b26 Validate book titlesIf uncommitted changes exist, determine whether they are:
Do not begin final testing from an unknown state.
Your test plan should come from the project brief and acceptance criteria.
The Personal Reading List Tracker has one main user workflow:
Enter book details
→ Select a status
→ Add the book
→ View it in the list
→ Filter or remove it
→ Refresh and keep the saved stateTesting should cover that workflow under several conditions.
A useful test plan includes:
Do not test only the easiest successful path.
Open the application with no saved reading-list data.
You may need to clear the site’s local storage in browser developer tools before beginning.
Expected behavior:
Open the browser console.
There should be no unexpected JavaScript error.
A page that looks correct but reports an exception is not ready for release.
Use a realistic example:
Title: Kindred
Author: Octavia E. Butler
Status: FinishedExpected behavior:
Now add a second book:
Title: The Dispossessed
Author: Ursula K. Le Guin
Status: Want to ReadExpected behavior:
If the application exposes state through development logs, remove those logs before release.
When inspecting local storage, each item should still follow the intended data model:
{
"id": "unique-book-id",
"title": "Kindred",
"author": "Octavia E. Butler",
"status": "finished",
"createdAt": "2026-07-11T10:30:00.000Z"
}Exact ID and timestamp values will vary.
The important point is that required fields remain consistent.
Validation should prevent invalid data without damaging the current list.
Test an empty title.
Expected behavior:
Now test a whitespace-only title:
" "Expected behavior:
Test a title with surrounding spaces:
" Parable of the Sower "Expected behavior:
Parable of the Sower;Test an empty author.
Expected behavior:
undefined, null, or an empty label;Test special characters where appropriate:
The Hitchhiker’s Guide to the GalaxyThe apostrophe should display correctly.
You do not need to submit millions of characters to a beginner application.
Use realistic edge cases:
If the project brief does not prohibit duplicate books, do not invent that rule during release testing. Record duplicate handling as a future improvement if needed.
Add at least one book for each status:
Want to Read
Reading
FinishedSelect All.
Expected behavior:
Select Want to Read.
Expected behavior:
Repeat for Reading and Finished.
Then switch back to All.
All books should return.
Keep one filter active and add a new book.
For example:
Reading.Finished book.Expected behavior depends on the chosen design, but it should be consistent.
A common expected result is:
Reading filter;Finished or All is selected.Now remove the final visible book while a filter is active.
Expected behavior:
All shows the remaining books.These interaction tests often reveal bugs that single-feature tests miss.
Add at least three books.
Remove the middle item.
Expected behavior:
Remove all remaining books.
Expected behavior:
Refresh the page.
The deleted books should not return.
Local storage is one of the most important release checks for this application.
Use this sequence:
Inspect local storage using browser developer tools.
Check:
Clear the site’s storage and reload.
Expected behavior:
During development, you may temporarily replace the stored value with invalid JSON.
For example:
not-valid-jsonReload the application.
Expected behavior:
Restore or clear the test value afterward.
Do not ship deliberately corrupted data.
When the application includes optional book search, test it separately from manual entry.
The core manual workflow must continue working whether the API succeeds or fails.
Test a normal search term.
Expected behavior:
Submit an empty or too-short search.
Expected behavior:
Search for an unlikely string.
Expected behavior:
Use the browser’s offline mode or temporarily block the request.
Expected behavior:
Inspect the Network panel.
Confirm:
A browser-based secret should be treated as publicly visible.
Testing the interface alone is not enough.
Open the Console panel and repeat the major workflows.
Look for:
A few development warnings may not break the app, but each should be understood.
Remove logs such as:
console.log(books);
console.log(apiResponse);
console.log("test");before release unless they serve a deliberate operational purpose.
The Network panel can reveal:
Static sites often work locally but fail after deployment because of path differences.
Suppose the repository contains:
reading-list-tracker/
├── index.html
├── styles.css
├── app.js
└── assets/
└── book-icon.svgRelative references might look like:
<link rel="stylesheet" href="./styles.css">
<script src="./app.js" defer></script>
<img src="./assets/book-icon.svg" alt="">Be careful with root-relative paths such as:
<script src="/app.js"></script>A root-relative path may behave differently when the site is hosted under a repository subpath.
For example, a deployed URL may resemble:
https://example.com/reading-list-tracker/In that environment, /app.js may point to the domain root rather than the project directory.
Relative paths are often easier for a simple static project, but the correct choice depends on the hosting setup.
A file named:
Styles.cssis different from:
styles.csson many hosting systems.
A local environment may appear more forgiving than production.
Confirm that file names and references use identical capitalization.
The application should remain usable at different viewport widths.
You do not need dozens of devices.
Check at least:
At narrow widths, confirm:
Use the responsive design mode in browser developer tools, but also resize a normal browser window.
A device preview is useful, not perfect.
A beginner release does not require claiming full accessibility compliance.
It should still include basic usable patterns.
Check:
Use only the keyboard.
Try:
Confirm that you can:
A visible application that cannot be operated with a keyboard has an important usability gap.
Run:
git statusInspect all modified and untracked files.
Look for unwanted artifacts such as:
.env
.env.local
debug.log
test-output.txt
api-response.json
notes-private.txt
.DS_Store
Thumbs.dbCheck the full diff:
git diffReview staged changes separately:
git diff --stagedInspect the project for:
A simple text search can help:
grep -RniE "api[_-]?key|secret|token|password|authorization|bearer" .This command may find harmless examples or documentation, so review every result.
It does not prove the repository is secret-free.
.gitignoreA simple static project may ignore files such as:
.env
.env.local
.DS_Store
Thumbs.dbOnly ignore files that are genuinely local or sensitive.
Do not use .gitignore to hide source files required for deployment.
A plain HTML, CSS, and JavaScript application may not require a build step.
The deployment contents may be:
index.html
styles.css
app.js
assets/
README.mdThe README does not affect the website, though it may remain in the repository.
Confirm that index.html is in the location expected by the hosting provider.
If the project uses a build tool, the provider may need the generated output directory rather than the source directory.
Examples of possible output directory names include:
dist
build
publicDo not guess.
Check the project configuration and current hosting documentation.
For this series, the simplest deployment path is a static site with no required server process.
After all required fixes are complete, run the full test checklist again.
Then stage the intended files:
git add index.html styles.css app.js README.mdReview:
git diff --stagedCreate a release-focused commit:
git commit -m "Prepare reading list tracker for deployment"You may also create a version tag when it helps your workflow:
git tag -a v1.0.0 -m "First public release"Push the commit and tag when appropriate:
git push
git push --tagsA tag is optional for a small beginner project, but it creates a clear reference to the published version.
Before using version numbers, keep the scheme simple and consistent.
The reading list tracker can be deployed to a static hosting service because it does not require a continuously running backend.
Common hosting approaches include:
The exact provider is less important than the release process.
A typical repository-based deployment looks like:
Git repository
→ Hosting provider reads selected branch
→ Provider publishes static files
→ Public URL becomes availableBefore enabling deployment, confirm:
For this project, a no-build static deployment is the simplest option.
A platform-neutral process may look like this.
git push origin mainIn the hosting provider’s dashboard:
index.html;Exact interface wording varies.
The provider copies or builds the project and assigns a public URL.
Look for:
Do not ignore a warning simply because the provider reports a successful deployment.
Do not assume the live application matches the local one.
Begin the post-deployment test process.
Repeat the critical local tests using the public URL.
At minimum, verify:
Test in:
A normal browser may contain cached files or existing local storage from development.
A fresh context helps reveal:
Local storage is tied to the site’s origin.
That means data saved under a local development address does not automatically appear on the deployed site.
For example:
Local:
http://127.0.0.1:5500
Deployed:
https://example-host.com/reading-list-trackerThese are different origins.
The live application will begin with its own empty local storage.
This is expected behavior, not data loss.
Also remember:
The app should not claim that data is backed up or shared across devices.
Inspect the live page and network requests.
Confirm:
View the deployed JavaScript source.
Anything included in the browser bundle should be considered public.
When an API requires a private key, that key must remain in a protected server-side environment.
Before sharing the application, review the HTML document metadata.
At minimum:
<title>Personal Reading List Tracker</title>
<meta
name="description"
content="A simple browser-based app for saving books and tracking reading status."
>
<meta name="viewport" content="width=device-width, initial-scale=1">Confirm:
Test, Click Here, or TODO;Metadata does not repair a weak application, but it helps the published result feel complete.
Static deployment paths can behave differently after refresh.
For a one-page application using only index.html, refresh should normally work.
If the project later adds client-side routes such as:
/books
/settingsthe hosting provider may need additional fallback configuration.
For the current reading list tracker, keep the routing simple.
Test:
Update the README with:
For example:
## Data Storage
The app stores books in the browser's localStorage.
Data is specific to the current browser and site address. It is not synchronized between devices and may be removed when site data is cleared.This prevents users from assuming the project includes accounts, backups, or cloud storage.
Useful limitations may include:
Honest limitations make a small application easier to trust.
A release is not complete immediately after the hosting provider reports success.
Use a checklist like this:
[ ] Public URL loads
[ ] HTTPS works
[ ] CSS loads
[ ] JavaScript runs
[ ] Console has no unexpected errors
[ ] Add Book works
[ ] Validation works
[ ] Filtering works
[ ] Removal works
[ ] Refresh persistence works
[ ] Empty states work
[ ] Mobile layout is usable
[ ] Keyboard navigation works
[ ] No secret is visible
[ ] Optional API fails gracefully
[ ] README contains the live URLRecord the date and commit hash associated with the deployment.
For example:
Deployment:
v1.0.0
Commit:
8c3f9d1
Verified:
[publication date]This makes future debugging more precise.
A deployed version should be rolled back or replaced when it contains a serious problem.
Examples include:
A visual spacing issue may be fixed in the next normal update.
An exposed credential requires immediate action.
Depending on the hosting provider and workflow, recovery may involve:
The exact dashboard controls vary.
Git gives you a provider-independent recovery path.
For a bad commit:
git revert <commit-hash>
git pushThe hosting provider can then deploy the new revert commit.
A public bug can create pressure to move quickly.
Avoid this sequence:
See bug
→ Ask AI to fix everything
→ Push without testing
→ Create another bugUse a smaller emergency process:
Reproduce live bug
→ Confirm local reproduction
→ Identify relevant commit
→ Create focused fix
→ Test locally
→ Review diff
→ Commit
→ Deploy
→ Verify liveThe urgency of a bug does not remove the need for evidence.
It makes a focused process more important.
The following matrix summarizes useful checks for the reading list tracker.
| Area | Test | Expected Result |
|---|---|---|
| Initial state | Open with no storage | Empty state appears |
| Add book | Valid title and author | One book appears |
| Validation | Empty title | Book is rejected |
| Validation | Spaces-only title | Book is rejected |
| Author | Empty author | Book is accepted |
| Filtering | Select each status | Only matching books appear |
| Removal | Remove one of several | Only selected book disappears |
| Persistence | Refresh after adding | Books remain |
| Persistence | Refresh after removal | Removed book stays removed |
| Storage failure | Invalid JSON | App recovers safely |
| API search | Successful request | Results appear |
| API failure | Offline request | Manual entry remains usable |
| Responsive | Narrow viewport | Controls remain usable |
| Keyboard | Tab through interface | All controls are reachable |
| Deployment | Fresh browser | App initializes correctly |
| Security | Inspect network and files | No private secret is exposed |
This matrix can be adapted as the project grows.
A single working book does not prove validation, filtering, removal, or persistence.
Freeze the release candidate before final testing.
Run the application and verify behavior yourself.
The interface may look correct while JavaScript reports problems.
Filtering may work until a book is removed or added.
A fresh user starts with no local data.
Local success does not prove deployed success.
It does not synchronize between browsers or devices.
Untracked logs and response files may contain data you did not intend to share.
Confirm which branch and commit the host publishes.
The host must find the correct index.html or generated output directory.
Root-relative paths may fail under a repository subdirectory.
Client-side variables may become public.
Open and test the public URL.
Secure pages may block insecure resources.
The release commit should have one clear purpose.
Know which commit represents the last verified release.
Use this sequence for the first public version:
1. Stop adding features.
2. Confirm the project brief and release scope.
3. Start from a clean Git state.
4. Run the complete local test checklist.
5. Fix one verified issue at a time.
6. Repeat affected tests.
7. Review responsive and keyboard behavior.
8. Inspect console and network activity.
9. Review storage and optional API behavior.
10. Search the repository for secrets and artifacts.
11. Review every changed file.
12. Create a release commit.
13. Push the verified commit.
14. Deploy the correct branch and folder.
15. Review deployment logs.
16. Test the live URL in a fresh browser.
17. Record the deployed commit.
18. Revert or redeploy if a serious issue appears.This process is intentionally repetitive.
Release confidence comes from checking the same important assumptions at several boundaries.
In real software delivery, deployment problems are often caused by small assumptions rather than dramatic coding failures.
A file path works locally but not on the host.
A setting exists on one machine but not in production.
A browser contains old local storage that hides an initialization bug.
A successful API response receives more testing than the failure path.
AI-generated applications are especially vulnerable to these assumptions because the code can be produced before the developer fully understands the deployment environment.
The most useful release habit is to separate evidence into three stages:
Local evidence
→ Repository evidence
→ Live evidenceLocal evidence shows that the feature works on your computer.
Repository evidence shows that the correct files and configuration are committed.
Live evidence shows that the deployed application behaves correctly in its public environment.
All three matter.
Testing and deployment are not the final button presses after vibe coding.
They are development stages that require their own evidence.
For the Personal Reading List Tracker, a responsible release includes testing the complete user workflow, invalid inputs, filtering, removal, local storage, optional API failure, responsive layout, keyboard navigation, repository contents, and deployed behavior.
The core release sequence is:
Freeze
→ Test
→ Review
→ Commit
→ Deploy
→ Verify
→ Recover when necessaryA live URL is valuable only when you know which version it contains and how that version was tested.
The final article in this series will step back from the project and examine the limits and future of vibe coding. We will look at where AI-assisted development provides real value, where it creates risk, which skills remain essential, and how beginners can continue improving after completing their first application.
Not necessarily for a small learning project, but you do need a repeatable verification process.
Manual testing can be sufficient for a simple first release when the workflows and results are documented clearly. Automated tests become more valuable as the application and number of regressions grow.
No.
Treat that statement as a suggestion. Review the repository, run the application, test the acceptance criteria, inspect the browser console, and verify the deployed version yourself.
Local storage belongs to a specific browser origin.
Data saved under a local development address does not automatically transfer to a deployed domain. The public version begins with its own separate storage.
Comments
Post a Comment