Skip to content

ASR4/omni-graph

Repository files navigation

OmniGraph

Know what you've shared with AI. OmniGraph is an open-source AI interaction tracker that gives you a timeline and knowledge graph of every message you send to ChatGPT, Claude, Gemini, Copilot, and other AI tools.

A browser extension silently captures outbound messages. A dashboard classifies them by sensitivity, maps data subjects, and visualizes your cumulative AI exposure — so you always know what went where.


Why

AI tools are everywhere. You paste code into ChatGPT, share financials with Claude, drop resumes into Copilot. But nobody tracks the cumulative picture:

  • What sensitive data have you shared?
  • With which services?
  • When did it happen?
  • How exposed are specific people, projects, or credentials?

OmniGraph answers these questions with a passive browser extension and a visual dashboard. No proxies, no browser profile changes — just install and browse.


How It Works

┌─────────────────────────────────────────────────────────────────┐
│                   BROWSER EXTENSION (MV3)                       │
│                                                                 │
│  ┌─────────────┐   ┌──────────┐   ┌──────────────────────────┐ │
│  │ Interceptor  │   │  Bridge  │   │   Background Worker      │ │
│  │ (MAIN world) │──▶│(ISOLATED)│──▶│ Dedup · Batch · Retry    │ │
│  │ fetch / XHR  │   │  relay   │   │ IndexedDB persistence    │ │
│  │ WebSocket    │   │          │   │                          │ │
│  └─────────────┘   └──────────┘   └───────────┬──────────────┘ │
│  ┌─────────────┐                               │                │
│  │ DOM Observer │───────────────────────────────┘                │
│  │ Input / Paste│                                               │
│  └─────────────┘                                                │
└─────────────────────────────────────────────────────────────────┘
                                │
                          POST /api/ingest
                                │
┌─────────────────────────────────────────────────────────────────┐
│                     NEXT.JS BACKEND                             │
│                                                                 │
│  ┌─────────────────┐   ┌──────────────┐   ┌──────────────────┐ │
│  │ Ingest API       │   │  Classifier  │   │  Graph API       │ │
│  │ Zod validation   │──▶│  OpenAI      │──▶│  CRUD + Search   │ │
│  │ Rate limiting    │   │  Queue       │   │  Timeline        │ │
│  │ Bearer auth      │   │  Retry       │   │  Stats           │ │
│  └─────────────────┘   └──────────────┘   └──────────────────┘ │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                     FalkorDB                              │   │
│  │  Service ← SENT_TO ← Disclosure → MENTIONS → DataSubject │   │
│  │                         │                                 │   │
│  │                    CONTAINS → DataCategory                │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                                │
                          Dashboard UI
                                │
┌─────────────────────────────────────────────────────────────────┐
│                        DASHBOARD                                │
│                                                                 │
│  Dashboard         Timeline         Exposure Graph              │
│  Stats & trends    Chronological    Interactive knowledge graph  │
│  Service breakdown Search & filter  Node inspector              │
│  Sensitivity bars  CSV export       Zoom & pan                  │
└─────────────────────────────────────────────────────────────────┘

Detection Architecture

OmniGraph uses dual-layer capture for reliability:

  1. Network interception — Monkey-patches fetch, XMLHttpRequest, and WebSocket in the page's MAIN world to capture outbound API calls to AI services.
  2. DOM observation — A MutationObserver watches for editable elements (textareas, contenteditable divs) and captures input/paste events as a fallback.

Events from both layers are deduplicated by content hash within a 3-second window, batched, persisted to IndexedDB, and sent to the backend with exponential-backoff retry.

Supported AI Services

Service Network Capture DOM Capture
ChatGPT (chat.openai.com, chatgpt.com)
Claude (claude.ai)
Gemini (gemini.google.com)
Copilot (copilot.microsoft.com)
Perplexity (perplexity.ai)
Harvey (app.harvey.ai)
Clay (app.clay.com)
Jasper (app.jasper.ai)
Notion AI (notion.so)

Adding a new service requires a small entry in extension/src/services/registry.js.


Quick Start

Prerequisites

Tool Version Check
Node.js 20+ node --version
Docker 24+ docker --version
Chrome/Chromium Latest
OpenAI API Key platform.openai.com

1. Clone and install

git clone https://github.com/ASR4/omni-graph.git
cd omni-graph
npm install

2. Start FalkorDB

docker compose up -d

Verify:

docker exec omnigraph-falkordb redis-cli -a omnigraph-dev-password ping
# Expected: PONG

3. Configure environment

cp .env.example .env

Set your OpenAI API key in .env:

OPENAI_API_KEY=sk-proj-your-key-here

Everything else has working defaults. See Environment Variables for the full reference.

4. Start the dev server

npm run dev

Dashboard is at http://localhost:3001.

5. Load the browser extension

  1. Open chrome://extensions in Chrome
  2. Enable Developer mode (top-right toggle)
  3. Click Load unpacked
  4. Select the extension/ directory from this repo

The OmniGraph icon appears in your toolbar. Click it to see the popup with status and controls.

6. Use any AI tool

Open ChatGPT, Claude, or any supported service and send a message. Within seconds, it appears on your OmniGraph dashboard timeline.


Environment Variables

Variable Purpose Required Default
OPENAI_API_KEY Classification via OpenAI Yes
INGEST_API_KEY Shared secret for extension auth No (auth disabled)
FALKORDB_HOST Graph database host No localhost
FALKORDB_PORT Graph database port No 6379
FALKORDB_PASSWORD FalkorDB/Redis password No omnigraph-dev-password
FALKORDB_GRAPH_NAME Graph name in FalkorDB No omnigraph
AUTH_SECRET NextAuth JWT signing secret Yes (prod) change-me-to-a-random-secret
OMNIGRAPH_PASSWORD Dashboard login password No (auth disabled)
LOG_LEVEL Pino log level No info

Generate secrets with: openssl rand -base64 32

If INGEST_API_KEY is set, the extension must send it as a Bearer token. If unset, the ingest endpoint accepts all requests (suitable for local dev).


Project Structure

omni-graph/
├── extension/                          # Chrome MV3 browser extension
│   ├── manifest.json                   # Extension config and permissions
│   ├── icons/                          # Extension icons (16, 48, 128px)
│   └── src/
│       ├── interceptor.js              # MAIN world: fetch/XHR/WS monkey-patching
│       ├── bridge.js                   # ISOLATED world: relay to service worker
│       ├── background.js               # Service worker: dedup, batch, retry, IndexedDB
│       ├── popup.html                  # Toolbar popup UI
│       ├── popup.js                    # Popup logic and state
│       ├── services/
│       │   └── registry.js             # AI service definitions and body parsers
│       └── content/
│           ├── element-discovery.js    # DOM observer for input detection
│           └── adapters/              # Service-specific DOM adapters
│               ├── chatgpt.js
│               ├── claude.js
│               └── gemini.js
├── src/
│   ├── app/                            # Next.js App Router
│   │   ├── page.tsx                    # Dashboard: stats, breakdowns, recent activity
│   │   ├── timeline/page.tsx           # Timeline: chronological feed, search, export
│   │   ├── graph/page.tsx              # Graph: interactive exposure map
│   │   ├── login/page.tsx              # Authentication
│   │   └── api/
│   │       ├── ingest/route.ts         # Extension → server ingestion
│   │       ├── graph/route.ts          # Graph data, search, timeline, stats
│   │       ├── health/route.ts         # System health check
│   │       └── auth/[...nextauth]/     # NextAuth handlers
│   ├── components/
│   │   ├── graph/
│   │   │   ├── GraphCanvas.tsx         # Graph visualization container
│   │   │   ├── CosmographWrapper.tsx   # Cosmograph WebGL renderer
│   │   │   └── NodeDetail.tsx          # Node inspector panel
│   │   └── ui/                         # shadcn/ui primitives
│   ├── lib/
│   │   ├── types.ts                    # TypeScript type definitions
│   │   ├── falkordb.ts                 # FalkorDB client and Cypher helpers
│   │   ├── classifier.ts              # OpenAI-based content classification
│   │   ├── classifier-queue.ts        # Async classification queue with retry
│   │   ├── rate-limit.ts              # Token bucket rate limiter
│   │   ├── auth.ts                     # NextAuth configuration
│   │   ├── logger.ts                   # Pino structured logging
│   │   ├── api-error.ts               # Safe error responses
│   │   ├── constants.tsx              # UI constants (icons, colors)
│   │   └── graph/
│   │       ├── schema.ts              # Node/edge types, colors, sizes
│   │       └── operations.ts          # Graph CRUD, search, timeline, stats
│   ├── middleware.ts                   # Route protection
│   ├── instrumentation.ts             # Startup: re-queue unclassified disclosures
│   └── __tests__/                      # Vitest test suite
│       ├── rate-limit.test.ts
│       ├── classifier.test.ts
│       └── ingest-validation.test.ts
├── docker-compose.yml                  # FalkorDB with persistence and auth
├── Dockerfile                          # Multi-stage production build
├── vitest.config.ts
├── .env.example                        # Environment variable reference
└── package.json

Graph Data Model

OmniGraph stores disclosures in a property graph with four node types and four edge types:

(Service) ←[SENT_TO]← (Disclosure) →[MENTIONS]→ (DataSubject)
                            │
                       [CONTAINS]
                            ↓
                      (DataCategory)

(DataSubject) ←[EXPOSED_TO]→ (Service)
Node Description Example
Service An AI tool or SaaS product ChatGPT, Claude, Gemini
Disclosure A single message sent to a service "Here's our Q4 revenue..."
DataSubject A person, company, project, or product mentioned "John Smith", "Acme Corp"
DataCategory Type of sensitive data contained PII, Financial, Code, Credentials

Sensitivity levels: LOW, MEDIUM, HIGH, CRITICAL — assigned by the OpenAI classifier.


API Reference

POST /api/ingest

Receives disclosure batches from the browser extension. Validates with Zod, stores in FalkorDB, queues for classification.

{
  "disclosures": [
    {
      "id": "uuid",
      "service": "ChatGPT",
      "serviceUrl": "https://chatgpt.com",
      "endpointUrl": "https://chatgpt.com/backend-api/f/conversation",
      "messageText": "Here is our Q4 revenue breakdown...",
      "timestamp": 1710000000000,
      "contentType": "text",
      "inputMethod": "typed",
      "captureSource": "network",
      "metadata": {
        "messageLength": 42,
        "tabUrl": "https://chatgpt.com/c/abc123"
      }
    }
  ]
}

Headers: Authorization: Bearer <INGEST_API_KEY> (if configured)

GET /api/graph?action=data&limit=500

Returns graph nodes and edges for visualization.

GET /api/graph?action=search&query=keyword&limit=20

Search nodes by keyword.

GET /api/graph?action=timeline&limit=50&offset=0

Chronological disclosures with optional filters: service, sensitivity, search.

GET /api/graph?action=dashboard

Aggregate stats: totals, weekly count, service breakdown, sensitivity distribution, most-exposed subjects, recent activity.

DELETE /api/graph?id=node-uuid

Delete a node with cascade (removes connected edges and orphaned nodes).

GET /api/health

System health check (FalkorDB connectivity).


Testing

# Run the full suite
npm test

# Watch mode
npm run test:watch

# Full CI pipeline (typecheck + lint + test)
npm run ci

Test Coverage

File Tests Covers
src/__tests__/rate-limit.test.ts 8 Token bucket: burst, refill, per-client isolation, key expiry
src/__tests__/classifier.test.ts 6 Zod schema validation, category/sensitivity/subject parsing, edge cases
src/__tests__/ingest-validation.test.ts 6 Ingest payload validation, required fields, bounds checking

Build Commands

Command What It Does
npm run dev Start dev server with hot reload (port 3001)
npm run build Next.js production build
npm run start Start production server (port 3001)
npm run typecheck TypeScript type checker
npm run lint ESLint
npm run test Run Vitest suite
npm run test:watch Vitest in watch mode
npm run ci Typecheck + lint + test

Tech Stack

Layer Technology
Frontend Next.js 15, React 19, Tailwind CSS 4, shadcn/ui
Graph Visualization Cosmograph (WebGL)
Graph Database FalkorDB (Cypher queries over Redis protocol)
Classification OpenAI API with Zod-validated structured output
Auth NextAuth v5
Validation Zod
Logging Pino
Testing Vitest
Extension Chrome Manifest V3

Common Gotchas

  1. Port 6379 in use. Another Redis instance will conflict with FalkorDB. Stop it or change FALKORDB_PORT.
  2. Extension not capturing. Make sure the extension is enabled and the page was loaded after the extension was installed. Reload the AI service tab.
  3. No data on dashboard. Check the extension popup — it shows a count of captured disclosures and connection status. If the count is zero, try sending a message on a supported AI service.
  4. CORS errors. The ingest API includes CORS headers for the extension. If you move the backend to a different origin, update host_permissions in manifest.json.
  5. Docker Compose V2. Use docker compose (no hyphen). Older Linux installations may need docker-compose.
  6. Auth is off by default. Set OMNIGRAPH_PASSWORD in .env to enable dashboard authentication.
  7. Classification requires OpenAI. An OPENAI_API_KEY is required for sensitivity classification. Without it, disclosures are stored but remain unclassified.

Contributing

Contributions are welcome. Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Make your changes
  4. Run npm run ci to verify (typecheck + lint + test)
  5. Submit a pull request

Adding a New AI Service

To add support for a new AI service:

  1. Add the service's URL patterns to extension/manifest.json (matches arrays and host_permissions)
  2. Add a service entry in extension/src/services/registry.js with endpoint patterns and a body parser
  3. Optionally add a DOM adapter in extension/src/content/adapters/

License

MIT License. See LICENSE for details.

About

OmniGraph is a browser extension + dashboard that tracks everything you share with AI tools (ChatGPT, Claude, Gemini, etc.) and shows you a timeline and graph of what data you've disclosed, to which service, and how sensitive it was.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors