> ## Documentation Index
> Fetch the complete documentation index at: https://amd-gaia.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Process Analyst Agent

> Build a process analyst agent in C++ that explains running processes, detects suspicious files, and lets you stop, restart, or quarantine items — all with local LLM inference

<Info>
  **Source Code:** [`cpp/examples/process_agent.cpp`](https://github.com/amd/gaia/blob/main/cpp/examples/process_agent.cpp) — single-file, self-contained agent (\~2,900 lines including 7 tools, action menu, and decision support).
</Info>

<Note>
  **Platform:** Windows (Win32 APIs + PowerShell). Compiles on Linux/macOS for CI but tools require Windows to return real data.
  **Prerequisite:** Lemonade Server running with a model loaded.
  **Recommended:** Run as Administrator for full process visibility and quarantine access.
</Note>

***

## What This Agent Does

The Process Analyst is an AI agent that makes sense of what's running on your PC. On startup it scans every process and service, classifies them by resource use and behavior, and shows you a plain-English summary. You can ask it to explain any task — what it is, what it does, and whether there's reason to be concerned — or take action directly.

Here's what makes it interesting:

* **It explains what's running** — every process gets a plain-English description: what it is, what it does, and whether it looks normal
* **Ask about any task** — describe an item from the summary and get a clear explanation without needing technical knowledge
* **Manage processes and services** — stop, restart, or quarantine items; the agent always asks before acting
* **Background monitoring** — toggle a background watcher that alerts you to memory spikes, new suspicious items, and health changes while you keep working
* **Everything is local** — no data leaves your machine

***

## See It In Action

<video controls autoPlay loop muted playsInline style={{ minHeight: '775px', objectFit: 'cover' }} src="https://assets.amd-gaia.ai/videos/process-analyzer-demo-01.webm" />

The agent auto-runs a full system scan on startup, then waits for your input. You can ask about any item in plain English — or use the action menu to stop, restart, or quarantine it.

***

## Quick Start

<Steps>
  <Step title="Build">
    <Tabs>
      <Tab title="Windows (MSVC)">
        ```bat theme={null}
        cd cpp
        ```

        ```bat theme={null}
        cmake -B build -G "Visual Studio 17 2022" -A x64
        ```

        <Note>
          If CMake reports a generator or platform mismatch, a stale `build\` directory from a previous run is causing the conflict. Delete it and reconfigure:

          ```powershell theme={null}
          Remove-Item -Recurse -Force build
          cmake -B build -G "Visual Studio 17 2022" -A x64
          ```
        </Note>

        ```bat theme={null}
        cmake --build build --config Release --target process_agent
        ```

        Binary: `build\Release\process_agent.exe`
      </Tab>

      <Tab title="Windows (Ninja)">
        <Warning>
          Ninja requires two prerequisites before running these commands:

          1. **Ninja installed** — `winget install Ninja-build.Ninja` (then restart your terminal)
          2. **MSVC compiler in PATH** — Ninja does not locate `cl.exe` automatically the way the Visual Studio generator does. Open an [x64 Native Tools Command Prompt for VS 2022](https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell) — this puts `cl.exe` in PATH automatically. Do not use a plain PowerShell or CMD window.
        </Warning>

        ```bat theme={null}
        cd cpp
        ```

        ```bat theme={null}
        cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
        ```

        <Note>
          If CMake reports a generator mismatch, a stale `build\` directory from a previous run is causing the conflict. Delete it and reconfigure:

          ```powershell theme={null}
          Remove-Item -Recurse -Force build
          cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
          ```
        </Note>

        ```bat theme={null}
        cmake --build build --target process_agent
        ```

        Binary: `build\process_agent.exe`
      </Tab>
    </Tabs>
  </Step>

  <Step title="Start Lemonade Server">
    ```bash theme={null}
    lemonade-server serve
    ```

    The agent connects to `http://localhost:13305/api/v1` by default.
  </Step>

  <Step title="Run the agent">
    <Tabs>
      <Tab title="Windows (MSVC)">
        ```bat theme={null}
        build\Release\process_agent.exe
        ```
      </Tab>

      <Tab title="Windows (Ninja)">
        ```bat theme={null}
        build\process_agent.exe
        ```
      </Tab>
    </Tabs>

    The agent auto-analyzes on startup. After the scan completes, you'll see a summary followed by an action menu:

    ```
    A. Processes
    A1  msedge.exe (x28) - 2.1 GB RAM - Microsoft Edge [NORMAL]
    A2  Teams.exe (x8) - 1.4 GB RAM - Microsoft Teams [HIGH]
    A3  cpptools-srv.exe (x2) - 890 MB RAM - C/C++ IntelliSense [NORMAL]

    B. Services
    All services running normally

    C. Suspicious Items
    C1  unknown_app.exe - C:\Users\user\Downloads\unknown_app.exe
        flags: unknown_company, unknown_description, temp_path

    ──────────────────────────────────────────────────────────────
    Available Actions:

    [1] Explain    -- Get details on a process or service
    [2] Stop       -- Kill a process or stop a service
    [3] Restart    -- Restart an app or service
    [4] Quarantine -- Move a suspicious file to quarantine
    [5] Reanalyze  -- Run a fresh system analysis
    [6] Monitor    -- Toggle background health watcher

    Shortcuts: '1 A3' = Explain A3,  '2 B1' = Stop B1,  '4 C1' = Quarantine C1,  '6 5' = Monitor every 5 min

    >
    ```

    Each item gets a label (A1, A2, C1, etc.) you can use in any command:

    | What you type          | What happens                                       |
    | ---------------------- | -------------------------------------------------- |
    | `1`                    | Explain all items                                  |
    | `1 A3`                 | Explain cpptools-srv.exe                           |
    | `2 A1`                 | Stop msedge.exe                                    |
    | `4 C1`                 | Quarantine unknown\_app.exe                        |
    | `5`                    | Reanalyze the system                               |
    | `6`                    | Toggle background monitor (default 5 min interval) |
    | `6 5`                  | Toggle monitor with 5-minute interval              |
    | `What is svchost.exe?` | Ask a free-form question                           |

    <Note>
      For full process visibility and quarantine access, right-click your terminal and select **Run as administrator** before launching the agent.
    </Note>
  </Step>
</Steps>

***

## Architecture

The agent runs in two phases. On startup it auto-scans the system — no menu shown first. The LLM calls `system_snapshot` and `list_processes`, classifies everything into three labeled sections (A: Processes, B: Services, C: Suspicious Items), then presents an action menu.

Conversation history is preserved across all actions so the LLM can reference any labeled item without re-scanning. Only **Reanalyze** clears history, because the system state has genuinely changed.

```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#E2A33E', 'primaryTextColor':'#1a1a1a', 'primaryBorderColor':'#A87B2D', 'lineColor':'#A87B2D', 'edgeLabelBackground':'#ffffff', 'fontFamily':'system-ui, -apple-system, sans-serif'}, 'flowchart': {'curve': 'basis'}}}%%
flowchart LR
    START["Startup<br/>Auto-scan"] --> CLASS["LLM classifies<br/>A · B · C"]
    CLASS --> MENU["Action Menu"]
    MENU --> ACT["Explain / Stop<br/>Restart / Quarantine"]
    ACT --> MENU
    MENU -->|"Reanalyze"| START
    MENU -->|"Monitor"| MON["Background Thread<br/>SilentConsole + diff alerts"]
    MON -.->|"alerts before prompt"| MENU

    style START fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CLASS fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style MENU fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style ACT fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style MON fill:#1565C0,stroke:#42A5F5,stroke-width:2px,color:#fff
```

***

## How It Works

The entire agent is a single `.cpp` file with six sections. Let's walk through each one.

1. **Shell Helper** — bridges C++ and PowerShell for command execution and validates inputs
2. **Win32 Process Intelligence** — native API for fast process snapshots with file version info
3. **Tool Registration** — 7 tools the LLM can call (3 read-only + 4 destructive)
4. **System Prompt** — teaches the LLM the A/B/C classification protocol
5. **ProcessConsole** — custom TUI that formats A/B/C sections with color coding
6. **Monitor Mode** — background thread that diffs snapshots and surfaces alerts

The agent subclasses `gaia::Agent` with three pieces: a config, registered tools, and a system prompt.

```cpp theme={null}
class ProcessAgent : public gaia::Agent {
public:
    explicit ProcessAgent(const std::string& modelId)
        : Agent(makeConfig(modelId)) {
        setOutputHandler(std::make_unique<ProcessConsole>());  // custom TUI
        init();  // calls registerTools() + composes system prompt
    }

protected:
    std::string getSystemPrompt() const override { /* ... */ }
    void registerTools() override { /* ... */ }

private:
    static gaia::AgentConfig makeConfig(const std::string& modelId) {
        gaia::AgentConfig config;
        config.maxSteps = 20;
        config.modelId = modelId;
        return config;
    }
};
```

***

### 1. The Shell Helper: Bridging C++ and PowerShell

The `runShell()` function wraps PowerShell execution, building a command string and reading output through a pipe:

```cpp theme={null}
static std::string runShell(const std::string& command) {
    std::string fullCmd = "powershell -NoProfile -NonInteractive -Command \"& { "
                          + command + " }\" 2>&1";
    FILE* pipe = _popen(fullCmd.c_str(), "r");
    if (!pipe) return R"({"error": "Failed to execute command"})";
    // ... code redacted for simplicity ...
    return result.empty()
        ? R"json({"status": "completed", "output": "(no output)"})json"
        : result;
}
```

The agent also includes a dedicated path validator for quarantine operations:

```cpp theme={null}
static bool isSafePath(const std::string& path) {
    if (path.size() < 3) return false;
    if (!std::isalpha(static_cast<unsigned char>(path[0])) ||
        path[1] != ':' || path[2] != '\\') return false;
    const std::string dangerous = "\"`;|&{}<>$";
    for (char c : path) {
        if (dangerous.find(c) != std::string::npos) return false;
    }
    return true;
}
```

**Why a separate path validator?** File paths need drive-letter validation and a different dangerous character set than shell arguments. `isSafeShellArg()` rejects single quotes (valid in Windows paths), while `isSafePath()` requires the `X:\` prefix and allows single quotes but blocks shell metacharacters. Two validators, two threat models.

***

### 2. Win32 Process Intelligence

Rather than relying on PowerShell for everything, the Process Analyst uses native Win32 APIs for its hot path — process enumeration and memory measurement. The core of `getTopProcesses()` takes a snapshot, groups processes by exe name, then enriches each entry with version info and factual flags:

```cpp theme={null}
static gaia::json getTopProcesses(int topN = 20) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    // ... enumerate processes, measure memory via K32GetProcessMemoryInfo ...
    // ... group by exe name, accumulate total memory and instance count ...

    for (auto& g : sorted) {
        // ... enrich with version info (company, description) via GetFileVersionInfoW ...

        // Factual flags for LLM classification
        gaia::json flags = gaia::json::array();
        if (company.empty()) flags.push_back("unknown_company");
        if (lowerPath.find("\\Downloads\\") != std::string::npos)
            flags.push_back("temp_path");
        entry["flags"] = flags;
    }
    return result;
}
```

Three design choices worth understanding:

* **Performance** — `CreateToolhelp32Snapshot` + `K32GetProcessMemoryInfo` returns data in \~20ms for 200+ processes. `Get-Process | ConvertTo-Json` takes 2-3 seconds for the same data. When the agent needs to scan on every startup, that difference matters.
* **Process grouping** — Instead of listing 45 separate `chrome.exe` entries, the agent groups by exe name with instance count and total memory. The LLM sees "chrome.exe x45 -- 3.2 GB" which is far more actionable than 45 lines of individual PIDs.
* **Factual flags** — `unknown_company`, `unknown_description`, `temp_path` are computed as structured metadata from Win32 `GetFileVersionInfoW` and path analysis. The LLM uses these as input to classification, not as final verdicts.

***

### 3. Tool Registration: Teaching the Agent What It Can Do

Tools are registered with a name, description, callback, and typed parameter list. The framework automatically includes registered tools in the system prompt sent to the LLM.

Here's `system_snapshot`, which demonstrates the hybrid Win32 + PowerShell approach:

```cpp theme={null}
toolRegistry().registerTool(
    "system_snapshot",
    "System overview: CPU load, memory, disk, uptime, top processes by memory "
    "(with company, description, path, and factual flags), problematic services, "
    "and network connection count. Use first during analysis.",
    [](const gaia::json& /*args*/) -> gaia::json {
        gaia::json result;
        result["tool"]          = "system_snapshot";
        result["disk"]          = getDiskUsageInfo();     // Win32: GetDiskFreeSpaceExW
        result["memory"]        = getMemoryInfo();        // Win32: GlobalMemoryStatusEx
        result["top_processes"] = getTopProcesses(30);    // Win32: CreateToolhelp32Snapshot

        // PowerShell: CPU load, uptime, services, connections
        std::string psCmd = "$o=@{}; $c=Get-CimInstance Win32_Processor; ...";
        // ... merge PowerShell results into result ...

        result["command"] = "Win32 API: memory, disk, processes + PowerShell: CPU, services, connections";
        return result;
    },
    {}  // no parameters
);
```

And `kill_process`, which shows parameter validation and the `command` + `output` contract:

```cpp theme={null}
toolRegistry().registerTool(
    "kill_process",
    "Terminate a running process by name. ONLY use after explicit user confirmation.",
    [](const gaia::json& args) -> gaia::json {
        std::string name = args.value("name", "");
        if (name.empty())
            return {{"error", "Process name is required"}};

        // Validate: only alphanumeric + . - _
        // ... code redacted for simplicity ...

        KillResult kr = killProcessesByName(name);
        return {
            {"tool", "kill_process"},
            {"terminated", kr.terminated},
            {"command", "Win32 API: TerminateProcess(" + name + ")"},
            {"output", "Found N instances, terminated N, freed X MB"}
        };
    },
    {{"name", gaia::ToolParamType::STRING, true, "Process name (e.g., 'chrome.exe')"}}
);
```

**Why `command` + `output` keys?** Every tool returns both a `command` string and an `output` string. The `ProcessConsole` uses these for its TUI display — the `command` appears in the tool header, and `output` appears in the preview box. This consistent contract means the output handler doesn't need to understand tool-specific JSON structures.

***

### 4. The System Prompt: Classification Protocol

The system prompt teaches the LLM how to classify processes into three labeled sections and how to respond to user actions. Here are the core classification criteria:

```
### A. Processes (resource consumers)
Select the most significant resource consumers. Consider:
- Memory usage relative to total system RAM
- Instance count (many instances = noteworthy)
- Whether the resource usage is expected for that application type
Tag each: [NORMAL] expected, [HIGH] unexpectedly high, [SUSPICIOUS]

### B. Services (problematic)
Report services with Status not "OK" or Memory > 200 MB.
If none: "All services running normally"

### C. Suspicious Items
The flags array provides factual signals — use as INPUT, not verdicts:
- unknown_company + unknown_description = STRONG signal
- temp_path = STRONG signal for non-installers
- EXCEPTIONS: svchost.exe, csrss.exe, smss.exe may show empty company — NORMAL
```

The system prompt also defines the action behavior protocol, including the multi-step quarantine confirmation:

```
## ACTION BEHAVIOR

Users reference items by group letter + number (e.g., "Explain A3", "Stop B1").

- **Quarantine**: Before calling quarantine_item, you MUST:
  1. Call explain_item to get full details
  2. Present confirmation in Key: Value format
  3. Ask: Kill [name] and move it to quarantine? (yes / no)
  4. Wait for response. If NO, abort. If YES, call quarantine_item.
```

**Why A/B/C labels?** They create a shared vocabulary between the LLM and the user. "Explain A3" unambiguously maps to the third process in the resource consumers section — no re-scanning required.

**Why explicit quarantine protocol?** Quarantine is irreversible — it kills the process AND moves the executable file. The multi-step protocol (explain, confirm, wait for yes/no) prevents accidental data loss from an LLM hallucination.

***

### 5. ProcessConsole: Section-Aware Formatting

The `ProcessConsole` overrides `CleanConsole::printFinalAnswer()` to render the LLM's structured A/B/C output with visual hierarchy. It applies six line detection rules in order (first match wins):

1. **Blank line** — suppresses consecutive blanks to keep output tight
2. **Section header** — "A. Processes", "B. Services", "C. Suspicious Items" — rendered as bold white label with a gray description line underneath
3. **Item reference** — `A4: cpptools-srv.exe` — bold cyan tag, bold white name
4. **Key: Value** — first colon within 20 chars with alpha key — bold white key, normal value
5. **Numbered item** — `1. chrome.exe ...` — normal rendering with markdown bold support
6. **Default paragraph** — everything else — gray (dimmed) prose

Here's how Rule 3 handles item reference lines:

```cpp theme={null}
// Rule 3: Item reference title (A4: cpptools-srv.exe)
if (line.size() >= 4 && line[0] >= 'A' && line[0] <= 'C' &&
    std::isdigit(static_cast<unsigned char>(line[1]))) {
    auto colon = line.find(": ");
    if (colon != std::string::npos && colon <= 4) {
        std::string tag  = line.substr(0, colon);
        std::string rest = line.substr(colon + 2);
        std::cout << color::BOLD << color::CYAN << tag << color::RESET
                  << "  " << color::BOLD << color::WHITE << rest << color::RESET;
    }
}
```

**Why override `printFinalAnswer()`?** The LLM outputs structured sections that need visual hierarchy. Default `CleanConsole` treats all text equally — `ProcessConsole` adds section headers with descriptions, color-coded item tags, and Key: Value formatting that makes the output scannable at a glance.

***

### 6. Monitor Mode: Background Health Watcher

<video controls autoPlay loop muted playsInline style={{ minHeight: '800px', objectFit: 'cover' }} src="https://assets.amd-gaia.ai/videos/process-analyzer-demo-02.webm" />

The monitor is a background thread that periodically re-scans the system and compares consecutive snapshots to detect changes. It runs alongside the interactive agent — you can keep explaining, stopping, or restarting processes while the monitor watches for anomalies.

**Starting and stopping.** Monitor is a toggle on `[6]`. Press it once to start, again to stop. You can also specify an interval: `6 5` starts monitoring every 5 minutes. Typing `monitor` or `monitor N` at the prompt does the same thing. The default interval is 5 minutes.

**How it works internally.** When started, the agent spawns a second `ProcessAgent` on a dedicated thread. This background agent uses a `SilentConsole` — it runs the same `system_snapshot` and `list_processes` tools but produces no visible output. After each scan it builds a `MonitorSnapshot` (memory usage, top process list, suspicious items, health status) and diffs it against the previous snapshot. Any meaningful changes become alerts.

**Alert types and thresholds:**

| Alert                    | Trigger                                               | Severity                   |
| ------------------------ | ----------------------------------------------------- | -------------------------- |
| Memory spike             | System memory use jumps >10 percentage points         | WARNING (CRITICAL if >90%) |
| Per-process memory surge | A single process grows by >500 MB                     | WARNING                    |
| New process in top-20    | A process appears that was not in the previous top-20 | INFO                       |
| Process left top-20      | A process drops out of the previous top-20            | INFO                       |
| New suspicious item      | LLM flags a new item in section C                     | CRITICAL                   |
| Health status change     | Overall health classification changes                 | WARNING or CRITICAL        |

**Alert delivery.** Pending alerts are displayed before the next menu prompt, so you see them naturally between actions. For CRITICAL and NEW\_SUSPICIOUS alerts, the agent also sends a Windows notification so you get alerted even if the terminal is in the background.

**Design choices:**

* **Separate agent instance** — the monitor's `ProcessAgent` has its own conversation history and LLM connection. This avoids corrupting the interactive agent's context with monitoring chatter.
* **SilentConsole** — suppresses all tool output and conclusions from the background scan. Only the diff-based alerts reach the user.
* **Deterministic scans** — the monitor agent uses `temperature=0` for consistent health classifications across consecutive scans when system state hasn't changed.
* **Toggle, not a mode** — the interactive menu stays fully functional while the monitor runs. There is no "monitor mode" to enter or exit.
* **NPU-friendly** — background monitoring is an ideal workload for AMD Ryzen AI NPU inference. The monitor runs periodic scans without tying up the CPU or GPU, leaving them free for your other work.

***

## Tool Reference

The agent registers 7 tools in two categories:

### Analysis Tools (Read-Only)

These gather information without changing anything on the system.

| Tool              | What It Uses           | Parameters        | What the LLM Learns                                                                                 |
| ----------------- | ---------------------- | ----------------- | --------------------------------------------------------------------------------------------------- |
| `system_snapshot` | Win32 API + PowerShell | none              | CPU load, memory, disk, uptime, top 30 processes with flags, problematic services, connection count |
| `list_processes`  | Win32 API + PowerShell | none              | Top 30 by memory (with company, description, flags), top 10 by CPU, background count                |
| `explain_item`    | Win32 API + PowerShell | `name` (required) | Full details: path, what the file is, what it does, memory, CPU, start time, network connections    |

### Action Tools (Destructive — require user confirmation)

These modify the system. The system prompt mandates user approval before the LLM calls any of them.

| Tool              | What It Uses                                    | Parameters        | When to Use                                              |
| ----------------- | ----------------------------------------------- | ----------------- | -------------------------------------------------------- |
| `kill_process`    | `CreateToolhelp32Snapshot` + `TerminateProcess` | `name` (required) | Stop a resource hog or suspicious process                |
| `restart_process` | `TerminateProcess` + `CreateProcessW`           | `name` (required) | Restart a hung application from the same exe path        |
| `restart_service` | PowerShell `Restart-Service`                    | `name` (required) | Restart a degraded Windows service                       |
| `quarantine_item` | `killProcessesByPath` + `MoveFileExW`           | `path` (required) | Move suspicious exe to `C:\ProgramData\GAIA\quarantine\` |

***

## Diagnostics Flow

```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#E2A33E', 'primaryTextColor':'#1a1a1a', 'primaryBorderColor':'#A87B2D', 'lineColor':'#A87B2D', 'edgeLabelBackground':'#ffffff', 'fontFamily':'system-ui, -apple-system, sans-serif'}, 'flowchart': {'curve': 'basis'}}}%%
flowchart TD
    START["Phase 1: DETECT<br/>(auto-runs on startup)"] --> SS["system_snapshot<br/>CPU, memory, disk, services"]
    SS --> LP["list_processes<br/>Top 30 memory, top 10 CPU"]
    LP --> CLASS["LLM classifies A/B/C<br/>Processes, Services, Suspicious"]
    CLASS --> CONC1["Conclusion displayed"]
    CONC1 --> MENU["Phase 2: Action Menu"]

    MENU -->|"[1] Explain"| EX["explain_item<br/>path, description, connections"]
    MENU -->|"[2] Stop"| CONF_S["Confirm with user"]
    MENU -->|"[3] Restart"| CONF_R["Confirm with user"]
    MENU -->|"[4] Quarantine"| EX_Q["explain_item first"]
    MENU -->|"[5] Reanalyze"| CLEAR["clearHistory()"]
    MENU -->|"[6] Monitor"| MTOG{"Monitor<br/>running?"}
    MTOG -->|No| MSTART["Start background thread<br/>SilentConsole + ProcessAgent"]
    MTOG -->|Yes| MSTOP["Stop monitor thread"]
    MSTART --> MSCAN["system_snapshot +<br/>list_processes (silent)"]
    MSCAN --> MDIFF["Diff MonitorSnapshot<br/>vs previous"]
    MDIFF -->|"alerts found"| MALERT["Show alerts before<br/>next menu prompt"]
    MDIFF -->|"no changes"| MWAIT["Sleep interval"]
    MALERT -->|"CRITICAL"| MBALLOON["Windows balloon<br/>notification"]
    MBALLOON --> MWAIT
    MALERT -->|"INFO/WARNING"| MWAIT
    MWAIT --> MSCAN
    MSTOP --> MENU

    EX --> ANS1["Explanation displayed"]
    ANS1 --> MENU

    CONF_S -->|Yes| KILL["kill_process<br/>TerminateProcess"]
    CONF_S -->|No| MENU
    KILL --> ANS2["Result displayed"]
    ANS2 --> MENU

    CONF_R -->|Yes| RESTART["restart_process /<br/>restart_service"]
    CONF_R -->|No| MENU
    RESTART --> ANS3["Result displayed"]
    ANS3 --> MENU

    EX_Q --> CONF_Q["Confirm: Key/Value summary<br/>Kill and quarantine? yes/no"]
    CONF_Q -->|Yes| QUAR["quarantine_item<br/>MoveFileExW"]
    CONF_Q -->|No| MENU
    QUAR --> ANS4["Result displayed"]
    ANS4 --> MENU

    CLEAR --> START

    style START fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style SS fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style LP fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CLASS fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CONC1 fill:#2d8a2d,stroke:#4CAF50,stroke-width:2px,color:#fff
    style MENU fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style EX fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CONF_S fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CONF_R fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style EX_Q fill:#2d2d2d,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CONF_Q fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style KILL fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style RESTART fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style QUAR fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style CLEAR fill:#1565C0,stroke:#42A5F5,stroke-width:2px,color:#fff
    style MTOG fill:#1565C0,stroke:#42A5F5,stroke-width:2px,color:#fff
    style MSTART fill:#1565C0,stroke:#42A5F5,stroke-width:2px,color:#fff
    style MSTOP fill:#1565C0,stroke:#42A5F5,stroke-width:2px,color:#fff
    style MSCAN fill:#2d2d2d,stroke:#42A5F5,stroke-width:2px,color:#fff
    style MDIFF fill:#2d2d2d,stroke:#42A5F5,stroke-width:2px,color:#fff
    style MALERT fill:#FF8F00,stroke:#FFA726,stroke-width:2px,color:#fff
    style MBALLOON fill:#A87B2D,stroke:#E2A33E,stroke-width:2px,color:#fff
    style MWAIT fill:#2d2d2d,stroke:#42A5F5,stroke-width:2px,color:#fff
    style ANS1 fill:#2d8a2d,stroke:#4CAF50,stroke-width:2px,color:#fff
    style ANS2 fill:#2d8a2d,stroke:#4CAF50,stroke-width:2px,color:#fff
    style ANS3 fill:#2d8a2d,stroke:#4CAF50,stroke-width:2px,color:#fff
    style ANS4 fill:#2d8a2d,stroke:#4CAF50,stroke-width:2px,color:#fff
```

Diagnostic nodes (dark) gather data. Red nodes are destructive actions requiring confirmation. Blue nodes are the Reanalyze and Monitor paths. Orange is the alert display. Green nodes are conclusion displays where the user reads output.

***

## Sample Session

```
  ========================================================================================
   Process Analyst  |  GAIA C++ Agent Framework  |  Local Inference
  ========================================================================================

  Select inference backend:
  [1] GPU  - Qwen3-4B-Instruct-2507-GGUF
  [2] NPU  - Qwen3-4B-Instruct-2507-FLM

  > 1
  Using GPU backend: Qwen3-4B-Instruct-2507-GGUF

  Analyzing your system...

  [1/20] system_snapshot
      Command: Win32 API: memory, disk, processes + PowerShell: CPU, services, connections
      Output:
      .----
      | CPU: 12% load  |  AMD Ryzen 9 7940HS  |  3893 / 5200 MHz
      | Memory: 12.4 GB / 30.4 GB  (41% used)
      | Uptime: 48.3 hrs  |  Processes: 312  |  Connections: 87
      |
      | Disk:
      |   C:\  52% used  |  224.8 GB free of 476.3 GB
      |
      | Top 30 by memory:
      |   msedge.exe                  x28  2.1 GB   <- explorer.exe
      |   Teams.exe                   x8   1.4 GB   <- explorer.exe
      |   cpptools-srv.exe            x2   890 MB   <- vsls-agent.exe
      |   ...
      '----

  [2/20] list_processes
      Command: Win32 API: top 30 by memory + PowerShell: top 10 by CPU time
      ...

  ========================================================================================
  Conclusion
  ========================================================================================

  A. Processes
  Top resource consumers grouped by name, sorted by memory and CPU usage.

  A1  msedge.exe (x28) - 2.1 GB RAM - Microsoft Edge <- explorer.exe [NORMAL]
  A2  Teams.exe (x8) - 1.4 GB RAM - Microsoft Teams <- explorer.exe [HIGH]
  A3  cpptools-srv.exe (x2) - 890 MB RAM - C/C++ IntelliSense <- vsls-agent.exe [NORMAL]
  A4  SearchHost.exe - 456 MB RAM - Windows Search <- svchost.exe [NORMAL]
  A5  explorer.exe - 312 MB RAM - Windows Explorer <- userinit.exe [NORMAL]

  B. Services
  System services with high memory usage (>200 MB) or error/degraded status.

  All services running normally

  C. Suspicious Items
  Unsigned binaries, unknown publishers, or processes running from unexpected locations.

  C1  unknown_app.exe - C:\Users\user\Downloads\unknown_app.exe
      flags: unknown_company, unknown_description, temp_path

  System Health: Warning - One suspicious executable found in Downloads folder

  ========================================================================================

  ========================================================================================
  Available Actions:

  [1] Explain  -- Get details on a process or service
  [2] Stop     -- Kill a process or stop a service
  [3] Restart  -- Restart an app or service
  [4] Quarantine -- Move a suspicious file to quarantine
  [5] Reanalyze  -- Run a fresh system analysis
  [6] Monitor    -- Toggle background health watcher
  ========================================================================================
  Shortcuts: '1 A3' = Explain A3,  '2 B1' = Stop B1,  '4 C1' = Quarantine C1,  '6 5' = Monitor every 5 min

  > 4 C1

  [3/20] explain_item
      Command: Win32 API + PowerShell: explain unknown_app.exe
      Output:
      .----
      | unknown_app.exe  (PID 14228, 1 instance)
      |   Path:        C:\Users\user\Downloads\unknown_app.exe
      |   Parent:      explorer.exe
      |   Memory:      45.2 MB
      |   CPU time:    2.3 sec
      |   Network:     no active connections
      '----

  ========================================================================================
  Conclusion
  ========================================================================================

  Process: unknown_app.exe
  Path: C:\Users\user\Downloads\unknown_app.exe
  Memory: 45.2 MB
  Publisher: Unknown
  Signature: Unsigned
  Reason: Unknown publisher, no description, running from Downloads folder

  Kill unknown_app.exe and quarantine this file? This will terminate the process
  immediately and move the file to C:\ProgramData\GAIA\quarantine\. (yes / no)

  ========================================================================================
  [1] Yes
  [2] No

  > 1

  [4/20] quarantine_item
      Command: Win32 API: TerminateProcess + MoveFileExW(... -> C:\ProgramData\GAIA\quarantine\...)
      Output:
      .----
      | Killed:      unknown_app.exe (1 instance, 45.2 MB freed)
      | Quarantined: C:\Users\user\Downloads\unknown_app.exe
      | Moved to:    C:\ProgramData\GAIA\quarantine\unknown_app.exe.20260309.quarantined
      | File size:   2.8 MB
      '----

  ========================================================================================
  Conclusion
  ========================================================================================

  Action: Quarantine
  Target: unknown_app.exe
  Result: Success

  Terminated 1 instance of unknown_app.exe, freed 45.2 MB. File moved to
  C:\ProgramData\GAIA\quarantine\unknown_app.exe.20260309.quarantined

  ========================================================================================
```

***

## Extending the Agent

Want to add your own tools? The pattern is straightforward. Here's an example that lists Windows startup items:

```cpp theme={null}
// Add this inside registerTools()
toolRegistry().registerTool(
    "check_startup_items",
    "List programs that run at Windows startup — registry Run keys and Startup folder.",
    [](const gaia::json& /*args*/) -> gaia::json {
        std::string output = runShell(
            "Get-CimInstance Win32_StartupCommand "
            "| Select-Object Name, Command, Location "
            "| ConvertTo-Json -Depth 2"
        );
        return {{"tool", "check_startup_items"},
                {"command", "PowerShell: Get-CimInstance Win32_StartupCommand"},
                {"output", output}};
    },
    {}
);
```

The framework automatically appends registered tools to the system prompt — the new tool is available to the LLM immediately. Optionally, add an `ActionEntry` to `kActions[]` if you want a new numbered menu item (e.g., `[7] Startup Items`).

***

## Next Steps

<CardGroup cols={2}>
  <Card title="C++ Framework Overview" icon="code" href="/docs/cpp/overview">
    AgentConfig reference, project structure, and how the agent loop works
  </Card>

  <Card title="Customizing Your Agent" icon="sliders" href="/docs/cpp/custom-agent">
    Custom prompts, typed tools, MCP servers, output capture, and tuning
  </Card>

  <Card title="Integration Guide" icon="puzzle-piece" href="/docs/cpp/integration">
    Use gaia\_core in your own CMake project via FetchContent or find\_package
  </Card>

  <Card title="Wi-Fi Troubleshooter Agent" icon="wifi" href="/docs/cpp/wifi-agent">
    Single-phase diagnostic agent with registered C++ tools
  </Card>
</CardGroup>

***

<small style="color: #666;">
  **License**

  Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.

  SPDX-License-Identifier: MIT
</small>
