Build an AI Helpdesk Agent Foundation

Create a secure, provider-agnostic monorepo for an AI helpdesk agent.

Introduction

30 Second Summary

Long-running software projects become hard to trust when files have no clear home. Early shortcuts can also force every new session to repeat the same setup work.

In this project, you will create the permanent monorepo foundation for a provider-agnostic Enterprise IT Helpdesk AI Agent. The finished foundation gives every future capability a stable home without choosing an LLM provider.

What You'll Build

You can open the finished repository in Visual Studio Code to show where every future helpdesk capability belongs before handing the project into Part 2.

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

  • A permanent monorepo where you can see stable homes for the frontend, backend, retrieval, tools, audit, infrastructure, tests, and mock data.
  • A provider-neutral architecture whose safe configuration template keeps provider decisions open without exposing the real .env file.
  • A synchronized private GitHub repository with two traceable Part 1 commits. Its handoff report gives the next session an exact starting point.
  • Secret Mission: Create an evidence-based rubric that scores future online, offline, or hybrid model providers without choosing a winner.

Are there any prerequisites?

You need a 64-bit Windows 10 or Windows 11 device with internet access. Bring a confirmed GitHub account. Administrator access is only needed if local policy blocks an installer.

Before We Start

Before any hands-on work begins, this checkpoint commits you to building a provider-agnostic Enterprise IT Helpdesk AI Agent. It also fixes Part 1's scope at architecture, environment, repository, documentation, and handoff foundations.

Set Up VS Code and Git

Your enterprise agent will grow inside one repository across twelve parts. That long-lived workspace needs a dependable editor.

Reliable history depends on a working Git for Windows client. Each commit also needs a clear author identity.

This step verifies Visual Studio Code through Windows PowerShell. You will keep the real outputs for the Part 1 handoff.

In this step, get ready to:
  • Install or verify Visual Studio Code from a fresh PowerShell terminal.
  • Install or verify Git for Windows.
  • Configure your global Git author identity.
Verify Visual Studio Code

The code command proves that PowerShell can find your editor through PATH. Its output also gives you the real installed version for the handoff.

  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open a fresh PowerShell terminal.
  • Check the installed Visual Studio Code version by running this command:
code --version

What does this check do?

This check asks the Visual Studio Code command-line interface for its installed version. A successful result also proves that the editor is available through PATH in this fresh terminal.

✔️ I see version 1.144 or higher

Good progress. The editor command now works from a fresh terminal.

  • Record the complete output for your handoff here: your actual VS Code version output.

ⓧ I see an older version

The editor command works. Your installed release is older than the project baseline of 1.144.

  • Visit the official Visual Studio Code Windows setup page.
  • Choose the User Setup installer that matches your device architecture.
  • Run the downloaded VSCodeUserSetup-{version}.exe installer.
  • Keep PATH integration enabled in the installer.
  • Close the current PowerShell terminal after installation finishes.
  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open a fresh terminal.

The fresh terminal receives the updated PATH from the installer.

  • Verify the updated installation by running this command:
code --version

What should this confirm?

The command should now print the installed Visual Studio Code version. Its success confirms that the new terminal can locate the editor.

  • Record the complete output for your handoff here: your actual VS Code version output.

ⓧ Command not found

PowerShell cannot currently find the Visual Studio Code command. Installing the editor with PATH integration creates that connection.

  • Visit the official Visual Studio Code Windows setup page.
  • Choose the User Setup installer that matches your device architecture.
  • Run the downloaded VSCodeUserSetup-{version}.exe installer.
  • Keep PATH integration enabled in the installer.
  • Close the current PowerShell terminal after installation finishes.
  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open a fresh terminal.

The fresh terminal receives the PATH change made by the installer.

  • Verify the installation by running this command:
code --version

What should this confirm?

A version response proves that Visual Studio Code is installed. It also confirms that PowerShell can locate the editor command.

  • Record the complete output for your handoff here: your actual VS Code version output.

Still can't run the editor command?

  • Close every PowerShell terminal that was open before the installation.
  • Open a fresh PowerShell terminal through Windows search.
  • Rerun the Visual Studio Code installer if PATH integration was disabled.

Still stuck? Help me troubleshoot why PowerShell cannot find Visual Studio Code.

Verify Git for Windows

Git records every future architecture change in a traceable history. This check confirms that its command-line client is available before the repository exists.

  • Switch back to the fresh PowerShell terminal from the previous check.
  • Check the installed Git version by running this command:
git --version

What does this check do?

This command asks Git for its installed version. A successful response proves that the current terminal can find Git through PATH.

✔️ I see version 2.56.0(4) or higher

That is another foundation piece working. Git is ready to track the repository you create later.

  • Record the complete output for your handoff here: your actual Git version output.

ⓧ I see an older version

Git is available through PATH. Your installed release is older than the project baseline of 2.56.0(4).

  • Visit the official Git for Windows installation page.
  • Download the current installer for your Windows device.
  • Run the downloaded installer.
  • Complete the installer with its default options.
  • Close the current PowerShell terminal after installation finishes.
  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open a fresh terminal.
  • Verify the updated installation by running this command:
git --version

What should this confirm?

The command should print the updated Git version. Its success also proves that the fresh terminal received the installer changes.

  • Record the complete output for your handoff here: your actual Git version output.

ⓧ Command not found

Git is missing from PATH in this terminal. The vendor-documented WinGet command installs Git for Windows from PowerShell.

Windows may request permission during installation. Approve that request so the installer can continue.

  • Install Git for Windows by running this command:
winget install --id Git.Git -e --source winget

What does this command do?

WinGet locates the package identified as Git for Windows. The exact-match option prevents it from selecting a similarly named package.

  • Close the current PowerShell terminal after installation finishes.
  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open a fresh terminal.
  • Verify the installation by running this command:
git --version

What should this confirm?

A version response confirms that Git for Windows is installed. It also proves that the fresh terminal can locate the Git command.

  • Record the complete output for your handoff here: your actual Git version output.

Still can't run Git?

  • Close every PowerShell terminal that was open before Git was installed.
  • Open a fresh PowerShell terminal through Windows search.
  • Use the official Git for Windows installer if WinGet is blocked by local machine policy.

Need a hand? Help me troubleshoot my Git for Windows installation.

Configure your Git identity

Git stores an author name plus an email on every commit. Use the identity connected to your GitHub account so your future history is attributed correctly.

Your GitHub-linked email can be your account email or your GitHub no-reply email. Both options keep your local commits tied to the intended account.

  • Record the author name you want attached to commits here: your Git author name.
  • Set your global author name by replacing YOUR NAME before running this command:
git config --global user.name "YOUR NAME"

What does this setting control?

The global setting supplies the author name for repositories on this Windows account. A repository can override it later when a different identity is required.

  • Read back the stored author name by running this command:
git config --global user.name

What should this show?

PowerShell should print the author name you entered. A non-blank result confirms that Git saved the global value.

  • Correct the author name now if the readback contains a typo.
  • Record the GitHub-linked email you want attached to commits here: your Git author email.
  • Set your global author email by replacing YOUR_GITHUB_EMAIL before running this command:
git config --global user.email "YOUR_GITHUB_EMAIL"

What does this setting control?

This global setting supplies the email metadata for future commits. Using a GitHub-linked value allows GitHub to associate those commits with your account.

  • Read back the stored author email by running this command:
git config --global user.email

What should this show?

PowerShell should print the email you entered. A non-blank result confirms that Git saved the global value.

Identity readback is blank?

  • Rerun the matching configuration command with the placeholder replaced.
  • Keep the quotation marks around a name that contains spaces.
  • Check the email for typing mistakes before saving it again.

Still seeing a blank value? Help me troubleshoot my global Git identity.

Before you run the final checks, do you expect every command to print a value in this brand-new terminal?

  • Close the current PowerShell terminal.
  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open a fresh PowerShell terminal.
  • Verify the Visual Studio Code command in the fresh terminal by running:
code --version

Visual Studio Code check

You should see the actual installed Visual Studio Code version. This confirms that the editor remains available in a brand-new terminal.

  • Verify the Git command in the same terminal by running:
git --version

Git check

You should see the actual installed Git version. This confirms that Git remains available through PATH.

  • Verify the stored Git author name by running:
git config --global user.name

Author name check

You should see the configured author name. The value must contain text before you continue.

  • Verify the stored Git author email by running:
git config --global user.email

Author email check

You should see the configured GitHub-linked email. The value must contain text before you continue.

That is the foundation in place. Your editor works from PowerShell. Git can now attribute every future commit to you.

Your Windows editor plus source-control identity are ready. Next, you will verify the development runtimes that future parts depend on.

Set Up the Development Runtimes

Your editor and Git identity are ready. The same fresh Windows PowerShell workflow can now verify the runtimes that future parts depend on.

A known Python and Node.js baseline prevents later sessions from using accidental runtime versions. Recording WSL readiness now also prevents a restart-heavy Docker detour when containers become relevant.

In this step, get ready to:
  • Install or verify Python 3.14.
  • Install or verify Node.js LTS and npm.
  • Record WSL and Windows readiness without installing Docker.
Install or verify Python 3.14

Python powers the backend work planned for later parts. This session only establishes the 3.14 runtime.

The Python Install Manager keeps installed runtimes visible through the py command. You will inspect that inventory before deciding whether an installation is needed.

  • Check the installed Python runtimes by running this command:
py list

What Does This Command Show?

The command lists the Python runtimes that the Python Install Manager can discover. Look for a runtime in the 3.14 series.

✔️ The required Python runtime is listed

The required runtime is already available. Verify the exact selected version before continuing.

Before you run the selection check, decide which Python version you expect the launcher to report.

  • Verify the selected Python runtime by running this command:
py -V:3.14 --version

What Does This Command Verify?

The version selector asks the launcher for the installed 3.14 runtime. This proves that future commands can target the intended Python series.

You should see a Python version in the 3.14.x series.

  • Record the complete output for the handoff: your Python 3.14 version output.

Python Selection Failed?

Confirm that the inventory listed a 3.14 runtime. A different installed Python series does not satisfy this selection.

Need help interpreting the launcher output? Help me troubleshoot my Python 3.14 runtime selection.

ⓧ The required runtime is absent

The launcher works, but its inventory does not contain the required Python runtime. Install the official manager before adding the runtime so the Windows launcher can discover it consistently.

  • Install the Python Install Manager by running this command:
winget install 9NQ7512CXL7T -e --accept-package-agreements --disable-interactivity

What Does This Command Install?

WinGet installs the official Python Install Manager package. The included options select the exact package and accept its package agreements without launching an interactive installer.

Install Command Failed?

A local machine policy can block WinGet or software installation. Keep the full command output so the restriction can be diagnosed.

Need help with the installation output? Help me troubleshoot the Python Install Manager installation.

  • Close the current PowerShell window.
  • Press the Windows key to open Windows search.
  • Type PowerShell and press Enter to open a fresh terminal.
  • Install the Python 3.14 runtime by running this command:
py install 3.14

What Does This Command Install?

The Python Install Manager downloads the current PythonCore runtime in the 3.14 series. It does not create a project environment or install any packages.

Runtime Download Failed?

Confirm that the fresh terminal recognizes the py command. Network filtering can also interrupt the runtime download.

Need help with the runtime installation? Help me troubleshoot py install 3.14.

Before you verify the installation, decide which Python version you expect the launcher to select.

  • Verify the installed runtime by running this command:
py -V:3.14 --version

What Does This Command Verify?

The launcher selects the installed 3.14 runtime and prints its complete version. This confirms that the installation is discoverable from a fresh terminal.

You should see a Python version in the 3.14.x series.

  • Record the complete output for the handoff: your Python 3.14 version output.

ⓧ The py command is unavailable

Windows cannot find the Python launcher yet. Install the official Python Install Manager before adding the required runtime.

  • Install the Python Install Manager by running this command:
winget install 9NQ7512CXL7T -e --accept-package-agreements --disable-interactivity

What Does This Command Install?

WinGet installs the official Python Install Manager package. A fresh terminal can then discover its py command.

Install Command Failed?

A local machine policy can block WinGet or software installation. Preserve the complete output so the failure can be diagnosed accurately.

Need help with the installation output? Help me troubleshoot the missing Python launcher.

  • Close the current PowerShell window.
  • Press the Windows key to open Windows search.
  • Type PowerShell and press Enter to open a fresh terminal.
  • Install the Python 3.14 runtime by running this command:
py install 3.14

What Does This Command Install?

The manager downloads the current PythonCore runtime in the 3.14 series. No virtual environment or project dependency is created.

Runtime Download Failed?

Check whether the fresh terminal now recognizes the py command. Network filtering can also stop the runtime download.

Need help with the download? Help me troubleshoot the Python 3.14 runtime installation.

Before you verify the installation, decide which Python version you expect the new launcher to report.

  • Verify the installed runtime by running this command:
py -V:3.14 --version

What Does This Command Verify?

The version selector targets the installed 3.14 runtime. Its output proves that the new launcher and runtime are available together.

You should see a Python version in the 3.14.x series.

  • Record the complete output for the handoff: your Python 3.14 version output.

That establishes the first runtime baseline. Python 3.14 is now selectable without adding project packages or a virtual environment.

Install or verify Node.js and npm

Node.js supplies the JavaScript runtime for the future frontend. Its installer also provides npm for managing frontend packages in a later part.

This step verifies Node.js v26.13.0 LTS with npm 11.20.0. It does not scaffold React or install global frontend packages.

  • Check the installed Node.js version by running this command:
node --version

What Does This Command Show?

The command prints the Node.js runtime available on the current PATH. Compare the output with the required LTS release before continuing.

✔️ I see the required LTS release

Node.js already reports the required LTS version. Record that output before checking the separately bundled npm command.

  • Record the complete Node.js output for the handoff: your Node.js version output.
  • Check the npm version by running this command:
npm --version

What Does This Command Verify?

The command confirms that the npm executable bundled with Node.js is available from the same terminal. The selected Node.js release publishes npm 11.20.0.

You should see npm 11.20.0.

  • Record the complete npm output for the handoff: your npm version output.

npm Is Unavailable?

Close the current terminal after confirming that Node.js is installed. Open a fresh PowerShell terminal so it reloads the updated PATH.

Still missing npm? Help me troubleshoot npm after verifying Node.js.

ⓧ I see a different Node.js version

The current runtime does not match the selected LTS baseline. Use the installer that matches the architecture reported by Windows.

  • Press the Windows key to open Windows search.
  • Type Settings and press Enter to open Windows Settings.
  • Select System.
  • Select About.
  • Read the displayed system type.
  • Record the value here: your Windows system type.
  • Open the official Node.js v26.13.0 release page.
  • Download node-v26.13.0-x64.msi if Windows reports an x64 system.
  • Download node-v26.13.0-arm64.msi if Windows reports an ARM64 system.
  • Run the downloaded installer.
  • Complete the installer using its default runtime features.

The installer completion screen confirms that the runtime has been updated.

  • Close every open PowerShell window.
  • Press the Windows key to open Windows search.
  • Type PowerShell and press Enter to open a fresh terminal.
  • Verify Node.js by running this command:
node --version

What Does This Command Verify?

The fresh terminal reloads the PATH created by the installer. The command should now resolve the selected Node.js LTS runtime.

You should see v26.13.0.

  • Record the complete Node.js output for the handoff: your Node.js version output.
  • Verify npm separately by running this command:
npm --version

What Does This Command Verify?

The npm check confirms that the package manager bundled with the selected Node.js release is available. This keeps the frontend runtime baseline complete.

You should see npm 11.20.0.

  • Record the complete npm output for the handoff: your npm version output.

Version Did Not Update?

Confirm that you downloaded the installer matching the Windows system type. Make sure the verification runs in a terminal opened after the installer finished.

Need help with the runtime update? Help me troubleshoot my Node.js and npm versions.

ⓧ The node command is unavailable

Node.js is not available on the current PATH. Install the selected LTS release using the installer that matches the architecture reported by Windows.

  • Press the Windows key to open Windows search.
  • Type Settings and press Enter to open Windows Settings.
  • Select System.
  • Select About.
  • Read the displayed system type.
  • Record the value here: your Windows system type.
  • Open the official Node.js v26.13.0 release page.
  • Download node-v26.13.0-x64.msi if Windows reports an x64 system.
  • Download node-v26.13.0-arm64.msi if Windows reports an ARM64 system.
  • Run the downloaded installer.
  • Complete the installer using its default runtime features.

The installer completion screen confirms that Node.js and its bundled npm package manager have been added.

  • Close every open PowerShell window.
  • Press the Windows key to open Windows search.
  • Type PowerShell and press Enter to open a fresh terminal.
  • Verify Node.js by running this command:
node --version

What Does This Command Verify?

The fresh terminal loads the PATH entry created by the installer. The version output proves that Windows can now locate Node.js.

You should see v26.13.0.

  • Record the complete Node.js output for the handoff: your Node.js version output.
  • Verify npm separately by running this command:
npm --version

What Does This Command Verify?

The separate npm check confirms that the bundled package manager is also available on the PATH. No frontend package is installed by this command.

You should see npm 11.20.0.

  • Record the complete npm output for the handoff: your npm version output.

Commands Still Unavailable?

Confirm that the installer completed before the fresh terminal was opened. Check that the downloaded installer matches the recorded Windows system type.

Need help with the installation? Help me troubleshoot the Node.js LTS installation.

You now have both development runtimes available from PowerShell. Their actual outputs are captured for the Part 1 handoff.

Record Windows and WSL readiness

Windows Subsystem for Linux readiness affects a future Docker Desktop setup. This session records the current state without installing WSL or container software.

A successful version output and an exact error are both useful evidence. Either result gives the next container session a concrete starting point.

Before you run this check, decide whether the current machine is likely to return WSL version details or an error.

  • Check the current WSL state by running this command:
wsl --version

What Does This Check Prove?

The command reports installed WSL version details when WSL is available. If WSL is unavailable, its exact error records the missing prerequisite for a later session.

  • Record the complete result here: your WSL output or exact error.

Leave WSL As It Is

Do not install or repair WSL in this session. The recorded result is the intended outcome for Part 1.

Windows version and memory complete the readiness record. The Settings page provides both values without changing the device.

  • Press the Windows key to open Windows search.
  • Type Settings and press Enter to open Windows Settings.
  • Select System.
  • Select About.
  • Read the displayed Windows version.
  • Record the value here: your Windows version.
  • Read the displayed amount of installed RAM.
  • Record the value here: your installed RAM.

Record Only What You Know

Virtualization may already be enabled even if you have never checked it. Record unknown when you do not have a confirmed status.

  • Record the known virtualization status here: enabled, disabled, or unknown.

Run the Final Readiness Check

A fresh terminal proves that every runtime survives beyond the installer session. Run each check separately so the handoff can match every output to its command.

  • Close the current PowerShell window.
  • Press the Windows key to open Windows search.
  • Type PowerShell and press Enter to open a fresh terminal.

Before the final check, predict whether the three runtime commands will still print versions in this fresh terminal.

  • Verify Python 3.14 by running this command:
py -V:3.14 --version

What Should This Confirm?

The output should match the Python 3.14.x series you recorded earlier. This confirms that the selected runtime remains available in a new terminal.

  • Update the recorded value if the complete output changed: your Python 3.14 version output.
  • Verify Node.js by running this command:
node --version

What Should This Confirm?

The output should report the selected Node.js LTS release. This proves that the runtime is available from the fresh terminal PATH.

  • Update the recorded value if the complete output changed: your Node.js version output.
  • Verify npm by running this command:
npm --version

What Should This Confirm?

The output should report npm 11.20.0. This confirms that the Node.js package manager is also available.

  • Update the recorded value if the complete output changed: your npm version output.
  • Repeat the WSL readiness check by running this command:
wsl --version

How Should You Read This Result?

Version details confirm that WSL is present. An error remains a valid recorded result because WSL installation is deliberately deferred.

  • Update the recorded result if the complete output changed: your WSL output or exact error.

A Runtime Check Changed?

Compare the command with its earlier version exactly. Confirm that every installation completed before this fresh terminal was opened.

Need help reconciling the outputs? Help me troubleshoot my final runtime checks.

Strong finish. Your Windows machine now has a recorded Python and Node.js baseline plus an honest WSL readiness result.

Your runtime baseline is ready without adding project packages or container software. Next, you will create the permanent monorepo foundation for the enterprise helpdesk agent.

Create the Monorepo Foundation

Your Windows toolchain is ready for the first permanent project artifact. You also recorded runtime readiness without installing any project services.

A monorepo gives every future capability a stable home inside one Git repository. This step also tests whether local configuration is protected before the first commit.

In this step, get ready to:
  • Initialize the permanent repository on main.
  • Build the monorepo directory skeleton.
  • Add blank provider-neutral configuration boundaries.
Create and initialize the repository

The folder at $HOME\source\repos\enterprise-it-helpdesk-agent becomes the permanent workspace for Parts 1 through 12. Initializing it on main establishes the branch that later connects to GitHub.

  • Switch back to PowerShell from earlier.
  • Create the permanent repository folder by running this command:
New-Item -ItemType Directory -Force -Path "$HOME\source\repos\enterprise-it-helpdesk-agent"

What does this command do?

PowerShell creates the complete folder path under your home directory. The -Force option keeps an existing directory intact if you already created it.

  • Move PowerShell into the new repository folder by running this command:
Set-Location -Path "$HOME\source\repos\enterprise-it-helpdesk-agent"

Why change location?

PowerShell now treats enterprise-it-helpdesk-agent as the current directory. Every relative path in the rest of this step starts here.

  • Open the current folder in Visual Studio Code by running this command:
code .

What does the dot mean?

The dot represents the current directory. Visual Studio Code opens enterprise-it-helpdesk-agent as your workspace.

  • Initialize the current folder as an empty repository on main by running this command:
git init -b main

What did Git initialize?

Git creates its local repository metadata inside the current folder. The -b main option sets main as the initial branch.

  • Display PowerShell's current location by running this command:
Get-Location

What should the path show?

Your path should end with source\repos\enterprise-it-helpdesk-agent. This confirms that later files land in the permanent repository.

Before you check the repository, which branch do you expect Git to report?

  • Check the repository state by running this command:
git status -sb

What should Git report?

Git should report an empty repository on main. There are no commits or remote connections yet.

Your permanent workspace now exists. Visual Studio Code is displaying the same empty repository that PowerShell initialized on main.

Repository opened in the wrong folder?

  • Run Get-Location to confirm that the current path ends with enterprise-it-helpdesk-agent.
  • Run code . again after PowerShell displays the correct path.
  • Run git init -b main from the repository folder if Git does not recognize it.

Still stuck? Help me verify the repository folder and main branch.

Build the permanent directory skeleton

The skeleton assigns one responsibility to each branch of the repository. These boundaries let future sessions add interfaces or adapters without scattering files across arbitrary folders.

  • Create the permanent monorepo directories by running this command:
New-Item -ItemType Directory -Force -Path `
    "apps/frontend", `
    "apps/backend/app/api", `
    "apps/backend/app/core", `
    "apps/backend/app/llm/contracts", `
    "apps/backend/app/llm/providers", `
    "apps/backend/app/agent", `
    "apps/backend/app/rag", `
    "apps/backend/app/mcp", `
    "apps/backend/app/auth", `
    "apps/backend/app/tools", `
    "apps/backend/app/audit", `
    "apps/backend/tests", `
    "services/mcp-server", `
    "data/mock", `
    "data/knowledge", `
    "docs/architecture", `
    "docs/decisions", `
    "docs/handoffs", `
    "infra/docker", `
    "infra/cloud", `
    "scripts", `
    "tests/integration", `
    "tests/e2e"

How is the monorepo divided?

  • The apps/frontend branch reserves the future React interface.
  • The apps/backend branch reserves future FastAPI boundaries.
  • The llm/contracts branch holds stable interfaces for model capabilities.
  • The llm/providers branch isolates future provider adapters.
  • The rag branch reserves the future RAG pipeline.
  • The mcp branches reserve future MCP integration points.
  • The docs branch stores architecture decisions plus session handoffs.
  • The infra branch reserves deployment definitions without starting infrastructure.
  • Add empty .gitkeep files to the leaf directories by running this command:
New-Item -ItemType File -Force -Path `
    "apps/frontend/.gitkeep", `
    "apps/backend/app/api/.gitkeep", `
    "apps/backend/app/core/.gitkeep", `
    "apps/backend/app/llm/contracts/.gitkeep", `
    "apps/backend/app/llm/providers/.gitkeep", `
    "apps/backend/app/agent/.gitkeep", `
    "apps/backend/app/rag/.gitkeep", `
    "apps/backend/app/mcp/.gitkeep", `
    "apps/backend/app/auth/.gitkeep", `
    "apps/backend/app/tools/.gitkeep", `
    "apps/backend/app/audit/.gitkeep", `
    "apps/backend/tests/.gitkeep", `
    "services/mcp-server/.gitkeep", `
    "data/mock/.gitkeep", `
    "data/knowledge/.gitkeep", `
    "docs/architecture/.gitkeep", `
    "docs/decisions/.gitkeep", `
    "docs/handoffs/.gitkeep", `
    "infra/docker/.gitkeep", `
    "infra/cloud/.gitkeep", `
    "scripts/.gitkeep", `
    "tests/integration/.gitkeep", `
    "tests/e2e/.gitkeep"

Why add .gitkeep files?

Git records files instead of empty directories. Each .gitkeep file gives its otherwise-empty directory a trackable placeholder for the first commit.

Before you inspect the result, how many parts of the future application do you expect the untracked file list to reveal?

  • Display every untracked candidate by running this command:
git status --short --untracked-files=all

What should the structure check show?

Git should list .gitkeep files across the application, service, data, documentation, infrastructure, script, plus test boundaries. Each entry is untracked because the repository still has no commits.

Missing a directory placeholder?

  • Confirm that PowerShell still points to enterprise-it-helpdesk-agent.
  • Compare the missing path with the directory command above.
  • Run the relevant New-Item command again after correcting the path.

Need another pair of eyes? Help me find the missing monorepo path.

Add provider-neutral configuration

The configuration template defines ports for chat generation plus embeddings without selecting an implementation. It also reserves blank boundaries for persistence, vector storage, MCP, authentication, plus audit settings.

  • Return to Visual Studio Code from earlier.
  • Create .env.example at the top level of enterprise-it-helpdesk-agent using the new-file control in the left sidebar.
  • Paste the blank configuration template into .env.example from the code below:
# Chat generation boundary
CHAT_PROVIDER=
CHAT_MODEL=
CHAT_BASE_URL=
CHAT_API_KEY=

# Embedding boundary
EMBEDDING_PROVIDER=
EMBEDDING_MODEL=
EMBEDDING_BASE_URL=
EMBEDDING_API_KEY=

# Persistence boundary
DATABASE_URL=

# Vector store boundary
VECTOR_STORE_PROVIDER=
VECTOR_STORE_URL=

# MCP boundary
MCP_SERVER_URL=

# Authentication boundary
AUTH_PROVIDER=

# Audit boundary
AUDIT_LOG_LEVEL=

What does this template define?

  • The CHAT_ slots keep chat generation configurable.
  • The EMBEDDING_ slots keep embedding generation independently configurable.
  • The remaining slots reserve boundaries for future services.
  • Every value stays blank because Part 1 chooses no provider, model, URL, or key.
  • Save .env.example by pressing Ctrl+S.
  • Confirm that .env.example appears at the top level of the left file sidebar.

Template saved in the wrong folder?

  • Check that .env.example sits beside the top-level apps folder.
  • Move the file to the top level if it appears inside another directory.
  • Confirm that every value after the equals sign remains blank.

Need help checking the template? Help me verify my blank provider-neutral environment file.

Use these tabs to confirm that your saved template matches the required configuration contract.

✔️ Awesome, I've got everything!

Your .env.example file is saved with blank chat, embedding, persistence, vector store, MCP, authentication, plus audit boundaries.

ⓧ I'd like to double check the full code

Compare your complete .env.example file with this reference.

# Chat generation boundary
CHAT_PROVIDER=
CHAT_MODEL=
CHAT_BASE_URL=
CHAT_API_KEY=

# Embedding boundary
EMBEDDING_PROVIDER=
EMBEDDING_MODEL=
EMBEDDING_BASE_URL=
EMBEDDING_API_KEY=

# Persistence boundary
DATABASE_URL=

# Vector store boundary
VECTOR_STORE_PROVIDER=
VECTOR_STORE_URL=

# MCP boundary
MCP_SERVER_URL=

# Authentication boundary
AUTH_PROVIDER=

# Audit boundary
AUDIT_LOG_LEVEL=

The template is safe to share because its configuration values are blank. The local .env copy represents the file that could eventually hold machine-specific values.

  • Switch back to PowerShell from earlier.
  • Copy the blank template to a local .env file by running this command:
Copy-Item -LiteralPath ".env.example" -Destination ".env"

What did PowerShell copy?

PowerShell creates .env with the same blank boundaries as .env.example. The source template remains unchanged.

Before you run the final check, do you think Git currently treats the local configuration file as protected or untracked?

  • Reveal the repository's complete untracked state by running this command:
git status --short --untracked-files=all

The configuration exposure is visible

You should see ?? .env in the output. Git currently sees the local configuration file as an untracked candidate.

You should also see ?? .env.example plus the .gitkeep entries. The visible .env line proves that local values could enter a future commit without a protection rule.

Do not see .env in the status output?

  • Confirm that PowerShell still points to enterprise-it-helpdesk-agent.
  • Confirm that .env appears at the top level in Visual Studio Code.
  • Run the copy command again if only .env.example exists.

Still missing the line? Help me make Git detect the local .env file.

You caught the security gap before the first commit. The repository now has its permanent structure plus a provider-neutral template, while the local .env remains visibly exposed for the next step to secure.

Your monorepo foundation now gives every future capability a permanent home. Next, you will protect the local configuration before documenting the architecture contracts.

Secure and Document the Architecture

Your monorepo now has permanent folders. The deliberate ?? .env result proved that Git would offer local configuration for staging.

That risk must disappear before the first commit. Written contracts must also keep future provider SDKs away from agent logic.

In this step, get ready to:
  • Protect local configuration with a verified ignore policy.
  • Document the permanent system boundaries.
  • Prepare the Part 1 handoff for the next session.
Protect local configuration

The local .env file is designed to hold machine-specific configuration. An ignore policy keeps that file outside version control while preserving the safe template.

  • Use the file creation control above the editor's file tree to create .gitignore inside enterprise-it-helpdesk-agent.
  • Add the environment rules plus the Python rules by pasting this first section:
# Local environment files
.env
.env.*
!.env.example

# Python
.venv/
venv/
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.ruff_cache/

# Node
node_modules/
dist/
build/
.next/

What do these rules protect?

  • .env excludes the local configuration file.
  • .env.* excludes other machine-specific environment files.
  • !.env.example creates an exception for the safe template.
  • The remaining patterns exclude generated Python files plus generated Node.js files.
  • Save .gitignore.

Before you run the check, predict whether Git will name an ignore rule for .env.

  • Test the new rule from the existing PowerShell terminal by running this command:
git check-ignore -v .env

What does this check prove?

Git reports the matching file plus the matching pattern. This proves that the saved rule controls .env.

You should see output naming .gitignore as the source of the matching .env rule.

No matching rule appears?

  • Confirm that .gitignore is saved at the top level of enterprise-it-helpdesk-agent.
  • Confirm that the file contains a line with only .env.
  • Return to the terminal that is already inside the repository.

Still stuck? Help me find why Git is not ignoring my .env file..

The secret-bearing file is now protected. The rest of the policy removes generated files plus local machine data from future commits.

  • Place the cursor after .next/ in .gitignore.
  • Complete the ignore policy by pasting this section below that line:

# Coverage and test output
coverage/
htmlcov/
.coverage

# Editors and operating systems
.vscode/
.idea/
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Local data
*.db
*.sqlite*
data/local/
data/vector-store/

# Certificates and private keys
*.pem
*.key
*.p12
*.pfx

What does the complete policy cover?

  • Coverage patterns exclude generated test reports.
  • Editor patterns exclude machine-specific workspace settings.
  • Local data patterns exclude database files plus vector-store files.
  • Certificate patterns exclude common private key formats.
  • Save the completed .gitignore.
  • Check the untracked files against the new policy by running this command:
git status --short --untracked-files=all

What should Git show?

The output should omit .env. It should retain .env.example as an untracked candidate.

Good work. Git now hides the local .env while keeping the safe template available to future collaborators.

Is the status output wrong?

  • Add the leading ! to the .env.example exception if the template is missing.
  • Remove any spaces before the .env pattern if the local file remains visible.
  • Save .gitignore before repeating the status check.

Need another pair of eyes? Help me correct my .gitignore behavior..

✔️ Awesome, I've got everything!

Your saved .gitignore protects local configuration plus generated project data.

ⓧ I'd like to double check the full code

# Local environment files
.env
.env.*
!.env.example

# Python
.venv/
venv/
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.ruff_cache/

# Node
node_modules/
dist/
build/
.next/

# Coverage and test output
coverage/
htmlcov/
.coverage

# Editors and operating systems
.vscode/
.idea/
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Local data
*.db
*.sqlite*
data/local/
data/vector-store/

# Certificates and private keys
*.pem
*.key
*.p12
*.pfx
Write the architecture contracts

An LLM boundary defines what the application needs without selecting the software that fulfills it. The ports and adapters pattern confines replaceable integrations to dedicated modules.

Each Markdown document gives future sessions a durable rule to follow. The repository can grow without reopening Part 1 decisions.

  • Use the file creation control above the file tree to create README.md at the top level of enterprise-it-helpdesk-agent.
  • Fill README.md with the project overview by pasting this content:
# Enterprise IT Helpdesk AI Agent

This monorepo is the permanent engineering foundation for one enterprise application.
Part 1 establishes architecture, environment, repository, documentation, and handoff foundations.

## Permanent Boundaries

- `apps/frontend` holds the future React interface.
- `apps/backend` holds the future FastAPI service and tests.
- `services/mcp-server` holds the future MCP server.
- `data` separates mock data from knowledge content.
- `docs` stores architecture, decisions, and session handoffs.
- `infra` separates Docker assets from cloud assets.
- `scripts` holds repeatable engineering tasks.
- `tests` separates integration tests from end-to-end tests.

## Provider-Neutral Design

Chat generation and embeddings use separate ports.
Configuration selects adapters without exposing provider SDK objects to business layers.
No provider, model, base URL, or credential is selected in Part 1.

## Future Implementation Scope

Future parts add authentication and RBAC, PostgreSQL, RAG, vector storage, MCP, tools, audit, tests, Docker, CI/CD, and cloud deployment.
This foundation remains the source of truth through Parts 2 to 12.

What does the README establish?

  • The purpose identifies this repository as one continuous enterprise application.
  • The boundary list assigns a lasting responsibility to every top-level area.
  • The provider-neutral section keeps provider selection outside Part 1.
  • The future scope shows how later sessions extend this foundation.
  • Save README.md.
  • Confirm that the editor displays the project title plus four document sections.

Does the README look incomplete?

  • Confirm that the file is named README.md.
  • Confirm that it sits beside .env.example.
  • Compare every heading with the full reference below.

Need help comparing the sections? Help me review my project README..

✔️ Awesome, I've got everything!

Your README now explains the repository's purpose plus its permanent boundaries.

ⓧ I'd like to double check the full code

# Enterprise IT Helpdesk AI Agent

This monorepo is the permanent engineering foundation for one enterprise application.
Part 1 establishes architecture, environment, repository, documentation, and handoff foundations.

## Permanent Boundaries

- `apps/frontend` holds the future React interface.
- `apps/backend` holds the future FastAPI service and tests.
- `services/mcp-server` holds the future MCP server.
- `data` separates mock data from knowledge content.
- `docs` stores architecture, decisions, and session handoffs.
- `infra` separates Docker assets from cloud assets.
- `scripts` holds repeatable engineering tasks.
- `tests` separates integration tests from end-to-end tests.

## Provider-Neutral Design

Chat generation and embeddings use separate ports.
Configuration selects adapters without exposing provider SDK objects to business layers.
No provider, model, base URL, or credential is selected in Part 1.

## Future Implementation Scope

Future parts add authentication and RBAC, PostgreSQL, RAG, vector storage, MCP, tools, audit, tests, Docker, CI/CD, and cloud deployment.
This foundation remains the source of truth through Parts 2 to 12.

The system overview records the complete path a future helpdesk request follows. It also assigns ownership for policy checks plus durable storage.

  • Create system-overview.md inside the existing docs/architecture directory.
  • Document the future request path by pasting this content:
# System Overview

## Future Request Path

1. The React frontend sends an authenticated helpdesk request to FastAPI.
2. FastAPI validates the request and passes identity context to authentication and RBAC policy enforcement.
3. The agent loop plans work through provider-neutral chat-generation contracts.
4. The RAG layer retrieves approved knowledge through an embedding port and vector database boundary.
5. The MCP host creates clients for approved MCP servers and exposes allowed capabilities to the agent.
6. Tool approval checks authorize each proposed action before tool execution.
7. Audit components record requests, decisions, retrieval, approvals, tool activity, and outcomes.
8. PostgreSQL stores durable application state while the vector database stores searchable knowledge representations.
9. FastAPI returns the policy-approved response to the React frontend.

## Permanent Boundaries

- `apps/frontend` owns presentation and browser interaction.
- `apps/backend/app/api` owns HTTP endpoints and transport models.
- `apps/backend/app/auth` owns authentication and RBAC policy.
- `apps/backend/app/agent` owns orchestration and the agent loop.
- `apps/backend/app/rag` owns retrieval workflows.
- `apps/backend/app/mcp` owns MCP host and client integration.
- `apps/backend/app/tools` owns approval and tool execution.
- `apps/backend/app/audit` owns audit events.
- `apps/backend/tests`, `tests/integration`, and `tests/e2e` own test layers.
- `infra/docker` and `infra/cloud` own deployment definitions.

## Delivery Boundaries

Docker supports reproducible local services.
CI/CD validates changes before cloud deployment.
Cloud infrastructure remains replaceable and separate from application logic.

How does a request move through the system?

  • The React interface sends requests to FastAPI after authentication plus RBAC checks.
  • RAG retrieves approved knowledge from a vector database while PostgreSQL stores durable application state.
  • MCP connects approved servers through host-controlled clients.
  • Docker plus CI/CD support repeatable delivery.
  • Save docs/architecture/system-overview.md.
  • Confirm that the editor displays the request path plus the permanent boundaries.

Is a system boundary missing?

  • Compare the request path with all nine numbered stages.
  • Confirm that the permanent boundary list includes application modules plus every test layer.
  • Confirm that the delivery section covers local services plus automated delivery.

Need help tracing the flow? Help me review my system request path..

✔️ Awesome, I've got everything!

Your system overview now traces the future request path across every permanent boundary.

ⓧ I'd like to double check the full code

# System Overview

## Future Request Path

1. The React frontend sends an authenticated helpdesk request to FastAPI.
2. FastAPI validates the request and passes identity context to authentication and RBAC policy enforcement.
3. The agent loop plans work through provider-neutral chat-generation contracts.
4. The RAG layer retrieves approved knowledge through an embedding port and vector database boundary.
5. The MCP host creates clients for approved MCP servers and exposes allowed capabilities to the agent.
6. Tool approval checks authorize each proposed action before tool execution.
7. Audit components record requests, decisions, retrieval, approvals, tool activity, and outcomes.
8. PostgreSQL stores durable application state while the vector database stores searchable knowledge representations.
9. FastAPI returns the policy-approved response to the React frontend.

## Permanent Boundaries

- `apps/frontend` owns presentation and browser interaction.
- `apps/backend/app/api` owns HTTP endpoints and transport models.
- `apps/backend/app/auth` owns authentication and RBAC policy.
- `apps/backend/app/agent` owns orchestration and the agent loop.
- `apps/backend/app/rag` owns retrieval workflows.
- `apps/backend/app/mcp` owns MCP host and client integration.
- `apps/backend/app/tools` owns approval and tool execution.
- `apps/backend/app/audit` owns audit events.
- `apps/backend/tests`, `tests/integration`, and `tests/e2e` own test layers.
- `infra/docker` and `infra/cloud` own deployment definitions.

## Delivery Boundaries

Docker supports reproducible local services.
CI/CD validates changes before cloud deployment.
Cloud infrastructure remains replaceable and separate from application logic.

The provider contract separates chat generation from embeddings. Each capability can change without carrying provider-specific objects into the rest of the system.

  • Create llm-provider-contract.md inside the existing docs/architecture directory.
  • Define the provider-neutral ports by pasting this content:
# LLM Provider Contract

## Decision

The application uses separate provider-neutral ports for chat generation and embeddings.
Provider selection remains open until later evidence supports a decision.

## Chat-Generation Port

- Accepts provider-neutral messages, generation settings, and tool definitions.
- Returns provider-neutral text, structured output, tool requests, usage data, and errors.
- Exposes no provider SDK types beyond its adapter.

## Embedding Port

- Accepts provider-neutral text batches and embedding settings.
- Returns numeric vectors, dimensions, usage data, and errors.
- Evolves independently from chat generation.

## Adapter Selection

- `CHAT_PROVIDER`, `CHAT_MODEL`, and `CHAT_BASE_URL` configure the chat adapter.
- `EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, and `EMBEDDING_BASE_URL` configure the embedding adapter.
- Adapter factories select implementations from configuration.
- Provider SDK imports stay inside `apps/backend/app/llm/providers`.

## Dependency Rule

- Agent, RAG, MCP, authentication, frontend, and business modules depend on contracts.
- Provider clients, responses, exceptions, and configuration objects stay inside adapter modules.
- Credentials enter adapters through runtime configuration and never enter domain objects.

## Acceptance Rules

Chat and embedding adapters can change independently.
No provider or model is named, installed, or required in Part 1.

What does the contract enforce?

  • The chat-generation port owns conversational model requests.
  • The embedding port owns vector creation requests.
  • Configuration selects each adapter independently.
  • Adapter modules contain every provider-specific object.
  • Save docs/architecture/llm-provider-contract.md.
  • Confirm that no provider name appears in the saved document.

Why ports instead of direct SDK calls?

Direct SDK calls would spread one provider's types across orchestration plus policy code. Stable ports let the application depend on its own contracts.

Adapters absorb provider-specific behavior at the boundary. A future replacement stays local to that boundary.

Did a provider choice slip in?

  • Remove any provider name from the document.
  • Remove any provider-specific model identifier.
  • Keep provider SDK references confined to the adapter rule.

Want help checking neutrality? Help me find provider-specific coupling in this contract..

✔️ Awesome, I've got everything!

Your contract now keeps chat generation plus embeddings independently replaceable.

ⓧ I'd like to double check the full code

# LLM Provider Contract

## Decision

The application uses separate provider-neutral ports for chat generation and embeddings.
Provider selection remains open until later evidence supports a decision.

## Chat-Generation Port

- Accepts provider-neutral messages, generation settings, and tool definitions.
- Returns provider-neutral text, structured output, tool requests, usage data, and errors.
- Exposes no provider SDK types beyond its adapter.

## Embedding Port

- Accepts provider-neutral text batches and embedding settings.
- Returns numeric vectors, dimensions, usage data, and errors.
- Evolves independently from chat generation.

## Adapter Selection

- `CHAT_PROVIDER`, `CHAT_MODEL`, and `CHAT_BASE_URL` configure the chat adapter.
- `EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, and `EMBEDDING_BASE_URL` configure the embedding adapter.
- Adapter factories select implementations from configuration.
- Provider SDK imports stay inside `apps/backend/app/llm/providers`.

## Dependency Rule

- Agent, RAG, MCP, authentication, frontend, and business modules depend on contracts.
- Provider clients, responses, exceptions, and configuration objects stay inside adapter modules.
- Credentials enter adapters through runtime configuration and never enter domain objects.

## Acceptance Rules

Chat and embedding adapters can change independently.
No provider or model is named, installed, or required in Part 1.

An architecture decision record preserves the reason behind a design choice. Future contributors can follow the decision without guessing what Part 1 intended.

  • Create 0001-provider-agnostic-llm-boundary.md inside the existing docs/decisions directory.
  • Record the provider-boundary decision by pasting this content:
# ADR 0001: Provider-Agnostic LLM Boundary

- Status: Accepted.
- Date: Part 1.

## Context

The enterprise helpdesk agent needs chat generation and embeddings.
Future online, offline, or hybrid choices may change after evidence is gathered.
Direct SDK use in business logic would make those choices expensive to replace.

## Decision

- Define separate chat-generation and embedding ports.
- Keep provider-neutral request, response, usage, and error models in contract modules.
- Select adapters through configuration.
- Confine provider SDK imports and objects to adapter modules.
- Keep agent, RAG, MCP, authentication, frontend, and business layers dependent on contracts.
- Leave provider, model, endpoint, and deployment choices open.

## Consequences

- Chat and embedding providers can evolve independently.
- Tests can use contract-level fakes without provider software.
- Adapter changes do not rewrite orchestration or policy logic.
- New adapters must translate provider behavior into project contracts.

## Deferred Decisions

Hardware fit, quality, latency, total cost, privacy, reliability, deployment, and operational support remain unscored.
No provider wins this decision in Part 1.

What does the decision record preserve?

  • Context explains why replaceable provider boundaries matter.
  • The decision records the dependency rules.
  • Consequences make future adapter work predictable.
  • Deferred decisions keep the eventual provider choice open.
  • Save docs/decisions/0001-provider-agnostic-llm-boundary.md.
  • Confirm that the document ends with an open provider decision.

Does the decision choose a provider?

  • Remove any named provider or named model.
  • Keep chat generation separate from embeddings.
  • Leave evidence-based selection for a later session.

Need help reviewing the ADR? Help me keep this architecture decision provider-neutral..

✔️ Awesome, I've got everything!

Your decision record now makes the provider-neutral boundary traceable.

ⓧ I'd like to double check the full code

# ADR 0001: Provider-Agnostic LLM Boundary

- Status: Accepted.
- Date: Part 1.

## Context

The enterprise helpdesk agent needs chat generation and embeddings.
Future online, offline, or hybrid choices may change after evidence is gathered.
Direct SDK use in business logic would make those choices expensive to replace.

## Decision

- Define separate chat-generation and embedding ports.
- Keep provider-neutral request, response, usage, and error models in contract modules.
- Select adapters through configuration.
- Confine provider SDK imports and objects to adapter modules.
- Keep agent, RAG, MCP, authentication, frontend, and business layers dependent on contracts.
- Leave provider, model, endpoint, and deployment choices open.

## Consequences

- Chat and embedding providers can evolve independently.
- Tests can use contract-level fakes without provider software.
- Adapter changes do not rewrite orchestration or policy logic.
- New adapters must translate provider behavior into project contracts.

## Deferred Decisions

Hardware fit, quality, latency, total cost, privacy, reliability, deployment, and operational support remain unscored.
No provider wins this decision in Part 1.
Build the Part 1 handoff

The handoff carries verified facts into Part 2. It prevents the next session from rebuilding the environment or reopening settled boundaries.

  • Create an empty PART-01-HANDOFF.md file inside the existing docs/handoffs directory.

Before you run the final checks, predict which local configuration file Git will hide from status.

  • Confirm the ignore source from the existing PowerShell terminal by running this command:
git check-ignore -v .env

What should this prove?

The result should name the matching .gitignore rule. This confirms that .env remains protected.

  • Confirm the complete untracked state by running this command:
git status --short --untracked-files=all

What should status prove?

The output should omit .env. It should include .env.example plus the new documentation.

  • Display the complete repository structure by running this command:
Get-ChildItem -LiteralPath . -Recurse -Name

What should the structure prove?

The recursive output should show every permanent directory. It should also show README.md plus all four files under docs.

Does the final check expose a gap?

  • Return to the relevant full-file reference if a document is missing.
  • Return to .gitignore if .env appears in status.
  • Record the observed issue plus its resolution for the handoff.

Need help interpreting the checks? Help me compare my final repository checks with the expected state..

The handoff must contain observed results from your own machine. The interactive fields below keep those values accurate without inventing outputs.

  • Fill PART1_COMMAND_LOG with every command used in Part 1 plus its observed result.
  • Add the opening handoff sections by pasting this content into PART-01-HANDOFF.md.
# Part 1 Handoff

## 1. Completed Work

- Established the permanent `enterprise-it-helpdesk-agent` monorepo on `main`.
- Verified the Windows editor, source control, Python, Node.js, npm, and WSL readiness.
- Created provider-neutral environment boundaries with blank values.
- Proved Git ignores `.env` while retaining `.env.example`.
- Documented the system architecture and provider boundary.

### Commands and Observed Results

[[PART1_COMMAND_LOG="paste every Part 1 command followed by its observed result"]]

What belongs in the command log?

Use the commands you actually ran. Pair each command with the output or error you actually observed.

Include the three final checks from this step. Keep credentials plus future secrets out of the handoff.

  • Save docs/handoffs/PART-01-HANDOFF.md.
  • Confirm that the file begins with completed work plus the populated command log.

Is the command log incomplete?

  • Use the terminal history from the existing Part 1 session.
  • Use your recorded tool outputs from the earlier setup steps.
  • Write an exact error when a readiness check failed.

Need help organizing the log? Help me format my commands and observed results..

  • Place the cursor after the populated command log.
  • Add the exact repository structure by pasting this section:

## 2. Exact Repository Structure

- `apps/frontend`.
- `apps/backend/app/api`.
- `apps/backend/app/core`.
- `apps/backend/app/llm/contracts`.
- `apps/backend/app/llm/providers`.
- `apps/backend/app/agent`.
- `apps/backend/app/rag`.
- `apps/backend/app/mcp`.
- `apps/backend/app/auth`.
- `apps/backend/app/tools`.
- `apps/backend/app/audit`.
- `apps/backend/tests`.
- `services/mcp-server`.
- `data/mock`.
- `data/knowledge`.
- `docs/architecture`.
- `docs/decisions`.
- `docs/handoffs`.
- `infra/docker`.
- `infra/cloud`.
- `scripts`.
- `tests/integration`.
- `tests/e2e`.
- Required otherwise-empty directories contain `.gitkeep` files.

Why list every directory?

The explicit paths give Part 2 an exact starting state. A future session can detect missing or misplaced files immediately.

  • Save docs/handoffs/PART-01-HANDOFF.md.
  • Confirm that the structure section includes all permanent directories.

Does a path differ?

  • Compare the path with the recursive listing you just generated.
  • Correct the handoff when the repository already contains the required directory.
  • Restore the required directory when it is absent from the repository.

Need help reconciling the paths? Help me compare my handoff structure with my repository..

Tool outputs must reflect your own machine. Fill each interactive field with the value you recorded earlier.

  • Place the cursor after the repository structure section.
  • Add the verified tool results by pasting this section:

## 3. Verified Tool Versions

- Visual Studio Code: [[VSCODE_VERSION_OUTPUT="your recorded code --version output"]].
- Git for Windows: [[GIT_VERSION_OUTPUT="your recorded git --version output"]].
- Git author name: [[GIT_AUTHOR_NAME="your verified Git author name"]].
- Git author email: [[GIT_AUTHOR_EMAIL="your verified GitHub-linked email"]].
- Python inventory: [[PYTHON_LIST_OUTPUT="your recorded py list result"]].
- Python runtime: [[PYTHON_VERSION_OUTPUT="your recorded Python 3.14 output"]].
- Node.js: [[NODE_VERSION_OUTPUT="your recorded Node.js output"]].
- npm: [[NPM_VERSION_OUTPUT="your recorded npm output"]].
- WSL readiness: [[WSL_RESULT="your recorded WSL output or exact error"]].
- Windows version: [[WINDOWS_VERSION="your recorded Windows version"]].
- Known RAM: [[KNOWN_RAM="your recorded RAM"]].
- Virtualization status: [[VIRTUALIZATION_STATUS="your recorded virtualization status"]].

Why use observed outputs?

Installed versions can differ from release-page versions. The handoff must describe the machine that Part 2 actually uses.

  • Save docs/handoffs/PART-01-HANDOFF.md.
  • Confirm that no tool field contains an unfilled interactive value.

Is a recorded value unavailable?

  • Use the exact output recorded during the earlier setup step.
  • Use the exact WSL error if its readiness check failed.
  • Avoid estimating a version or machine capability.

Need help identifying an output? Help me map my recorded outputs to the handoff fields..

  • Place the cursor after the verified tool versions.
  • Add the current repository status plus the intentional deferrals by pasting this section:

## 4. Git and GitHub Status

- Local branch: `main`.
- Local repository: initialized with no commits yet.
- Remote repository: not created yet.
- Secret check: `.env` is ignored while `.env.example` remains visible to Git.
- Remote URL: PENDING STEP 5.

## 5. Commits

- Foundation commit SHA: PENDING STEP 5.
- Handoff finalization commit SHA: PENDING STEP 5.

## 6. Intentional Deferrals

- No project package has been installed.
- No virtual environment has been created.
- No frontend application has been scaffolded.
- No Docker service has been installed or started.
- No database or vector store has been started.
- No MCP SDK or LLM software has been selected.
- No provider, model, base URL, or credential has been configured.

What remains for Step 5?

The remote URL plus both commit SHAs are the only pending handoff values. Step 5 creates those values through real Git operations.

  • Save docs/handoffs/PART-01-HANDOFF.md.
  • Confirm that every deferral matches the software left uninstalled in Part 1.

Does the handoff claim too much?

  • Remove any claim that a provider has been selected.
  • Remove any claim that a project service is running.
  • Keep both commit values plus the remote URL pending for Step 5.

Need help checking the current state? Help me remove premature implementation claims..

The final sections preserve actual problems plus the exact launch point for Part 2. They also keep unresolved architecture choices visible.

  • Place the cursor after the intentional deferrals.
  • Complete the handoff by pasting these final sections:

## 7. Problems and Resolutions

[[PROBLEMS_AND_RESOLUTIONS="describe actual issues and resolutions or write None"]]

## 8. Exact Part 2 Starting Point

- Create a minimal modular FastAPI service.
- Create an isolated Python environment.
- Add typed settings for the existing environment boundaries.
- Add a health endpoint and tests.
- Preserve the provider-neutral contract from Part 1.
- Defer LLM, RAG, MCP, authentication, and database implementation.

## 9. Decisions That Remain Open

- Chat provider and model.
- Embedding provider and model.
- Online, offline, or hybrid inference.
- Vector database implementation.
- Authentication and RBAC implementation.
- PostgreSQL deployment model.
- MCP transport and server topology.
- Tool approval policy.
- Docker, CI/CD, and cloud deployment details.

What does the final section accomplish?

  • Problems plus resolutions preserve machine-specific setup knowledge.
  • The Part 2 starting point prevents premature feature work.
  • Open decisions preserve provider neutrality plus deployment flexibility.
  • Save docs/handoffs/PART-01-HANDOFF.md.
  • Review the saved handoff for all nine numbered sections.
  • Confirm that only the remote URL plus the two commit SHAs remain marked PENDING STEP 5.

Does the handoff still contain another placeholder?

  • Replace every interactive tool field with an observed value.
  • Replace the problem field with actual issues plus resolutions.
  • Use None when no problem occurred.

Need a final review? Help me check my nine-section Part 1 handoff..

✔️ Awesome, I've got everything!

Your handoff now captures the exact state that Part 2 inherits.

ⓧ I'd like to double check the full code

# Part 1 Handoff

## 1. Completed Work

- Established the permanent `enterprise-it-helpdesk-agent` monorepo on `main`.
- Verified the Windows editor, source control, Python, Node.js, npm, and WSL readiness.
- Created provider-neutral environment boundaries with blank values.
- Proved Git ignores `.env` while retaining `.env.example`.
- Documented the system architecture and provider boundary.

### Commands and Observed Results

[[PART1_COMMAND_LOG="paste every Part 1 command followed by its observed result"]]

## 2. Exact Repository Structure

- `apps/frontend`.
- `apps/backend/app/api`.
- `apps/backend/app/core`.
- `apps/backend/app/llm/contracts`.
- `apps/backend/app/llm/providers`.
- `apps/backend/app/agent`.
- `apps/backend/app/rag`.
- `apps/backend/app/mcp`.
- `apps/backend/app/auth`.
- `apps/backend/app/tools`.
- `apps/backend/app/audit`.
- `apps/backend/tests`.
- `services/mcp-server`.
- `data/mock`.
- `data/knowledge`.
- `docs/architecture`.
- `docs/decisions`.
- `docs/handoffs`.
- `infra/docker`.
- `infra/cloud`.
- `scripts`.
- `tests/integration`.
- `tests/e2e`.
- Required otherwise-empty directories contain `.gitkeep` files.

## 3. Verified Tool Versions

- Visual Studio Code: [[VSCODE_VERSION_OUTPUT="your recorded code --version output"]].
- Git for Windows: [[GIT_VERSION_OUTPUT="your recorded git --version output"]].
- Git author name: [[GIT_AUTHOR_NAME="your verified Git author name"]].
- Git author email: [[GIT_AUTHOR_EMAIL="your verified GitHub-linked email"]].
- Python inventory: [[PYTHON_LIST_OUTPUT="your recorded py list result"]].
- Python runtime: [[PYTHON_VERSION_OUTPUT="your recorded Python 3.14 output"]].
- Node.js: [[NODE_VERSION_OUTPUT="your recorded Node.js output"]].
- npm: [[NPM_VERSION_OUTPUT="your recorded npm output"]].
- WSL readiness: [[WSL_RESULT="your recorded WSL output or exact error"]].
- Windows version: [[WINDOWS_VERSION="your recorded Windows version"]].
- Known RAM: [[KNOWN_RAM="your recorded RAM"]].
- Virtualization status: [[VIRTUALIZATION_STATUS="your recorded virtualization status"]].

## 4. Git and GitHub Status

- Local branch: `main`.
- Local repository: initialized with no commits yet.
- Remote repository: not created yet.
- Secret check: `.env` is ignored while `.env.example` remains visible to Git.
- Remote URL: PENDING STEP 5.

## 5. Commits

- Foundation commit SHA: PENDING STEP 5.
- Handoff finalization commit SHA: PENDING STEP 5.

## 6. Intentional Deferrals

- No project package has been installed.
- No virtual environment has been created.
- No frontend application has been scaffolded.
- No Docker service has been installed or started.
- No database or vector store has been started.
- No MCP SDK or LLM software has been selected.
- No provider, model, base URL, or credential has been configured.

## 7. Problems and Resolutions

[[PROBLEMS_AND_RESOLUTIONS="describe actual issues and resolutions or write None"]]

## 8. Exact Part 2 Starting Point

- Create a minimal modular FastAPI service.
- Create an isolated Python environment.
- Add typed settings for the existing environment boundaries.
- Add a health endpoint and tests.
- Preserve the provider-neutral contract from Part 1.
- Defer LLM, RAG, MCP, authentication, and database implementation.

## 9. Decisions That Remain Open

- Chat provider and model.
- Embedding provider and model.
- Online, offline, or hybrid inference.
- Vector database implementation.
- Authentication and RBAC implementation.
- PostgreSQL deployment model.
- MCP transport and server topology.
- Tool approval policy.
- Docker, CI/CD, and cloud deployment details.

That is the architecture contract secured. Your local configuration is protected while every future component has a documented boundary.

Next, you will turn this reviewed foundation into two traceable commits. You will also synchronize the repository with a private GitHub remote.

Commit and Publish the Foundation

Your repository now describes the full enterprise agent without coupling its business logic to a provider. However, the foundation still lives on one machine.

A traceable Git history records how the foundation changes. A private GitHub repository gives the project a durable remote home.

In this step, get ready to:
  • Review the staged foundation before creating its first commit.
  • Publish the foundation to a private remote repository.
  • Finalize the handoff before proving branch synchronization.
Review and commit the foundation

Your first commit becomes the baseline for Parts 2 to 12. A careful review keeps the ignored .env file outside that history.

  • Switch back to the PowerShell terminal in VS Code.
  • Review every untracked file by running this command:
git status --short --untracked-files=all

What should this status show?

The output should list the monorepo files as untracked candidates. It should include .env.example while omitting .env.

  • Prove the local environment file is ignored by running this command:
git check-ignore -v .env

What does this prove?

The output identifies the matching rule from .gitignore. This proves the local environment file stays outside the commit.

  • Stage the reviewed foundation by running this command:
git add .

What did Git stage?

Git stages the visible repository files for the first commit. Ignored paths remain outside the staging area.

  • Inspect the exact staged changes by running this command:
git diff --cached

Review the staged foundation

The diff should show the repository structure plus its documentation. It should show blank provider slots in .env.example without showing the local .env file.

  • Create the foundation commit by running this command:
git commit -m "chore: establish Part 1 project foundation"

What did this commit capture?

This commit records the permanent monorepo skeleton plus its provider-neutral engineering contracts. It becomes the clean starting point for future implementation work.

  • Read the new commit hash by running this command:
git log -1 --oneline

What should the log show?

The newest log entry should contain the message chore: establish Part 1 project foundation. The characters before the message are the commit's short SHA.

  • Copy the short SHA from the log output into your first commit SHA.

That is the first durable checkpoint complete. Your architecture foundation now has an attributed place in Git history.

Commit did not complete?

  • Check that the staged diff contains files before retrying the commit.
  • Check that your global Git author name has a non-blank value.
  • Check that your global Git author email has a non-blank value.

Still blocked? Help me diagnose why my first Git commit did not complete.

Create and connect the private repository

The local commit needs a remote copy before it can support collaboration or recovery. An HTTPS remote connects the existing main branch to the private GitHub repository.

  • Go to GitHub in your browser.
  • Select the upper-right creation menu.
  • Choose New repository.
  • Select your GitHub account as the owner.
  • Enter enterprise-it-helpdesk-agent as the repository name.
  • Choose Private as the visibility.
  • Leave all initialization options unselected.
  • Click Create repository.

Why keep the remote empty?

An empty remote accepts the local history without introducing a competing README or ignore file. Your reviewed local foundation remains the source of truth.

The empty repository page contains several command examples. Finding the correct HTTPS address can feel crowded.

  • Copy the HTTPS repository URL into your HTTPS repository URL.
  • Replace REMOTE-URL in the command below with your HTTPS repository URL before running it:
git remote add origin REMOTE-URL

What does the remote do?

The remote name origin becomes the local label for your private GitHub repository. Future pushes can use that label instead of repeating the full URL.

  • Verify the configured fetch URL plus push URL by running this command:
git remote -v

What should the remote show?

The output should show your private repository URL for both operations under origin.

The first push may trigger browser authentication or Git Credential Manager. This protects the private repository without placing a GitHub password in the terminal.

  • Publish the local main branch by running this command:
git push -u origin main

What did the first push establish?

The push publishes the first commit to origin/main. The upstream connection lets later status checks compare the local branch with its remote counterpart.

First push did not complete?

  • Complete the browser authentication flow if GitHub opens one.
  • Approve the request in Git Credential Manager if it appears.
  • Avoid entering a GitHub password into a Git password prompt.

Need a hand? Help me troubleshoot my authenticated GitHub push.

Finalize the handoff and verify synchronization

The handoff is the next session's entry point. It now needs the real repository facts produced by the first commit plus the first push.

  • In the VS Code Explorer sidebar, select docs/handoffs/PART-01-HANDOFF.md.
  • Complete the remaining Part 1 handoff fields with the actual remote URL, first commit SHA, push result, plus recorded issues.
  • Keep every previously recorded tool output unchanged.
  • Save docs/handoffs/PART-01-HANDOFF.md.
  • Confirm the handoff is modified while .env remains absent by running this command:
git status --short --untracked-files=all

What should this status show?

The handoff should appear as the changed file. The ignored local environment file should remain absent.

  • Stage the completed handoff by running this command:
git add .

What is staged now?

Only the saved handoff update should join the next commit. The repository's ignore rules still exclude .env.

  • Review the staged handoff changes by running this command:
git diff --cached

Check the handoff details

The diff should show the actual remote URL plus the first commit SHA. It should also preserve the observed tool outputs from earlier steps.

  • Create the final Part 1 commit by running this command:
git commit -m "docs: finalize Part 1 handoff"

What does this commit finish?

The second commit turns the handoff into a reproducible continuation point. Part 2 can begin from recorded facts instead of recreated setup.

  • Publish the finalized handoff by running this command:
git push

What did this push update?

The upstream connection sends the second commit to the existing origin/main branch.

  • Read the latest commit entry by running this command:
git log -1 --oneline

What should the latest entry show?

The newest entry should contain docs: finalize Part 1 handoff.

  • Copy the short SHA from the latest entry into your second commit SHA.

Before the final checks, do you expect the local branch tip to match the remote branch tip?

  • Refresh the remote-tracking information by running this command:
git fetch origin

What did the fetch refresh?

Git refreshes its local view of the remote repository. A successful fetch may finish without printing new changes.

  • Check the branch tracking state by running this command:
git status -sb

What should the branch status prove?

The status should show local main tracking origin/main. It should show no file changes.

  • Confirm the newest commit message by running this command:
git log -1 --oneline

What should the latest commit be?

The latest message should be docs: finalize Part 1 handoff.

  • Print the full local branch hash by running this command:
git rev-parse main

What does this hash represent?

This full hash identifies the exact commit at the tip of your local main branch.

  • Print the full remote-tracking branch hash by running this command:
git rev-parse origin/main

Do the hashes match?

The second full hash should match the local hash character for character. Matching values prove that both branch tips reference the same commit.

Branches are not synchronized?

  • Check the short branch status for uncommitted handoff changes.
  • Push the local branch if the status shows an unpublished commit.
  • Fetch from origin again before comparing the full hashes.

Still seeing different hashes? Help me reconcile local main with origin/main safely.

  • Return to the private enterprise-it-helpdesk-agent repository in your browser.
  • Confirm the branch selector shows main.
  • Confirm the repository displays the same foundation files as VS Code.
  • Confirm the latest commit message is docs: finalize Part 1 handoff.

You now have a clean local branch plus a matching private remote. The ignored environment file stayed local throughout both commits.

Secret mission

Create the Future LLM Evaluation Rubric

A provider-neutral boundary needs a repeatable way to compare future options. Create an evidence-based rubric for online, offline, or hybrid choices without naming a provider or model winner.

Clean Up Your Resources

Clean Up Your Resources

Part 1 created no running services or metered resources, so there are no ongoing project costs. Choose whether to keep the foundation for Part 2, pause by closing your tools, or delete both copies if you are abandoning the application.

Resources you used:

  • Local files: Your persistent project folder at $HOME\source\repos\enterprise-it-helpdesk-agent, including the ignored blank .env file.
  • Remote repository: Your private GitHub repository named enterprise-it-helpdesk-agent.

Keep everything running

No action is needed. Choose this option because the local folder and private repository form the permanent starting point for Part 2.

  • Keep the local folder at $HOME\source\repos\enterprise-it-helpdesk-agent.
  • Keep the private enterprise-it-helpdesk-agent repository on GitHub.
  • Use docs/handoffs/PART-01-HANDOFF.md as the starting point for Part 2.

Pause - I'll come back to this later

Pausing means closing the tools from this session. Your synchronized local and remote copies stay ready for Part 2.

  • Return to the PowerShell terminal from earlier.
  • Confirm the repository still has a clean synchronized state by running this command:
git status -sb

What Does This Check Prove?

The git status -sb result should show main tracking origin/main with no file changes. You're set for a clean return when Part 2 begins.

  • Close Visual Studio Code.
  • Close the PowerShell window if it remains open.

No service needs to remain running while you are away.

Delete - I don't want to use this again

Deleting both copies is a serious step. Choose this option only if you are abandoning the complete 12-part application.

  • Return to the private enterprise-it-helpdesk-agent repository on GitHub from earlier.
  • Select Settings in the repository navigation.
  • Locate the repository deletion controls on the Settings page.
  • Delete the enterprise-it-helpdesk-agent repository with those controls.
  • Complete GitHub's confirmation prompts.

The remote copy is now gone. Windows File Explorer gives you a visible way to remove the local copy.

  • Press the Windows key to open search.
  • Type File Explorer in the search field.
  • Press Enter to open File Explorer.
  • Open your Windows user folder.
  • Open the source folder.
  • Open the repos folder.
  • Right-click the enterprise-it-helpdesk-agent folder.
  • Select Delete.

You should no longer see the repository in your GitHub repository list. You should no longer see the local folder inside repos.

The local deletion also removes the ignored blank .env file.

Nice Work!

Nice Work!

You did it! Your provider-agnostic Enterprise IT Helpdesk AI Agent now has a permanent monorepo foundation synchronized through GitHub.

You've learned how to:

  • Defined provider-neutral architecture contracts that keep chat generation separate from embeddings.
  • Applied secret hygiene to keep .env outside Git history before the first commit.
  • Published a copyable Part 1 handoff through three traceable commits in the private GitHub repository.
  • Completed the optional Secret Mission by adding an evidence-based LLM evaluation rubric with rejection gates for future online, offline, or hybrid choices.

Ready to quiz yourself?