# Project export: ARIA (Autonomous IT Response Intelligence Agent)

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2026
- Tagline: Most people require IT for every laptop problem — days of waiting. ARIA fixes it by voice; Deepgram listens, Browserbase verifies, Claude plans, Simulang executes, with your approval for every action.
- Devpost: https://devpost.com/software/aria-autonomous-it-response-intelligence-agent
- GitHub: https://github.com/AarabhiRK/aria
- Video: https://www.youtube.com/embed/zxtmk-BWIHg?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 5 GitHub contributor(s) — Rutu Aarabhi Kuchi (24 commits), Sky (22 commits), Claude Sonnet 4.6 (16 commits), Cursor (10 commits), Melissa Catherine Rajamanuvel (4 commits)

## Devpost submission (written by the team)

### Inspiration

When a cyberattack or IT incident hits, the human response often takes days — days the business stays exposed, damage spreads unchecked, and trust erodes. The average incident takes 3–7 days to fully investigate and resolve. For 90% of small and mid-size businesses, a dedicated 24/7 security team simply isn't affordable. And even when help exists, investigation is slow, manual, and entirely dependent on whoever is available that day. Existing tools detect and alert. They don't investigate and fix in real time — especially not in plain English, especially not for someone who would never open Task Manager. We built ARIA (Autonomous IT Response Intelligence Agent) to close that gap. Any incident. Any machine. Minutes — not days. Speak naturally, get a verified diagnosis, approve each fix, and walk away with a full incident record.

### What it does

ARIA is a voice-first desktop agent that runs an end-to-end incident pipeline on your machine. You describe the problem by voice or text — slow performance, popups, weird startup behavior, anything that feels off. ARIA creates an incident, scans locally (processes, startup items, and other system signals when relevant), and uses Claude to diagnose what's actually going on. Suspicious indicators aren't taken at face value: Browserbase verifies them against live web research before anything is recommended. Before any fix runs, you review and approve each action — kill a process, quarantine a file, block a connection. Nothing destructive happens without your sign-off. Routine fixes run through Python for deterministic operations; OS-level actions can execute via Simulang, which drives the OS through accessibility APIs on macOS and Windows. After remediation, ARIA gives you a spoken summary and saves the incident to local history so you can revisit what happened. The whole loop — report, investigate, verify, plan, approve, fix — is designed for someone who would never open a terminal on their own. ARIA complements tools like Windows Defender: Defender scans for known signatures; ARIA investigates behavior, explains everything in plain English, and fixes what it finds with human oversight. What we handle: Supported actions (including network blocking) are available in the fix engine; our hackathon demos focus on popup, miner, startup, and duplicate-file scenarios via scripts/demo_break.py.

### How we built it

ARIA is a local Electron app with a React frontend and a FastAPI backend orchestrating a multi-stage incident pipeline — everything runs on the user's machine, no second control laptop required. Voice layer (Deepgram): Deepgram powers speech-to-text (live dictation) and text-to-speech (spoken summaries). Users describe problems and approve fixes by voice or text in the dashboard. Orchestrator (Claude): Claude selects investigation targets, analyzes findings, builds atomic fix plans, and runs validation checks. Scout, Investigator, and Fixer are logical roles within a single orchestrator loop — not separate bots. Each recommended action maps back to evidence from the scan, not generic "clean your computer" advice. Threat verification (Browserbase): Suspicious filenames and network indicators are checked via Browserbase Search + Fetch, so verdicts are grounded in external research rather than model guesswork. Investigation (psutil + Python): Fast, deterministic local data collection — processes, network, startup items, recent files — keeps the pipeline responsive while Claude reasons over structured findings. The scan report UI highlights processes and startup items; other signals are collected when the investigation needs them. Remediation (Python + Simulang): Routine fixes (kill process, quarantine, startup removal) run through native Python scripts; complex OS-level actions execute as generated TypeScript scripts via Simulang, using accessibility APIs instead of brittle screen-scraping or vision models. Safety & approval: A validation gate before presentation (validate_fix), protected-process blocklists and system-path guards, and explicit user approval for every action before execution. Users approve decisions one at a time through voice or the dashboard. Frontend: React, TypeScript, Tailwind, Zustand, and Framer Motion — dark cinematic UI, live findings, decision cards, and incident timeline. Incident history stored as local JSON on-device.

### Challenges we ran into

Autonomous fixes need guardrails, not just a smarter model. The scariest failure mode wasn't a crash — it was the agent doing the wrong thing and reporting success. We added independent validation: fix plans must match scan evidence before they're shown, and a safety harness blocks protected OS processes and system paths. False positives on real OS processes. Innocent processes like python.exe, explorer.exe, or dev tools kept showing up as suspicious. We built explicit allowlists and protected-process blocklists so ARIA never kills something that would brick the machine or kill itself mid-demo. Voice ↔ long-running pipeline. A full investigation takes time. We bridged that with streaming progress to the UI and clear spoken updates so the user knows ARIA is working, not stuck. Scope discipline. Our original vision included a two-laptop enterprise setup, Fetch.ai uAgents, Redis, Arize, and Sentry. For the hackathon we cut to a lean single-machine build — and kept the validation gate even when we dropped everything else, because autonomous remediation without guardrails isn't trustworthy. Demo reliability under pressure. A polished UI means nothing if the sick-machine scenario isn't reproducible. Break/cleanup scripts saved us more time than chasing edge cases nobody would see in a five-minute judge visit.

### Accomplishments we're proud of

Real end-to-end flow on a real machine — voice in, verified diagnosis, gated remediation out. Not a mock dashboard. Minutes, not days — full investigate → verify → approve → fix loop completes in under ~2 minutes for our scripted demo scenarios. Human-in-the-loop at the action level — users approve each kill, quarantine, and block individually, not a blanket "fix everything." Sponsor integrations that each do real work — Deepgram for voice, Browserbase for verification, Simulang for execution. Claude isn't a chat wrapper — it is the reasoning engine. Accessible by design — voice-first so any employee, regardless of technical skill, can report and resolve incidents. Safety as first-class engineering — validation gates, protected-process blocklists, and pytest coverage for the safety harness. Reproducible demos — we can plant a sick-laptop scenario, run ARIA live, and clean up reliably every time.

### What we learned

Autonomous remediation is less about picking the best LLM and more about where you put the gates. Validation before presentation and explicit approval before every execution matter more than clever prompts. Splitting investigation (fast, deterministic collection with psutil) from execution (Python for routine fixes, Simulang for complex OS actions) kept the pipeline responsive and fixes reliable. Reproducibility beats perfection. Scripts to break and un-break the machine matter more than polish on edge cases. Honest limitations build judge trust. No fleet dashboard, no rollback yet, local-only audit trail — naming these made our design story stronger, not weaker.

### What's next

Fleet & IT visibility — central dashboard so IT teams see what happened across machines Rollback & recovery — undo path if an approved fix goes wrong Enterprise deployment — ARIA control plane connecting to endpoints across a local network (our original two-machine vision) The core vision stays the same: "Your AI IT Department. Any Incident. Any Machine. Minutes — Not Days." Anyone should be able to talk to their laptop and get it fixed safely — without waiting on IT for every popup.

## README (from the GitHub repository)

# ARIA

**Autonomous IT Response Intelligence Agent**

*Your AI IT department. Any incident. Any machine. Minutes — not days.*

ARIA is a voice-first desktop agent that investigates and fixes laptop problems locally. Describe an issue by voice or text — slow performance, popups, suspicious network activity — and ARIA scans your machine, verifies threats with Browserbase, plans fixes with Claude, and remediates approved actions. **Nothing destructive runs without your approval on each action.**

---

## How it works

1. **Report** — Speak or type the problem (Deepgram Voice Agent).
2. **Investigate** — Collect processes, network, startup items, and recent files locally (psutil).
3. **Verify** — Check suspicious indicators via Browserbase Search + Fetch.
4. **Diagnose & plan** — Claude analyzes findings and builds an evidence-backed fix plan.
5. **Approve** — Review each kill / quarantine / block decision in the UI or by voice.
6. **Remediate** — Execute approved actions via native Python and Simulang.
7. **Close** — Spoken summary + incident saved to local history.

---

## Prerequisites

| Requirement | Version |
|-------------|---------|
| Python | 3.12+ |
| Node.js | 22.18+ |
| npm | 10+ |

**API keys** (required):

- [Anthropic](https://console.anthropic.com/) — Claude orchestrator
- [Deepgram](https://console.deepgram.com/) — voice STT, TTS, and Voice Agent
- [Browserbase](https://www.browserbase.com/) — threat verification and fix research

**Global tool** (recommended for GUI remediation):

- [Simulang](https://www.npmjs.com/package/@simular-ai/simulang) `@6.0.0` — OS automation for complex fixes

**Platforms:** macOS and Windows.

---

## Quick start

### 1. Clone and enter the repo

```bash
git clone https://github.com/AarabhiRK/aria.git
cd aria
```

### 2. Install dependencies

```bash
pip install -r requirements.txt
npm install
npm install -g @simular-ai/simulang@6.0.0
```

**macOS only** — grant Simulang permissions once:

```bash
simulang setup
```

**Windows** — no setup command needed. If `simulang run` fails with a load error, unblock the native binary:

```powershell
Get-ChildItem -Recurse (npm root -g) | Unblock-File
```

### 3. Configure environment

Copy the example env file and add your API keys:

```bash
cp .env.example .env
```

On Windows PowerShell:

```powershell
Copy-Item .env.example .env
```

Edit `.env` and replace the placeholder values:

- `DEEPGRAM_API_KEY`
- `ANTHROPIC_API_KEY`
- `BROWSER_BASE_API_KEY`

`.env` is gitignored — never commit real keys.

### 4. Run the app

Open **two terminals** from the repo root:

```bash
# Terminal 1 — FastAPI backend (port 8787)
npm run backend
```

```bash
# Terminal 2 — Electron desktop UI
npm run dev
```

The ARIA window opens automatically. The sidebar shows **Systems online** when the backend is reachable.

### 5. Try it

1. Click **Start session** on the welcome screen.
2. Type or speak a problem (e.g. *"My laptop is slow"* or *"I keep getting popups"*).
3. Wait for the scan (~1 minute). Review the diagnosis and proposed fixes.
4. **Approve** or **Skip** each fix. When all are reviewed, approved fixes apply automatically.
5. Open **History** for past incidents or **Quarantine** for moved files.

---

## Demo scenarios

Plant harmless fake problems for a repeatable demo, then clean up afterward.

```bash
# Plant a scenario (popup | miner | startup | duplicates | all)
python scripts/demo_break.py popup

# Remove all demo artifacts when done
python scripts/demo_cleanup.py
```

| Scenario | What it simulates | Expected fix |
|----------|-------------------|--------------|
| `popup` | High-CPU adware process + startup entry | kill process, remove startup |
| `miner` | Cryptominer CPU load | kill process |
| `startup` | Fake persistence registry entry | remove startup |
| `duplicates` | Extra copies in Downloads | quarantine files |
| `all` | popup + miner + startup combined | multiple fixes |

Example prompts after running a scenario:

- popup: *"I keep getting suspicious popups"*
- miner: *"My laptop is running hot and slow"*
- startup: *"Something launches at startup that I don't recognize"*
- duplicates: *"My Downloads folder is full of duplicate files"*

Verify demo fixes end-to-end:

```bash
python scripts/verify_demos.py
```

---

## Project layout

```
aria/
├── backend/          FastAPI server, orchestrator, voice agent, decisions
├── electron/           Electron main process
├── sick_machine/       Local collection (psutil) + remediation execution
├── src/                React + TypeScript desktop UI
├── scripts/            Demo break / cleanup / verify
├── tests/              Python test suite
└── docs/               Architecture diagram and API contract
```

---

## Development

```bash
npm run typecheck          # TypeScript check
python -m pytest tests/  # Backend tests (82 tests)
npm run build              # Production Electron build
```

Backend health check: `http://localhost:8787/health`

---

## Privacy

All incident data is stored locally under `~/.aria/incidents/`. Nothing is synced to the cloud except API calls to Anthropic, Deepgram, and Browserbase during an active session.


## Detected evidence (automated analysis)

Indexed codebase: 107 recognized source files, 447 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- AI coding agent: Claude Code — evidence: commit authorship or trailers
- AI coding agent: Cursor — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (117 of 117)

```
.env.example
.gitignore
.gitmodules
.vscode/settings.json
backend/__init__.py
backend/adapters.py
backend/agent_settings.py
backend/agents/__init__.py
backend/agents/research.py
backend/aria_agent.py
backend/decisions.py
backend/events.py
backend/incident_store.py
backend/INTEGRATION_SKY.md
backend/main.py
backend/orchestrator_routes.py
backend/pipeline_progress.py
backend/registry.py
backend/schemas.py
backend/static/voice_test.html
backend/test_agent_settings.py
backend/test_browserbase.py
backend/tools.py
backend/voice_agent.py
backend/voice_bridge.py
backend/voice_tools.py
backend/voice.py
docs/API-CONTRACT.md
docs/aria_sequence_flow.mermaid
docs/PRD-v3.md
electron.vite.config.ts
electron/main.ts
electron/preload.ts
index.html
package.json
postcss.config.js
pytest.ini
README.md
requirements.txt
scripts/demo_break.py
scripts/demo_cleanup.py
scripts/verify_demos.py
sick_machine/__init__.py
sick_machine/agent.py
sick_machine/demo_setup.py
src/App.tsx
src/components/incident/ActionProgress.tsx
src/components/incident/DiagnosisPanel.tsx
src/components/incident/FindingCard.tsx
src/components/incident/FixPlanCard.tsx
src/components/incident/ThreatBadge.tsx
src/components/layout/AppShell.tsx
src/components/layout/IncidentStepper.tsx
src/components/layout/PageContent.tsx
src/components/layout/ScrollableListCard.tsx
src/components/layout/Sidebar.tsx
src/components/ui/badge.tsx
src/components/ui/button.tsx
src/components/ui/card.tsx
src/components/ui/progress.tsx
src/components/ui/separator.tsx
src/components/voice/AgentStatusBar.tsx
src/components/voice/ARIAFace.tsx
src/components/voice/ChatComposer.tsx
src/components/voice/ConversationPanel.tsx
src/components/voice/DecisionCard.tsx
src/components/voice/DecisionProgressBar.tsx
src/components/voice/DiagnosisSummaryCard.tsx
src/components/voice/ScanProgressPanel.tsx
src/components/voice/SessionWelcome.tsx
src/components/voice/TelemetryPanel.tsx
src/components/voice/VoiceButton.tsx
src/index.css
src/lib/api/analysis.ts
src/lib/api/client.ts
src/lib/api/decisions.ts
src/lib/api/incident.ts
src/lib/api/investigation.ts
src/lib/api/quarantine.ts
src/lib/api/remediation.ts
src/lib/api/types.ts
src/lib/api/voice.ts
src/lib/audio/pcm.ts
src/lib/audio/transcript.ts
src/lib/hooks/useIncident.ts
src/lib/hooks/useInvestigationStream.ts
src/lib/hooks/usePipelineStream.ts
src/lib/hooks/useVoice.ts
src/lib/hooks/useVoiceAgent.ts
src/lib/utils.ts
src/lib/voiceSessionStorage.ts
src/main.tsx
src/pages/ApprovalPage.tsx
src/pages/CompletePage.tsx
src/pages/DiagnosisPage.tsx
src/pages/HistoryPage.tsx
src/pages/HomePage.tsx
src/pages/IncidentDashboardPage.tsx
src/pages/InvestigationPage.tsx
src/pages/QuarantinePage.tsx
src/pages/RemediationPage.tsx
src/pages/ScanReportPage.tsx
src/stores/conversationStore.ts
src/stores/incidentStore.ts
src/stores/telemetryStore.ts
src/vite-env.d.ts
tailwind.config.ts
tests/__init__.py
tests/test_agent_collectors.py
tests/test_aria_agent.py
tests/test_decisions_quarantine.py
tests/test_execute_action.py
tests/test_remediation.py
tests/test_safety_harness.py
tests/test_tools.py
tsconfig.json
tsconfig.node.json
```

### Dependencies

- package.json: @radix-ui/react-progress@^1.1.2, @radix-ui/react-separator@^1.1.2, @radix-ui/react-slot@^1.1.2, @types/react@^18.3.18, @types/react-dom@^18.3.5, @vitejs/plugin-react@^4.3.4, autoprefixer@^10.4.20, class-variance-authority@^0.7.1, clsx@^2.1.1, electron@^34.2.0, electron-vite@^3.0.0, framer-motion@^12.4.7, lucide-react@^0.475.0, postcss@^8.5.2, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^7.2.0, tailwind-merge@^3.0.1, tailwindcss@^3.4.17, typescript@^5.7.3, vite@^6.1.0, zustand@^5.0.3
- requirements.txt: anthropic@>=0.40.0, browserbase@>=1.11.0, deepgram-sdk@==7.3.1, fastapi@>=0.115.0, httpx@>=0.27.0, psutil@>=6.0.0, pydantic@>=2.0.0, pytest@>=8.0.0, pytest-asyncio@>=0.23.0, python-dotenv@>=1.0.0, sounddevice@>=0.5.5, uvicorn[standard]@>=0.30.0, websockets@>=13.0

### Recent commits (newest first)

- fixed readme
- README fixed
- Merge pull request #5 from AarabhiRK/frontend
- frontend fixes
- Show generated script in DecisionCard with collapsible View script toggle
- Merge branch 'main' of https://github.com/AarabhiRK/aria
- 4 Python demos (no Simulang) working
- Fix CompletePage remount loop and ensure post-fix message always shows.
- Merge origin/main (Sky frontend PR) with remediation and demo scenario fixes.
- Make all four hackathon demo scenarios reliably detectable and fixable.
- Merge pull request #4 from AarabhiRK/frontend
- Fix backend script signal handling for clean Ctrl+C shutdown
- Revert "Consolidate aria message + TTS into single sayAndShow helper"
- Expand ~ in quarantine script target path
- Consolidate aria message + TTS into single sayAndShow helper
- Fix execute-approved crash from missing import and improve quarantine path resolution.
- Fix infinite loop on CompletePage
- Fix remediation execution and demo-ready voice agent UX.
- Add quarantine console with restore and delete
- Allow execute-approved on needs_review incidents

## Key source files (fetched from GitHub, selected and truncated for size)

### docs/PRD-v3.md

```markdown
# ARIA — Product Requirements Document v3

Lean single-app, single-machine build. Standalone app installed on the machine it protects. Sarah reports a problem by voice, ARIA investigates and fixes it locally, end to end.

## Scope Note

Compared to earlier drafts, this version drops Redis, Fetch/uAgents, Sentry, and Arize. No fleet-wide visibility — incident history is local to each machine. Result validation stays in (Workstream 6) as plain app logic.

## Function-Level API

See [API-CONTRACT.md](./API-CONTRACT.md) for the full REST mapping.

- **Voice:** `speech_to_text()`, `text_to_speech()` — Deepgram + Aura
- **Incident:** `create_incident()`, `get_device_history()`, `save_incident()`
- **Investigation:** `collect_system_data()` — Agent S per target
- **Analysis:** `analyze_findings()` — Claude; `check_reputation()` — Browserbase/VirusTotal
- **Fix planning:** `build_fix_plan()`, `validate_fix()`
- **Approval:** `present_findings()`, `capture_approval()`
- **Remediation:** `compose_instruction()` → `execute()` → `validate_result()` per action
- **Closing:** `assess_damage()`, `generate_prevention_plan()`

## Workstreams

1. Voice interface (Deepgram)
2. Incident lifecycle & local storage
3. Investigation (Agent S)
4. Analysis & threat verification
5. Fix planning
6. Validation gate
7. Approval flow
8. Remediation
9. Damage assessment & closing

## Open Risks

- No fleet-wide audit trail
- No rollback/undo
- Sarah is sole approver — no IT escalation path
- Reimage path out of scope

```

### backend/INTEGRATION_SKY.md

```markdown
# Sky — orchestrator integration contract

Sky's `run_pipeline()` should call these endpoints after Agent S investigation.

## 1. Threat verification (Browserbase)

```
POST /api/threat/check
Content-Type: application/json

{
  "indicator": "demo_popup.exe",
  "kind": "filename"
}
```

`kind` is `"filename"` or `"ip"`.

Response:

```json
{
  "malicious": true,
  "source": "Browserbase Search + Fetch",
  "confidence": 0.85,
  "indicator": "demo_popup.exe",
  "evidence_url": "https://...",
  "summary": "...",
  "used_fallback": false
}
```

## 2. Fix research (Browserbase)

```
POST /api/agents/research
Content-Type: application/json

{
  "symptoms": "slow laptop and weird popups",
  "findings": ["demo_popup.exe in startup", "high CPU"]
}
```

Response:

```json
{
  "recommended_steps": [
    "Open Task Manager and end the demo_popup process.",
    "Remove the suspicious startup entry."
  ],
  "sources": ["https://..."],
  "query": "how to fix ...",
  "used_fallback": false
}
```

## 3. Voice entry (already wired)

```
POST /api/orchestrator/run

{ "message": "user problem", "session_id": "abc" }

→ { "spoken_report": "...", "status": "..." }
```

## Suggested pipeline order

1. `create_incident(transcript)`
2. Agent S `collect_system_data()`
3. `POST /api/threat/check` for each suspicious indicator
4. Claude `analyze_findings()`
5. `POST /api/agents/research`
6. Claude `build_fix_plan()` + `validate_fix()`
7. User approval
8. Agent S `execute()` per action
9. Return `spoken_report` for Deepgram

## curl smoke tests

```powershell
curl http://localhost:8000/api/browserbase/status

curl -X POST http://localhost:8000/api/threat/check ^
  -H "Content-Type: application/json" ^
  -d "{\"indicator\":\"demo_popup.exe\",\"kind\":\"filename\"}"

curl -X POST http://localhost:8000/api/agents/research ^
  -H "Content-Type: application/json" ^
  -d "{\"symptoms\":\"slow laptop and popups\",\"findings\":[\"demo_popup.exe\"]}"
```

```

### requirements.txt

```
anthropic>=0.40.0
browserbase>=1.11.0
deepgram-sdk==7.3.1
fastapi>=0.115.0
httpx>=0.27.0
psutil>=6.0.0
pydantic>=2.0.0
pytest>=8.0.0
pytest-asyncio>=0.23.0
python-dotenv>=1.0.0
sounddevice>=0.5.5
uvicorn[standard]>=0.30.0
websockets>=13.0

```

### package.json

```
{
  "name": "aria",
  "version": "1.0.0",
  "description": "ARIA — local AI security assistant",
  "main": "./out/main/index.js",
  "type": "module",
  "scripts": {
    "dev": "electron-vite dev",
    "backend": "node -e \"const {spawn}=require('child_process');const py=process.platform==='win32'?'python':'python3';const c=spawn(py,['-m','backend.main'],{stdio:'inherit'});process.on('SIGINT',()=>c.kill('SIGINT'));process.on('SIGTERM',()=>c.kill('SIGTERM'));c.on('exit',(code)=>process.exit(code??0))\"",
    "build": "electron-vite build",
    "preview": "electron-vite preview",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@radix-ui/react-progress": "^1.1.2",
    "@radix-ui/react-separator": "^1.1.2",
    "@radix-ui/react-slot": "^1.1.2",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "framer-motion": "^12.4.7",
    "lucide-react": "^0.475.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^7.2.0",
    "tailwind-merge": "^3.0.1",
    "zustand": "^5.0.3"
  },
  "devDependencies": {
    "@types/react": "^18.3.18",
    "@types/react-dom": "^18.3.5",
    "@vitejs/plugin-react": "^4.3.4",
    "autoprefixer": "^10.4.20",
    "electron": "^34.2.0",
    "electron-vite": "^3.0.0",
    "postcss": "^8.5.2",
    "tailwindcss": "^3.4.17",
    "typescript": "^5.7.3",
    "vite": "^6.1.0"
  }
}

```

### src/main.tsx

```typescript
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

```

### electron/main.ts

```typescript
import { app, BrowserWindow, shell } from 'electron'
import { join } from 'path'
import { fileURLToPath } from 'url'

const __dirname = fileURLToPath(new URL('.', import.meta.url))

const isDev = !app.isPackaged

function createWindow(): void {
  const mainWindow = new BrowserWindow({
    width: 1280,
    height: 840,
    minWidth: 960,
    minHeight: 640,
    show: false,
    autoHideMenuBar: true,
    backgroundColor: '#0f1218',
    title: 'ARIA',
    webPreferences: {
      preload: join(__dirname, '../preload/index.mjs'),
      sandbox: false,
      contextIsolation: true,
      nodeIntegration: false
    }
  })

  mainWindow.on('ready-to-show', () => {
    mainWindow.show()
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })

  if (isDev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }
}

app.whenReady().then(() => {
  createWindow()

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

```

### src/App.tsx

```typescript
import { useEffect } from 'react'
import { HashRouter, Routes, Route, Navigate } from 'react-router-dom'
import { AppShell } from '@/components/layout/AppShell'
import { HomePage } from '@/pages/HomePage'
import { IncidentDashboardPage } from '@/pages/IncidentDashboardPage'
import { InvestigationPage } from '@/pages/InvestigationPage'
import { DiagnosisPage } from '@/pages/DiagnosisPage'
import { ApprovalPage } from '@/pages/ApprovalPage'
import { RemediationPage } from '@/pages/RemediationPage'
import { CompletePage } from '@/pages/CompletePage'
import { HistoryPage } from '@/pages/HistoryPage'
import { QuarantinePage } from '@/pages/QuarantinePage'
import { ScanReportPage } from '@/pages/ScanReportPage'
import { checkBackendHealth } from '@/lib/api/client'
import { useIncidentStore } from '@/stores/incidentStore'

function BackendHealthCheck() {
  const setBackendConnected = useIncidentStore((s) => s.setBackendConnected)

  useEffect(() => {
    let consecutiveFailures = 0
    let mounted = true

    const check = async () => {
      const ok = await checkBackendHealth()
      if (!mounted) return
      if (ok) {
        consecutiveFailures = 0
        setBackendConnected(true)
        return
      }
      consecutiveFailures += 1
      // One slow health probe during a scan should not flash "Backend offline".
      if (consecutiveFailures >= 2) {
        setBackendConnected(false)
      }
    }

    check()
    const interval = setInterval(check, 5000)
    return () => {
      mounted = false
      clearInterval(interval)
    }
  }, [setBackendConnected])

  return null
}

export default function App() {
  return (
    <HashRouter>
      <div className="flex h-full min-h-0 flex-col overflow-hidden">
        <BackendHealthCheck />
        <div className="flex h-full min-h-0 flex-1 flex-col overflow-hidden">
        <Routes>
        <Route element={<AppShell />}>
          <Route index element={<HomePage />} />
          <Route path="history" element={<HistoryPage />} />
          <Route path="quarantine" element={<QuarantinePage />} />
          <Route path="incident/:id" element={<IncidentDashboardPage />} />
          <Route path="incident/:id/investigation" element={<InvestigationPage />} />
          <Route path="incident/:id/scan-report" element={<ScanReportPage />} />
          <Route path="incident/:id/diagnosis" element={<DiagnosisPage />} />
          <Route path="incident/:id/approval" element={<ApprovalPage />} />
          <Route path="incident/:id/remediation" element={<RemediationPage />} />
          <Route path="incident/:id/complete" element={<CompletePage />} />
        </Route>
        <Route path="report" element={<Navigate to="/" replace />} />
        <Route path="*" element={<Navigate to="/" replace />} />
        </Routes>
        </div>
      </div>
    </HashRouter>
  )
}

```

### backend/main.py

```python
"""
ARIA backend — Deepgram voice + Claude orchestrator + Browserbase + frontend REST.
"""

from __future__ import annotations

import logging
import os
import sys
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Literal

_REPO_ROOT = Path(__file__).resolve().parent.parent
if str(_REPO_ROOT) not in sys.path:
    sys.path.insert(0, str(_REPO_ROOT))

from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Query, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, Response
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel, Field

from backend import incident_store
from backend.agents.research import check_reputation, get_browserbase_api_key, research_problem
from backend.orchestrator_routes import router as orchestrator_router
from backend.registry import list_incidents, lookup_device, start_incident
from backend.schemas import ResearchRequest, ResearchResult, ThreatCheckRequest, ThreatVerdict
from backend.tools import load_incident
from backend.voice import TTS_ENCODING, VoiceService
from backend.voice_agent import VoiceAgentService
from backend.voice_bridge import (
    prepare_investigation,
    run_approve_from_voice,
    run_investigation_by_id,
    run_investigation_from_voice,
)

load_dotenv(_REPO_ROOT / ".env")

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

BACKEND_DIR = Path(__file__).resolve().parent
STATIC_DIR = BACKEND_DIR / "static"
BACKEND_PORT = int(os.getenv("ARIA_BACKEND_PORT") or "8787")


@asynccontextmanager
async def lifespan(app: FastAPI):
    api_key = os.getenv("DEEPGRAM_API_KEY")
    if not api_key:
        logger.warning("DEEPGRAM_API_KEY is not set; voice routes will fail.")
    if not os.getenv("ANTHROPIC_API_KEY"):
        logger.warning("ANTHROPIC_API_KEY is not set; investigation/analysis routes will fail.")
    if not get_browserbase_api_key():
        logger.warning(
            "BROWSER_BASE_API_KEY is not set; investigation requires Browserbase "
            "for threat verification and fix research."
        )

    app.state.voice = VoiceService(api_key=api_key)
    app.state.voice_agent = VoiceAgentService(api_key=api_key)

    async def on_final_transcript(text: str, session_id: str) -> dict:
        logger.info("Final transcript [%s]: %s", session_id, text)
        result = await run_investigation_from_voice(text)
        logger.info("Investigation [%s]: %s", session_id, result.get("spoken_report", ""))
        return result

    app.state.voice.set_final_transcript_handler(on_final_transcript)
    yield


app = FastAPI(title="ARIA", version="0.2.0", lifespan=lifespan)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

if STATIC_DIR.is_dir():
    app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")

app.include_router(orchestrator_router)


class SpeakRequest(BaseModel):
    text: str = Field(min_length=1)
    session_id: str | None = None


class DeviceLookupRequest(BaseModel):
    employee_name: str = Field(min_length=1)


class StartIncidentRequest(BaseModel):
    employee_name: str = Field(min_length=1)
    symptoms: str = Field(min_length=1)


class CreateIncidentRequest(BaseModel):
    transcript: str = Field(min_length=1)
    deviceId: str = Field(min_length=1)


class PipelineRequest(BaseModel):
    transcript: str = Field(min_length=1)
    deviceId: str = "local-laptop"
    operatingSystem: Literal["windows", "macos"] = "windows"


class OrchestratorRunRequest(BaseModel):
    # Accept both "message" and "transcript" — voice agent sends "message",
    # REST clients often send "transcript".
    message: str = Field(default="", min_length=0)
    transcript: str = Field(default="", min_length=0)
    session_id: str | None = None
    deviceId: str = "local-laptop"

    @property
    def text(self) -> str:
        return self.message or self.transcript


class ApprovalResponse(BaseModel):
    incident_id: str
    status: str
    summary: str
    remaining_threats: list[str] = Field(default_factory=list)
    prevention_plan: str = ""
    action_results: list[dict] = Field(default_factory=list)
    spoken_report: str | None = None


@app.get("/health")
async def health() -> dict[str, str | bool]:
    return {
        "status": "ok",
        "service": "aria",
        "deepgram_configured": bool(os.getenv("DEEPGRAM_API_KEY")),
        "anthropic_configured": bool(os.getenv("ANTHROPIC_API_KEY")),
        "browserbase_configured": bool(get_browserbase_api_key()),
        "voice_agent_llm": "deepgram_managed",
    }


@app.get("/api/browserbase/status")
async def browserbase_status() -> dict:
    configured = bool(get_browserbase_api_key())
    return {
        "configured": configured,
        "message": "Browserbase API key found" if configured else "Set BROWSER_BASE_API_KEY in .env",
    }


@app.post("/api/threat/check", response_model=ThreatVerdict)
async def threat_check(body: ThreatCheckRequest) -> ThreatVerdict:
    return await check_reputation(body.indicator, body.kind)


@app.post("/api/agents/research", response_model=ResearchResult)
async def agents_research(body: ResearchRequest) -> ResearchResult:
    return await research_problem(body.symptoms, body.findings)


@app.get("/dev/voice")
async def voice_dev_page() -> FileResponse:
    return FileResponse(str(STATIC_DIR / "voice_test.html"))


@app.websocket("/ws/voice/listen")
async def voice_listen(websocket: WebSocket, dictate: bool = Query(False)) -> None:
    voice: VoiceService = app.state.voice
    await voice.bridge_listen_websocket(websocket, auto_investigate=not dictate)


@app.websocket("/ws/voice/agent")
async def voice_agent(websocket: WebSocket) -> None:
    agent: VoiceAgentService = app.state.voice_agent
    await agent.bridge_websocket(websocket)


async def _synthesize(body: SpeakRequest) -> Res
[truncated — 9026 more characters]
```

### postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {}
  }
}

```

### index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ARIA</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

[95 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]