Build an AI Debug Coach

Build and deploy a jQuery and Express app that diagnoses coding errors with AI.

Introduction

30 Second Summary

A single red error can halt your progress for longer than the bug itself. The hardest part is often turning that message into the next useful check.

In this project, you will build an AI Debug Coach that uses jQuery, Express, and Vercel AI Gateway to turn pasted errors into practical diagnoses. You will deploy the finished app to a public URL.

What You'll Build

At your public URL, the finished app turns ReferenceError: total is not defined into a tailored diagnosis with four labeled sections and three practical checks.

By the end of this project, you'll have:

  • A responsive browser form that turns a runtime error plus optional code into a clear debugging plan.
  • A visible AJAX request flow that sends JSON from jQuery to Express. Validation problems and request failures appear clearly on the page.
  • A public Vercel deployment you can share, where different errors produce tailored diagnoses with four labeled sections.
  • Secret Mission: Add a programming language selector so each diagnosis uses language-specific context.

Before We Start

Before any setup, choose one real development error you want to understand. This gives your AI Debug Coach a concrete problem to turn into a practical debugging plan.

Set Up the Windows Project

Your AI Debug Coach needs a stable local runtime before its browser interface can communicate with a server. The Vercel AI SDK requires a compatible Node.js version.

In this step, you will verify Node.js. You will prepare a pinned project in Visual Studio Code. You will finish by running a temporary Express server.

In this step, get ready to:
  • Verify a compatible Node.js 22.x version plus npm.
  • Create the project files that pin dependencies and protect local credentials.
  • Install the dependencies and run the temporary Express server.
Verify Node.js and npm

Node.js runs your server-side JavaScript. The npm command installs the exact packages listed in your project configuration.

  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open PowerShell.
  • Check the installed Node.js and npm versions by running:
node -v
npm -v

What should these commands show?

The first command prints your installed Node.js version. This project needs Node.js 22.18 or later within the 22.x release line.

The second command prints your npm version. A version number confirms that npm is available.

✔️ I see Node.js 22.18 or higher in 22.x

Your runtime meets the project requirement. npm is ready when its command also prints a version number.

ⓧ I see an older Node.js version

Your current runtime is below the version required by the AI SDK. Update it before creating the project.

  • Open the official Node.js download page.
  • Download Node.js v22.23.3 LTS for Windows.
  • Close Visual Studio Code.
  • Run the downloaded installer.
  • Follow the installer prompts to complete the update.
  • Reopen PowerShell through Windows search.
  • Verify the updated versions by running:
node -v
npm -v

What should you see?

The Node.js output should show v22.23.3 or another compatible 22.x version. The npm command should print its version number.

Still seeing the older version?

Close every open PowerShell window after the installer finishes. Open a fresh PowerShell window so Windows reloads the updated command path.

Ask for help if the old version remains active: help me verify which Node.js installation Windows PowerShell is using

ⓧ The node command is not found

Windows cannot currently find a Node.js installation. Install the pinned LTS release before continuing.

  • Open the official Node.js download page.
  • Download Node.js v22.23.3 LTS for Windows.
  • Run the downloaded installer.
  • Follow the installer prompts to complete the installation.
  • Open a fresh PowerShell window through Windows search.
  • Verify the installation by running:
node -v
npm -v

What should you see?

The first command should print v22.23.3 or another compatible 22.x version. The second command should print an npm version number.

Commands still unavailable?

Restart Windows if a fresh PowerShell window still cannot find the commands. This forces Windows to reload the installation path.

Ask for help if the commands remain unavailable: help me troubleshoot a missing Node.js command on Windows

  • Press the Windows key to open Windows search.
  • Type Visual Studio Code into the search field.
  • Press Enter to open Visual Studio Code.

Your runtime is ready. Visual Studio Code is now the workspace for every project file you create next.

Create the project files

Opening a folder in Visual Studio Code turns that folder into a workspace. The Explorer view then keeps every project file in one visible place.

Visual Studio Code may display a Workspace Trust prompt after the folder opens. You created this empty folder yourself, so you can trust its contents.

  • Select File from the Visual Studio Code menu.
  • Select Open Folder....
  • Select your Desktop in the folder picker.
  • Select New Folder.
  • Enter ai-debug-coach as the folder name.
  • Select Select Folder.
  • Select Yes, I trust the authors if the Workspace Trust dialog appears.

You should see ai-debug-coach at the top of the Explorer view. This confirms that every new file lands inside the project folder on your Desktop.

  • Select New File... in the Explorer view.
  • Enter package.json as the file name.
  • Press Enter.
  • Fill package.json with the pinned project configuration by pasting:
{
  "name": "ai-debug-coach",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": "22.x"
  },
  "scripts": {
    "start": "node --env-file=.env server.js",
    "deploy": "vercel --prod"
  },
  "dependencies": {
    "ai": "7.0.138",
    "express": "5.3.0"
  },
  "devDependencies": {
    "vercel": "63.1.2"
  }
}

What does this configuration do?

  • The engines field records the required Node.js 22.x release line.
  • The dependencies field pins the Vercel AI SDK to 7.0.138.
  • The Express dependency is pinned to 5.3.0.
  • The Vercel development dependency is pinned to 63.1.2.
  • The start script loads local environment values before starting server.js.
  • Save package.json.
  • Confirm package.json is listed under ai-debug-coach in the Explorer view.

Does package.json show a problem?

JSON requires every quoted key and value to match the code exactly. Compare the braces plus commas with the reference before continuing.

Ask for help with any highlighted syntax problem: help me find the JSON syntax issue in my package.json file

The next two files establish a safe place for a local credential. They contain a placeholder now, so no live secret is exposed.

  • Select New File... in the Explorer view.
  • Enter .env.example as the file name.
  • Press Enter.
  • Fill .env.example with the reusable environment template by pasting:
AI_GATEWAY_API_KEY=your-api-key-here

Why create an environment template?

The template records the required AI_GATEWAY_API_KEY name without storing a real credential. Another developer can copy this structure safely.

  • Save .env.example.
  • Confirm .env.example is visible in the Explorer view.
  • Select New File... in the Explorer view.
  • Enter .env as the file name.
  • Press Enter.
  • Create the local copy of the environment template by pasting:
AI_GATEWAY_API_KEY=your-api-key-here

What belongs in .env?

The local .env file eventually holds the credential used during local development. The placeholder keeps this setup safe until the AI integration step.

  • Save .env.
  • Confirm .env appears beside .env.example in the Explorer view.
  • Select New File... in the Explorer view.
  • Enter .gitignore as the file name.
  • Press Enter.
  • Protect generated files plus local credentials by pasting:
node_modules
.env
.vercel

What does .gitignore protect?

This file excludes installed packages plus the local environment file from Git tracking. It also excludes local Vercel project metadata.

  • Save .gitignore.
  • Confirm .gitignore appears in the Explorer view.
  • Select New File... in the Explorer view.
  • Enter .vercelignore as the file name.
  • Press Enter.
  • Exclude the local environment file from future deployment uploads by pasting:
.env

Why use a second ignore file?

The .vercelignore file controls which local files Vercel excludes from an upload. Listing .env keeps the local credential file outside the deployment bundle.

  • Save .vercelignore.
  • Confirm all five configuration files appear under ai-debug-coach in the Explorer view.
Install dependencies and run the server

Your pinned configuration now gives npm a precise installation plan. Installing from that file keeps each learner on the same package versions.

  • Select View from the Visual Studio Code menu.
  • Select Terminal.
  • Confirm the terminal path ends with ai-debug-coach.
  • Install the pinned project dependencies by running:
npm install

The command finishes after npm installs the dependencies. You should see node_modules appear in the Explorer view.

Did the installation fail?

  • Confirm the terminal path ends with ai-debug-coach.
  • Compare package.json with the pinned configuration above.
  • Retry the installation after confirming your internet connection.

Ask for help with the terminal output: help me diagnose why npm install failed in this project

The temporary server proves that the runtime plus Express can answer a browser request. Its single route returns a short setup confirmation.

  • Select New File... in the Explorer view.
  • Enter server.js as the file name.
  • Press Enter.
  • Create the temporary Express server by pasting:
import express from 'express';

const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('AI Debug Coach setup complete.');
});

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

What does this server do?

  • The Express import provides the server and routing tools.
  • The app value represents your Express application.
  • The root route responds with the setup confirmation text.
  • The listener accepts local requests on port 3000.
  • Save server.js.
  • Confirm server.js appears in the Explorer view.

Before you start the server, what do you expect PowerShell and the browser to confirm?

  • Start the Express server by running:
npm start

You should see AI Debug Coach is running at http://localhost:3000 in the terminal. The server keeps this terminal busy while it waits for browser requests.

Your browser should display AI Debug Coach setup complete. This proves that Node.js loaded the environment file plus started the Express route successfully.

Server not responding?

  • Confirm the terminal is still running the server.
  • Compare server.js with the reference below.
  • Confirm .env exists beside package.json.

Ask for help with the terminal output: help me debug why my temporary Express server does not respond

✔️ Awesome, I've got everything!

Great. Keep the server running and confirm that every project file is saved.

ⓧ I'd like to double check the full code

Compare each file with these complete references. Every value should match exactly.

AI_GATEWAY_API_KEY=your-api-key-here
AI_GATEWAY_API_KEY=your-api-key-here
node_modules
.env
.vercel
.env
{
  "name": "ai-debug-coach",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": "22.x"
  },
  "scripts": {
    "start": "node --env-file=.env server.js",
    "deploy": "vercel --prod"
  },
  "dependencies": {
    "ai": "7.0.138",
    "express": "5.3.0"
  },
  "devDependencies": {
    "vercel": "63.1.2"
  }
}
import express from 'express';

const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('AI Debug Coach setup complete.');
});

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

Your Windows project is running with pinned dependencies plus protected local configuration. Next up, you will replace the temporary message with the Debug Coach interface.

Build the Debug Coach Interface

Your starter Express server already responds to the browser. That proves the local project works, but a setup sentence cannot collect an error for diagnosis.

A visible form gives you a usable first version before the API or AI logic arrives. In this step, you will build it with HTML, CSS, and jQuery 4.0.0.

In this step, get ready to:
  • Create the error form with its status region and diagnosis panel.
  • Style the interface for wide screens and narrow screens.
  • Serve the completed interface from the local Express app.
Build and serve the page structure

The public directory holds files that the browser can request directly. Your first file defines the page structure and loads the browser scripts.

  • Create a folder named public inside the ai-debug-coach folder using the VS Code Explorer sidebar.

You should see the new public folder beneath the existing project files in the Explorer sidebar.

  • Create a file named index.html inside the public folder.
  • Build the page shell by pasting this code into public/index.html:
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AI Debug Coach</title>
    <link rel="stylesheet" href="/styles.css" />
  </head>
  <body>
    <main class="app-shell">
      <section class="intro-panel">
        <p class="eyebrow">jQuery + Express + AI Gateway</p>
        <h1>AI Debug Coach</h1>
        <p>
          Paste an error and optional code to get an explanation, a likely cause,
          and three practical checks.
        </p>
      </section>
    </main>

    <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
    <script src="/app.js"></script>
  </body>
</html>

What Does This HTML Do?

  • The document metadata gives the page a browser title and a responsive viewport.
  • The intro-panel section explains what the Debug Coach produces.
  • The first script loads jQuery 4.0.0 from its CDN.
  • The second script establishes the location for the form behavior you add in the next step.
  • Save public/index.html.
  • Confirm that index.html appears inside public in the Explorer sidebar.

Page File in the Wrong Place?

Check that the Explorer sidebar shows index.html directly inside public.

Help me place the page file correctly.

The temporary root route still answers requests with the setup sentence. Static middleware connects the browser to the files inside public.

  • Replace the entire contents of server.js with this code:
import express from 'express';

const app = express();
const port = 3000;

app.use(express.static('public'));

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

How Does Static Serving Work?

  • The Express import creates the server application.
  • The express.static('public') middleware serves files stored inside public.
  • A request for the site root now resolves to public/index.html.
  • The listener keeps the local app available on port 3000.
  • Save server.js.
  • Return to the VS Code terminal from the previous step.
  • Stop the temporary server by pressing Ctrl+C.
  • Start the updated server by running:
npm start

What Does This Confirm?

The start script runs the updated server.js file. The terminal message confirms that Express is listening on port 3000.

  • Return to the browser tab showing http://localhost:3000.
  • Refresh the page.

You should see the AI Debug Coach heading with a short explanation underneath. The setup sentence has been replaced by your own browser page.

Still Seeing the Setup Sentence?

Confirm that server.js contains app.use(express.static('public'));. Stop the previous server process before running the updated file.

Help me debug the static page.

✔️ Awesome, I've got everything!

Your server now serves browser files from the public directory.

ⓧ I'd like to double check the full code

Compare your complete server.js file with this version:

import express from 'express';

const app = express();
const port = 3000;

app.use(express.static('public'));

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

The page shell introduces the tool. The coach panel adds the inputs, status region, and hidden result area required for a complete diagnosis flow.

  • In public/index.html, find the closing </main> tag.
  • Insert this coach panel directly above the closing </main> tag:
      <section class="coach-panel">
        <form id="debug-form">
          <label for="error-message">Error message</label>
          <textarea
            id="error-message"
            maxlength="1200"
            required
            placeholder="ReferenceError: total is not defined"
          ></textarea>

          <label for="code">Relevant code <span>(optional)</span></label>
          <textarea
            id="code"
            class="code-input"
            maxlength="6000"
            placeholder="console.log(total);"
          ></textarea>

          <button id="submit-button" type="submit">Diagnose Error</button>
        </form>

        <p id="status" class="status" aria-live="polite"></p>

        <section id="result" class="result-panel" aria-live="polite" hidden>
          <h2>Diagnosis</h2>
          <pre id="diagnosis"></pre>
        </section>
      </section>

How Is the Interface Structured?

  • The debug-form groups the values that the browser logic submits later.
  • The error-message field requires an error before submission.
  • The code field accepts optional debugging context.
  • The status region communicates request progress.
  • The hidden result panel waits for a successful diagnosis.
  • Save public/index.html.
  • Refresh http://localhost:3000.

You should see an error-message field with an optional code field underneath. The Diagnose Error button appears below both fields.

Form Missing from the Page?

Make sure the coach-panel section sits inside <main class="app-shell">. Check that the new section appears before the closing </main> tag.

Help me find the missing form.

✔️ Awesome, I've got everything!

Great. Save public/index.html before moving on to the visual design.

ⓧ I'd like to double check the full code

Compare your complete public/index.html file with this version:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AI Debug Coach</title>
    <link rel="stylesheet" href="/styles.css" />
  </head>
  <body>
    <main class="app-shell">
      <section class="intro-panel">
        <p class="eyebrow">jQuery + Express + AI Gateway</p>
        <h1>AI Debug Coach</h1>
        <p>
          Paste an error and optional code to get an explanation, a likely cause,
          and three practical checks.
        </p>
      </section>

      <section class="coach-panel">
        <form id="debug-form">
          <label for="error-message">Error message</label>
          <textarea
            id="error-message"
            maxlength="1200"
            required
            placeholder="ReferenceError: total is not defined"
          ></textarea>

          <label for="code">Relevant code <span>(optional)</span></label>
          <textarea
            id="code"
            class="code-input"
            maxlength="6000"
            placeholder="console.log(total);"
          ></textarea>

          <button id="submit-button" type="submit">Diagnose Error</button>
        </form>

        <p id="status" class="status" aria-live="polite"></p>

        <section id="result" class="result-panel" aria-live="polite" hidden>
          <h2>Diagnosis</h2>
          <pre id="diagnosis"></pre>
        </section>
      </section>
    </main>

    <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
    <script src="/app.js"></script>
  </body>
</html>
Style the responsive interface

The form now has every required element, but the browser defaults make it difficult to scan. The stylesheet turns it into a focused workspace with a responsive layout.

  • Create a file named styles.css inside the public folder.
  • Add the page foundation by pasting this code into public/styles.css:
:root {
  color-scheme: dark;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  background: #07111f;
  color: #e8f0ff;
}

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  background:
    radial-gradient(circle at top left, #17335f 0, transparent 35%),
    #07111f;
}

.app-shell {
  width: min(1100px, 92vw);
  margin: 0 auto;
  padding: 64px 0;
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 32px;
}

What Does This Styling Control?

  • The root rules establish the shared font and dark color palette.
  • The universal selector keeps element dimensions predictable.
  • The body combines a blue glow with a dark base color.
  • The app-shell grid gives the form more space than the introduction.
  • Save public/styles.css.
  • Refresh the browser.

You should see a dark blue background. The introduction and form should sit in two columns on a wide screen.

Still Seeing a White Page?

Check that styles.css sits inside public. Confirm that index.html links to /styles.css.

Help me debug the missing styles.

  • Add the panel and heading styles below the .app-shell block:
.intro-panel,
.coach-panel {
  border: 1px solid #29456f;
  border-radius: 20px;
  background: rgba(10, 25, 45, 0.92);
  padding: 28px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.28);
}

.eyebrow {
  color: #70d8ff;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  font-size: clamp(2.4rem, 6vw, 4.4rem);
  line-height: 0.98;
}

How Do the Panels Take Shape?

  • Both panels share the same border and translucent background.
  • Rounded corners and a shadow separate the workspace from the page background.
  • The eyebrow style turns the technology line into a compact label.
  • The main heading scales with the browser width.
  • Save public/styles.css.
  • Refresh the browser.

You should see both columns inside rounded dark panels. The technology label should appear in bright blue uppercase text.

Panels Still Look Plain?

Compare the .intro-panel and .coach-panel selectors with the class values in public/index.html.

Help me match the panel selectors.

  • Add the label and textarea styles below the h1 block:
label {
  display: block;
  margin: 18px 0 8px;
  font-weight: 750;
}

label span {
  color: #93a4bd;
  font-weight: 500;
}

textarea {
  width: 100%;
  min-height: 120px;
  resize: vertical;
  border: 1px solid #3a5d8c;
  border-radius: 12px;
  padding: 14px;
  background: #06101e;
  color: #f7fbff;
  font: inherit;
}

Why Style the Form Fields?

  • Block labels create a clear title above each input.
  • The optional label text uses a quieter color.
  • Each textarea fills the available panel width.
  • Vertical resizing gives longer errors more room.
  • Save public/styles.css.
  • Refresh the browser.

You should see two dark textareas with rounded blue borders. Each field should remain inside the coach panel.

Textareas Overflowing the Panel?

Confirm that the universal selector uses box-sizing: border-box. Check that the textarea width is 100%.

Help me fix the textarea layout.

  • Add the code font and form-state styles below the textarea block:
.code-input,
#diagnosis {
  font-family: Consolas, Monaco, monospace;
}

button {
  width: 100%;
  margin-top: 18px;
  border: 0;
  border-radius: 12px;
  padding: 14px 18px;
  background: #65d6ff;
  color: #06223a;
  font-weight: 850;
  cursor: pointer;
}

button:disabled {
  cursor: wait;
  opacity: 0.65;
}

.status {
  min-height: 24px;
  margin: 18px 0 0;
  color: #b8c8df;
}

How Do These States Help?

  • A monospace font makes code and diagnosis text easier to scan.
  • The full-width button creates one clear form action.
  • The disabled state signals that a request is in progress.
  • The status region reserves space for progress and error messages.
  • Save public/styles.css.
  • Refresh the browser.

You should see a bright blue Diagnose Error button spanning the form panel. The optional code field should use a monospace font.

Button Missing Its Blue Style?

Check that the selector is written as button. Confirm that public/index.html uses a <button> element.

Help me debug the button style.

  • Finish the diagnosis panel and narrow-screen layout by adding this code below the .status block:
.result-panel {
  margin-top: 18px;
  border-radius: 14px;
  padding: 20px;
  background: #0d2039;
}

#diagnosis {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: #e8f0ff;
}

@media (max-width: 760px) {
  .app-shell {
    grid-template-columns: 1fr;
    padding: 28px 0;
  }
}

What Makes the Page Responsive?

  • The result panel gives each diagnosis its own dark surface.
  • The diagnosis preserves line breaks from the response.
  • Long error text wraps inside the panel.
  • The media query changes the grid to one column below 760px.
  • Save public/styles.css.
  • Refresh the browser.
  • Narrow the browser window below 760px.

You should see the form panel move below the introduction panel. The controls should remain inside the browser width.

Layout Staying in Two Columns?

Check that grid-template-columns: 1fr sits inside the media query's .app-shell block. Confirm that both closing braces are present.

Help me debug the responsive layout.

✔️ Awesome, I've got everything!

Your stylesheet now covers the background, panels, form controls, result area, and narrow-screen layout.

ⓧ I'd like to double check the full code

Compare your complete public/styles.css file with this version:

:root {
  color-scheme: dark;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  background: #07111f;
  color: #e8f0ff;
}

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  background:
    radial-gradient(circle at top left, #17335f 0, transparent 35%),
    #07111f;
}

.app-shell {
  width: min(1100px, 92vw);
  margin: 0 auto;
  padding: 64px 0;
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 32px;
}

.intro-panel,
.coach-panel {
  border: 1px solid #29456f;
  border-radius: 20px;
  background: rgba(10, 25, 45, 0.92);
  padding: 28px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.28);
}

.eyebrow {
  color: #70d8ff;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  font-size: clamp(2.4rem, 6vw, 4.4rem);
  line-height: 0.98;
}

label {
  display: block;
  margin: 18px 0 8px;
  font-weight: 750;
}

label span {
  color: #93a4bd;
  font-weight: 500;
}

textarea {
  width: 100%;
  min-height: 120px;
  resize: vertical;
  border: 1px solid #3a5d8c;
  border-radius: 12px;
  padding: 14px;
  background: #06101e;
  color: #f7fbff;
  font: inherit;
}

.code-input,
#diagnosis {
  font-family: Consolas, Monaco, monospace;
}

button {
  width: 100%;
  margin-top: 18px;
  border: 0;
  border-radius: 12px;
  padding: 14px 18px;
  background: #65d6ff;
  color: #06223a;
  font-weight: 850;
  cursor: pointer;
}

button:disabled {
  cursor: wait;
  opacity: 0.65;
}

.status {
  min-height: 24px;
  margin: 18px 0 0;
  color: #b8c8df;
}

.result-panel {
  margin-top: 18px;
  border-radius: 14px;
  padding: 20px;
  background: #0d2039;
}

#diagnosis {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: #e8f0ff;
}

@media (max-width: 760px) {
  .app-shell {
    grid-template-columns: 1fr;
    padding: 28px 0;
  }
}
Verify the complete interface

The browser now has every visible control required for the first usable version. The diagnosis panel remains hidden until a later request returns a result.

Before you refresh, which fields and controls do you expect to see in the coach panel?

  • Return to the browser tab at http://localhost:3000.
  • Refresh the page.

You should see the error-message field, the optional code field, and the Diagnose Error button. A wide browser window should show the dark two-panel layout.

  • Narrow the browser window below 760px.

You should see the form stack below the introduction. That confirms the responsive interface works across both layouts.

That is your first visible Debug Coach milestone. Next up, you will connect the form to a real browser request and expose the missing API route.

Send an AJAX Request

Your styled AI Debug Coach can collect an error in the browser. Its form still has no request path to the server.

In this step, jQuery uses AJAX to send the fields as JSON to Express. The response will show whether that request path exists.

In this step, get ready to:
  • Capture the form values without reloading the page.
  • Send the field values to /api/debug as JSON.
  • Surface the server response inside the interface.
Capture the form submission

A submit handler intercepts the form before the browser reloads the page. This gives jQuery control over what happens to the entered values.

  • Create public/app.js with the following code by using the VS Code Explorer sidebar:
$(function () {
  $('#debug-form').on('submit', function (event) {
    event.preventDefault();

    const errorMessage = $('#error-message').val().trim();
    const code = $('#code').val().trim();

    if (!errorMessage) {
      $('#status').text('Please enter an error message.');
      return;
    }

    $('#submit-button').prop('disabled', true).text('Diagnosing...');
    $('#status').text('Sending the error to your Express API...');
    $('#result').prop('hidden', true);
    $('#diagnosis').text('');
  });
});

What does this code do?

  • The outer $(function () { wrapper waits until the page is ready.
  • The #debug-form selector identifies the form that triggers the handler.
  • The event.preventDefault() call keeps the browser on the current page.
  • The errorMessage variable holds the trimmed error text.
  • The code variable holds the trimmed optional code.
  • The validation branch stops an empty error message from continuing.
  • The final lines prepare the loading state before a request begins.

This first slice is a deliberate checkpoint that ends at the loading state. The next chunk adds the request callbacks that restore the interface.

  • Save public/app.js.
  • Refresh the browser page at http://localhost:3000.
  • Enter ReferenceError: total is not defined in the error field.
  • Click Diagnose Error.

You should see Sending the error to your Express API... in the status region. The button should display Diagnosing....

You have the first connection working: the page stays put while the form enters its loading state.

  • Refresh the browser page to reset the loading state.

Loading State Not Appearing?

A page reload usually means event.preventDefault() is missing. Confirm that it remains at the start of the submit handler.

A missing status change often means the script did not load. Confirm that public/app.js is saved inside the public folder.

Help me debug why my jQuery submit handler does not show the loading state.

Send JSON and manage every outcome

The handler now has the values required for a request. Separate callbacks let the interface respond to successful requests or failed requests.

  • In public/app.js, find the line $('#diagnosis').text('');.
  • Paste the following request block directly below that line:
    $.ajax({
      url: '/api/debug',
      method: 'POST',
      contentType: 'application/json',
      dataType: 'json',
      data: JSON.stringify({ errorMessage, code }),
    })
      .done(function (response) {
        $('#diagnosis').text(response.diagnosis);
        $('#result').prop('hidden', false);
        $('#status').text('Diagnosis ready.');
      })
      .fail(function (xhr) {
        const message =
          xhr.responseJSON?.error || `Request failed with status ${xhr.status}.`;
        $('#status').text(message);
      })
      .always(function () {
        $('#submit-button').prop('disabled', false).text('Diagnose Error');
      });

How Does the Request Flow Work?

  • The url setting targets /api/debug.
  • The method setting sends a POST request.
  • The contentType setting identifies the outgoing body as application/json.
  • The JSON.stringify() call converts the form values into the request body.
  • The .done() callback places a successful diagnosis into the result panel.
  • The .fail() callback places a request error into the status region.
  • The .always() callback restores the submit button after either outcome.
  • Save public/app.js.
Test the request path

The handler is ready to make a real request. The response will tell you whether Express has a matching route.

Before you submit, do you think the browser will receive a diagnosis or a server error?

  • Return to the browser page at http://localhost:3000.
  • Refresh the page.
  • Enter ReferenceError: total is not defined in the error field.
  • Leave the optional code field empty.
  • Click Diagnose Error.

You should see Request failed with status 404. in the status region. The button should return to Diagnose Error.

That intended 404 is a real milestone because your request reached Express. The missing route is now the exact gap to fix.

Not Seeing the 404 Status?

A page reload means the submit handler did not take control. Confirm that event.preventDefault() remains inside the handler.

A status message that stays on the loading text means the failure callback did not run. Confirm that .fail() follows the .done() callback.

Help me debug why the form does not display the expected 404 response.

✔️ Awesome, I've got everything!

Your request code is complete. Double check that public/app.js is saved.

ⓧ I'd like to double check the full code

  • Compare your complete public/app.js file with this reference:
$(function () {
  $('#debug-form').on('submit', function (event) {
    event.preventDefault();

    const errorMessage = $('#error-message').val().trim();
    const code = $('#code').val().trim();

    if (!errorMessage) {
      $('#status').text('Please enter an error message.');
      return;
    }

    $('#submit-button').prop('disabled', true).text('Diagnosing...');
    $('#status').text('Sending the error to your Express API...');
    $('#result').prop('hidden', true);
    $('#diagnosis').text('');

    $.ajax({
      url: '/api/debug',
      method: 'POST',
      contentType: 'application/json',
      dataType: 'json',
      data: JSON.stringify({ errorMessage, code }),
    })
      .done(function (response) {
        $('#diagnosis').text(response.diagnosis);
        $('#result').prop('hidden', false);
        $('#status').text('Diagnosis ready.');
      })
      .fail(function (xhr) {
        const message =
          xhr.responseJSON?.error || `Request failed with status ${xhr.status}.`;
        $('#status').text(message);
      })
      .always(function () {
        $('#submit-button').prop('disabled', false).text('Diagnose Error');
      });
  });
});

This reference combines the submit handler with every request callback in the required order.

Your browser-to-server request path is proven. Next, you will add the Express route that turns the visible 404 into a validated diagnosis.

Add the Express Diagnosis Route

Your jQuery form reached the server in the previous step. The visible 404 confirmed that Express had no matching /api/debug route.

The new route lets Express parse JSON before it checks errorMessage. A valid request receives a fixed diagnosis that completes the browser-to-server loop.

In this step, get ready to:
  • Parse incoming JSON request bodies.
  • Reject missing error messages with a JSON 400 response.
  • Return a fixed diagnosis for valid requests.
Add the JSON diagnosis route

Express middleware prepares a request before the route handles it. The JSON middleware places parsed browser data in req.body with a 20kb limit.

  • In Visual Studio Code from earlier, select server.js in the Explorer sidebar.
  • Replace the entire contents of server.js with the code below:
import express from 'express';

const app = express();
const port = 3000;

app.use(express.json({ limit: '20kb' }));
app.use(express.static('public'));

app.post('/api/debug', (req, res) => {
  const errorMessage =
    typeof req.body?.errorMessage === 'string'
      ? req.body.errorMessage.trim()
      : '';

  if (!errorMessage) {
    return res.status(400).json({
      error: 'Please enter an error message.',
    });
  }

  return res.json({
    diagnosis: 'WHAT IT MEANS\nThe application tried to use a value that is not available.\n\nLIKELY CAUSE\nThe variable may not have been declared or is outside the current scope.\n\nTHREE CHECKS\n1. Check the variable spelling.\n2. Confirm it is declared before use.\n3. Check the scope.\n\nMISSING CONTEXT\nReview the surrounding code and full stack trace.',
  });
});

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

How does the route close the gap?

  • The express.json({ limit: '20kb' }) middleware parses the JSON payload before the route runs.
  • The 20kb limit caps the accepted request-body size.
  • The type check accepts errorMessage only when the browser sends a string.
  • The if (!errorMessage) block returns a JSON 400 response when the field is empty.
  • The final response sends the fixed diagnosis back under the diagnosis key.
  • Save server.js.
  • Switch to the terminal that is running the local app.
  • Press Ctrl+C to stop the old server process.
  • Restart the local app by running:
npm start

What does the start command do?

The start script uses Node.js to load your local .env file. It starts the updated server.js application.

Your terminal should show AI Debug Coach is running at http://localhost:3000.

Server not restarting?

  • Check that every bracket in server.js matches the reference below.
  • Confirm that the previous server process stopped before restarting the app.

Help me debug why the updated Express server will not start.

✔️ Awesome, I've got everything!

Your saved server.js now parses JSON input and answers valid diagnosis requests.

ⓧ I'd like to double check the full code

  • Compare your saved server.js with the complete file below.
import express from 'express';

const app = express();
const port = 3000;

app.use(express.json({ limit: '20kb' }));
app.use(express.static('public'));

app.post('/api/debug', (req, res) => {
  const errorMessage =
    typeof req.body?.errorMessage === 'string'
      ? req.body.errorMessage.trim()
      : '';

  if (!errorMessage) {
    return res.status(400).json({
      error: 'Please enter an error message.',
    });
  }

  return res.json({
    diagnosis: 'WHAT IT MEANS\nThe application tried to use a value that is not available.\n\nLIKELY CAUSE\nThe variable may not have been declared or is outside the current scope.\n\nTHREE CHECKS\n1. Check the variable spelling.\n2. Confirm it is declared before use.\n3. Check the scope.\n\nMISSING CONTEXT\nReview the surrounding code and full stack trace.',
  });
});

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

What should match?

This reference contains the JSON middleware before the static-file middleware. It also contains the complete validation and mock response inside POST /api/debug.

Test the valid request flow

The fixed diagnosis gives the browser a successful JSON response. This proves the frontend can complete a request through the server.

  • Before you submit the form, predict what will replace the former 404 message.
  • Switch back to the browser tab at http://localhost:3000.
  • Refresh the page.
  • Enter ReferenceError: total is not defined in the error field.
  • Click Diagnose Error.

You should see Diagnosis ready. in the status region. The result panel begins with WHAT IT MEANS.

You closed the missing-route gap. Your jQuery frontend now receives a successful response from Express.

Expose the mock response limitation

One successful request proves that the endpoint works. A second error checks whether the diagnosis adapts to the request.

  • Before you submit again, predict whether the diagnosis will change when the error changes.
  • Replace the error field contents with a different development error you have encountered.
  • Click Diagnose Error.

You will see the same diagnosis with the same four sections. This is the intended shortfall.

The route validates the input. Its response text is hard-coded.

Your browser-to-server request cycle now works. Next, you will replace the fixed response with a diagnosis that adapts to each error.

Generate AI Diagnoses and Deploy

Your jQuery frontend can now send a JSON request to Express. The route answers each valid request with the same diagnosis.

A fixed response cannot adapt to different errors. In this step, you will connect the route to Vercel AI Gateway for tailored diagnoses. You will then deploy the complete request flow to a public URL.

In this step, get ready to:
  • Create an AI Gateway API key for local development.
  • Replace the fixed diagnosis with a server-side AI request.
  • Deploy the working application to Vercel.
Create and protect your Gateway key

Local AI Gateway requests need an API key. Your Express server reads this credential from the existing .env file.

Adding a payment method can feel risky. The selected model has zero model-token pricing. This project does not ask you to purchase credits.

  • Sign in to your Vercel dashboard.
  • Select your team from the team switcher.
  • Open Settings from the sidebar.
  • Select Billing from the left navigation.
  • Locate the Payment Method area.

Choose the tab that matches what you see in the Payment Method area.

✔️ A payment method is saved

Your team meets the payment-method requirement for free AI Gateway Credits. Continue without changing the saved payment method.

ⓧ No payment method is saved

  • Click Add new card.
  • Enter valid credit or debit card details.
  • Save the payment method using the dialog's confirmation control.

The Payment Method area should now show that your team has a saved card.

  • Leave credit purchases unchanged.
  • Leave auto top-up disabled.
  • Open the AI Gateway API Keys page.
  • Click Create key.
  • Enter AI Debug Coach local in the name field.
  • Click Create key to generate the credential.

The one-time key reveal is easy to rush.

  • Copy the generated key without sharing it.
  • Switch back to the existing .env file in Visual Studio Code.
  • Replace your-api-key-here with the copied key.
  • Save .env.

Why does the key stay local?

The existing .gitignore keeps .env out of version control. The existing .vercelignore keeps the same file out of the deployment bundle.

Only the server reads the credential. The browser receives the diagnosis without receiving the key.

Replace the mock response with AI

The Vercel AI SDK can send a prompt to AI Gateway from your Express route. The route must remain responsible for validation. It must also return a safe response when the Gateway request fails.

  • Select server.js in the Visual Studio Code Explorer sidebar.
  • Replace everything from the first line through the existing errorMessage extraction with this updated route opening:
import express from 'express';
import { generateText } from 'ai';

const app = express();
const port = 3000;

app.use(express.json({ limit: '20kb' }));
app.use(express.static('public'));

app.post('/api/debug', async (req, res) => {
  const errorMessage =
    typeof req.body?.errorMessage === 'string'
      ? req.body.errorMessage.trim()
      : '';
  const code =
    typeof req.body?.code === 'string' ? req.body.code.trim() : '';

What changed in the route opening?

  • The generateText import gives the server access to AI SDK text generation.
  • The async route can wait for the model response.
  • The code value safely captures the optional code field as a trimmed string.
  • Find the fixed response that begins with return res.json({.
  • Replace that complete response with this AI request and error handler:
  try {
    const { text } = await generateText({
      model: 'inclusionai/ling-3.1-flash',
      instructions:
        'You are a careful debugging coach. Explain errors in beginner-friendly language. Do not claim certainty when context is missing. Return plain text with exactly these headings: WHAT IT MEANS, LIKELY CAUSE, THREE CHECKS, and MISSING CONTEXT.',
      prompt: `USER ERROR:\n${errorMessage}\n\nUSER CODE:\n${code || 'Not provided'}`,
    });

    return res.json({ diagnosis: text });
  } catch (error) {
    console.error('AI Gateway request failed:', error);
    return res.status(500).json({
      error: 'The AI diagnosis failed. Check your Gateway access and try again.',
    });
  }
});

How does the AI diagnosis work?

  • The model value selects inclusionai/ling-3.1-flash.
  • The instructions value requires four predictable diagnosis sections.
  • The prompt value supplies the submitted error.
  • The same prompt supplies the optional code or Not provided.
  • The catch block logs the server-side failure.
  • The browser receives a safe 500 response without internal details.

✔️ I've updated server.js

Save the file after comparing both edited sections with the snippets above.

ⓧ I'd like to double check the full code

import express from 'express';
import { generateText } from 'ai';

const app = express();
const port = 3000;

app.use(express.json({ limit: '20kb' }));
app.use(express.static('public'));

app.post('/api/debug', async (req, res) => {
  const errorMessage =
    typeof req.body?.errorMessage === 'string'
      ? req.body.errorMessage.trim()
      : '';
  const code =
    typeof req.body?.code === 'string' ? req.body.code.trim() : '';

  if (!errorMessage) {
    return res.status(400).json({
      error: 'Please enter an error message.',
    });
  }

  try {
    const { text } = await generateText({
      model: 'inclusionai/ling-3.1-flash',
      instructions:
        'You are a careful debugging coach. Explain errors in beginner-friendly language. Do not claim certainty when context is missing. Return plain text with exactly these headings: WHAT IT MEANS, LIKELY CAUSE, THREE CHECKS, and MISSING CONTEXT.',
      prompt: `USER ERROR:\n${errorMessage}\n\nUSER CODE:\n${code || 'Not provided'}`,
    });

    return res.json({ diagnosis: text });
  } catch (error) {
    console.error('AI Gateway request failed:', error);
    return res.status(500).json({
      error: 'The AI diagnosis failed. Check your Gateway access and try again.',
    });
  }
});

app.listen(port, () => {
  console.log(`AI Debug Coach is running at http://localhost:${port}`);
});

What should the full file contain?

The complete file preserves the existing JSON middleware. It also preserves static file serving and input validation.

The fixed response is now replaced by one model call with a safe failure path.

  • Save server.js.
  • Switch back to the PowerShell terminal running the local server.
  • Stop the server by pressing Ctrl+C.
  • Restart the local application by running:
npm start

What happens when the server restarts?

The existing start script loads variables from .env before Node runs server.js.

The AI SDK reads AI_GATEWAY_API_KEY automatically. Your application code never passes the secret to the browser.

Before you submit the first error, do you expect the diagnosis to contain the same fixed wording as before?

  • Return to http://localhost:3000 in your browser.
  • Enter ReferenceError: total is not defined in the Error message field.
  • Click Diagnose Error.

You should see a generated diagnosis with WHAT IT MEANS, LIKELY CAUSE, THREE CHECKS, and MISSING CONTEXT sections.

  • Replace the error with TypeError: obj.map is not a function.
  • Click Diagnose Error again.

You should see a different explanation and a different set of checks. The route now adapts its diagnosis to the submitted error.

Seeing the safe AI failure message?

  • Confirm the copied key replaced your-api-key-here in .env.
  • Confirm .env is saved inside the ai-debug-coach folder.
  • Restart the server after correcting the local key.

Ask for help with the local request without sharing your key: help me diagnose why my Express AI Gateway request returns the safe 500 response

Deploy the complete application

Your local request now works. A production deployment on Vercel needs secure access to the same Gateway without uploading your local key.

Why OIDC here?

Vercel deployments receive an OIDC token through VERCEL_OIDC_TOKEN. AI Gateway can use that deployment identity without a long-lived API key.

Your existing .vercelignore excludes .env from the upload. The production deployment authenticates without exposing the local credential.

  • Click Terminal in the Visual Studio Code top menu.
  • Click New Terminal to create a second PowerShell terminal.
  • Confirm the new terminal is inside the ai-debug-coach folder.

The CLI may open a browser authentication flow. It also asks how to link this folder to a Vercel project.

  • Complete the browser sign-in if the CLI requests authentication.
  • Select your payment-enabled team when the CLI asks Which team?.
  • Choose No when the CLI asks Link to existing project?.
  • Accept ai-debug-coach when the CLI asks Name?.
  • Choose No when the CLI asks Customize settings?.
  • Create the production deployment by running:
npm run deploy

What does the deploy script do?

The deploy script runs the pinned Vercel CLI with its production option. The CLI links the local folder to the new project.

Expect the first deployment to take a few minutes while Vercel uploads the files and builds the application. The terminal prints a production URL when the deployment succeeds.

  • Record the production URL printed by Vercel: https://ai-debug-coach.vercel.app.
  • Open https://ai-debug-coach.vercel.app in your browser.

You should see the same AI Debug Coach form from your local application. This confirms the frontend and Express application reached production.

Before you submit the production test, do you expect the deployed route to work without the local .env file?

  • Enter ReferenceError: total is not defined in the Error message field.
  • Click Diagnose Error.

You should see a tailored diagnosis with all four labeled sections. This proves the public jQuery form reached Express. It also proves the deployed server authenticated with AI Gateway.

You made the complete request path work in production. Your browser can now turn a real error into an actionable diagnosis from a public URL.

Production diagnosis not loading?

  • Confirm the terminal reported a successful production deployment.
  • Confirm the opened URL matches the production URL from the terminal.
  • Retry the request after a short wait if the free model is temporarily rate limited.
  • Inspect the deployment's request logs if the browser shows the safe AI failure message.

Get help without sharing credentials: help me debug why my deployed Express route cannot return an AI Gateway diagnosis

Secret mission

Add a Programming Language Selector

Error messages can mean different things across programming languages. Add a language selector that carries structured context from the browser to the AI prompt. Then redeploy the coach and verify a Python-specific diagnosis.

Clean Up Your Resources

Clean Up Your Resources

Your AI Debug Coach currently uses a free model, so its requests have no model-token charge. Choose whether to keep the Vercel project active, pause public access, or remove the resources.

Cost warning

Billing controls can feel risky.

Vercel requires a valid payment method for free Vercel AI Gateway Credits. The inclusionai/ling-3.1-flash model is currently marked free. Free-tier requests have lower per-model rate limits.

  • Leave purchased credits and auto top-up disabled unless you intend to move to paid usage.

Resources you used:

  • The ai-debug-coach project folder, including its protected .env file.
  • The AI Gateway API key created for local development.
  • The Vercel project that owns the public production deployment.

Keep everything running

No action needed. Choose this if you want to keep using the public AI Debug Coach.

  • Keep the Vercel project active so the public URL remains available.
  • Keep the AI Gateway API key active for local requests.
  • Keep the .env file private.

Pause - I'll come back to this later

Pause public access while preserving the Vercel project. Your local files remain available for future development.

  • Stop the local development server if it is still running.
  • Return to the Vercel project from earlier.
  • Select Settings.
  • Select General.
  • Select Pause Project.

Visitors will receive a paused-deployment error. Public access returns when you use Resume Project from the same page.

Your ai-debug-coach folder remains on your computer. Its .env file stays private.

Delete - I don't want to use this again

This is the irreversible option, so each resource is handled separately to keep the process clear.

  • Return to the Vercel project from earlier.
  • Select Settings.
  • Select General.
  • Select Delete Project.
  • Enter the project name shown in the confirmation prompt.
  • Select Delete.
  • Select Continue.

Your public URL now stops serving the AI Debug Coach. The production deployment is removed with the project.

The local .env copy remains separate from the remote key. Revoking the remote credential prevents future local AI requests from using it.

  • Return to the AI Gateway API key page from earlier.
  • Use the key's revoke control for the API key created in this project.
  • Confirm the key no longer appears as active.

The revoked key can no longer authenticate local AI requests.

Deleting the local folder removes the protected .env file with the project source.

  • Copy any source files you want to keep to a separate location.
  • Locate the ai-debug-coach folder from earlier in File Explorer.
  • Delete the ai-debug-coach folder.
  • Empty the Recycle Bin to remove the folder permanently.
  • Search File Explorer for ai-debug-coach.

You should no longer see the ai-debug-coach folder in the search results.

Nice Work!

Nice Work!

You did it! Your deployed AI Debug Coach now turns browser submissions into language-aware diagnoses through jQuery, Express, and Vercel AI Gateway.

You've learned how to:

  • Build a responsive jQuery interface that accepts an error message with optional code. Send that input as JSON through an AJAX request flow with visible request states.
  • Prove the missing /api/debug endpoint with a real 404 response. Fix that obstacle with a validated Express route that checks browser input before returning a diagnosis.
  • Replace the mock response with a server-side AI diagnosis that adapts to each error. Deploy the app to a public Vercel URL without exposing the local API key.
  • Complete the Secret Mission by extending the HTML form with a programming language selector. Carry that language context through jQuery and Express to produce Python-specific debugging guidance.

Ready to quiz yourself?