{"id":47873727,"url":"https://github.com/Quinnod345/context-engine","last_synced_at":"2026-04-19T07:01:04.172Z","repository":{"id":341538599,"uuid":"1170259419","full_name":"Quinnod345/context-engine","owner":"Quinnod345","description":"A lightweight context engine for AI agents. Ingest events, build semantic context, query with natural language. Zero config.","archived":false,"fork":false,"pushed_at":"2026-03-16T21:58:11.000Z","size":202,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-17T01:57:55.795Z","etag":null,"topics":["ai","ai-agents","context","developer-tools","embeddings","llm","mcp","model-context-protocol","nodejs","pgvector","rag","semantic-search","sqlite","temporal-decay","typescript","vector-search","zero-config"],"latest_commit_sha":null,"homepage":"https://quinnod345.github.io/context-engine/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Quinnod345.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-01T23:14:04.000Z","updated_at":"2026-03-16T21:58:15.000Z","dependencies_parsed_at":"2026-03-07T02:02:14.162Z","dependency_job_id":null,"html_url":"https://github.com/Quinnod345/context-engine","commit_stats":null,"previous_names":["quinnod345/context-engine"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Quinnod345/context-engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quinnod345%2Fcontext-engine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quinnod345%2Fcontext-engine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quinnod345%2Fcontext-engine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quinnod345%2Fcontext-engine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Quinnod345","download_url":"https://codeload.github.com/Quinnod345/context-engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quinnod345%2Fcontext-engine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31997804,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agents","context","developer-tools","embeddings","llm","mcp","model-context-protocol","nodejs","pgvector","rag","semantic-search","sqlite","temporal-decay","typescript","vector-search","zero-config"],"created_at":"2026-04-04T01:00:58.204Z","updated_at":"2026-04-19T07:01:04.149Z","avatar_url":"https://github.com/Quinnod345.png","language":"TypeScript","funding_links":[],"categories":["Learning"],"sub_categories":["Repositories"],"readme":"\u003cdiv align=\"center\"\u003e\n\n# context-engine-ai\n\n**Give your AI agent a memory of what just happened.**\n\nIngest events from any source. Query with natural language. Get back ranked, time-decayed results — no vector database, no API keys, no config.\n\n[![npm version](https://img.shields.io/npm/v/context-engine-ai)](https://www.npmjs.com/package/context-engine-ai)\n[![CI](https://github.com/Quinnod345/context-engine/actions/workflows/ci.yml/badge.svg)](https://github.com/Quinnod345/context-engine/actions)\n[![license](https://img.shields.io/npm/l/context-engine-ai)](./LICENSE)\n[![npm downloads](https://img.shields.io/npm/dm/context-engine-ai)](https://www.npmjs.com/package/context-engine-ai)\n[![GitHub stars](https://img.shields.io/github/stars/Quinnod345/context-engine?style=social)](https://github.com/Quinnod345/context-engine)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://www.typescriptlang.org/)\n[![Node](https://img.shields.io/badge/Node-%3E%3D18-green)](https://nodejs.org/)\n\n[**Live Demo**](https://quinnod345.github.io/context-engine/) · [Try the CLI](#try-it-in-10-seconds) · [Install](#install) · [Quick Start](#quick-start) · [Use Cases](#use-cases) · [API Reference](#api-reference) · [Examples](./examples)\n\n\u003c/div\u003e\n\n---\n\n## Try It in 10 Seconds\n\n```bash\nnpx context-engine-ai demo\n```\n\nNo API keys. No database. No config. Runs a simulated developer workflow and shows how context-engine answers natural language questions about what's happening.\n\n```\n  context-engine demo\n\n  Simulating developer workflow...\n\n    [editor]     app: VS Code, file: src/auth.ts, project: backend\n    [test]       command: npm test, result: 47 passed, 2 failed\n    [message]    from: Alice, via: Slack, text: auth token bug is back\n    [browser]    url: oauth.net/2, title: OAuth 2.0 docs\n    [meeting]    title: Sprint Review, starts_in: 25 minutes\n    [editor]     app: VS Code, file: src/auth.ts, change: fix token refresh\n    [test]       command: npm test, result: 49 passed, 0 failed\n    [commit]     message: fix: token refresh race condition, files: 3\n\n  8 events ingested. Querying...\n\n  Q: \"messages from slack?\"\n  A: [message] from: Alice, via: Slack, text: auth token bug is back\n\n  Q: \"next meeting?\"\n  A: [meeting] title: Sprint Review, starts_in: 25 minutes\n\n  Q: \"test results?\"\n  A: [test] command: npm test, result: 47 passed, 2 failed | [test] 49 passed, 0 failed\n\n  Q: \"latest commit?\"\n  A: [commit] message: fix: token refresh race condition, files: 3\n\n  Zero config. Zero API keys. Just context.\n```\n\n---\n\n## The Problem\n\nYou're building an AI agent. It needs to know what's going on — the user just switched to VS Code, a Slack message came in, there's a meeting in 15 minutes, and three tests are failing.\n\nYour options today:\n\n1. **Vector database + embedding API** — Set up Pinecone/Weaviate, get an OpenAI key, write the retrieval pipeline, handle rate limits. Works, but it's infrastructure for what should be a function call.\n2. **Stuff everything into the prompt** — Append raw events to the system prompt. Hits token limits fast. No relevance ranking. Old events drown out new ones.\n3. **Build it yourself** — Roll your own event store, embedding logic, similarity search, temporal decay, deduplication. Easily a week of work before you write any agent logic.\n\n`context-engine-ai` is option 4: a single import that handles all of this.\n\n```js\nimport { ContextEngine } from 'context-engine-ai'\n\nconst ctx = new ContextEngine()   // SQLite + local embeddings, zero config\n\nawait ctx.ingest({ type: 'app_switch', data: { app: 'VS Code', file: 'main.ts' } })\nawait ctx.ingest({ type: 'calendar',   data: { event: 'Standup', in: '15min' } })\nawait ctx.ingest({ type: 'message',    data: { from: 'Alice', text: 'PR ready for review' } })\n\nconst result = await ctx.query('what is the user doing right now?')\n```\n\n**Returns:**\n\n```js\n{\n  summary: '[app_switch] app: VS Code, file: main.ts | [calendar] event: Standup, in: 15min | [message] from: Alice, text: PR ready for review',\n  events: [\n    { type: 'app_switch', data: { app: 'VS Code', file: 'main.ts' }, relevance: 0.94, ... },\n    { type: 'calendar',   data: { event: 'Standup', in: '15min' },   relevance: 0.87, ... },\n    { type: 'message',    data: { from: 'Alice', text: 'PR ready for review' }, relevance: 0.82, ... },\n  ],\n  query: 'what is the user doing right now?',\n  timestamp: 1709312400000\n}\n```\n\nEvents are ranked by **similarity** to your query and weighted by **recency** — a 5-minute-old event scores higher than an identical one from yesterday. Local TF-IDF handles keyword matching out of the box; upgrade to OpenAI embeddings for true semantic search. The `summary` string is formatted for direct injection into LLM system prompts — drop it into your agent's context and it just works.\n\n---\n\n## Features\n\n| Feature | Description |\n|---------|-------------|\n| **Zero config** | SQLite + local TF-IDF embeddings. No API keys, no cloud, instant startup. |\n| **Natural language querying** | Ask `\"test results?\"` instead of writing SQL or filtering by type. Local TF-IDF for keyword matching; upgrade to OpenAI embeddings for true semantic search. |\n| **Temporal decay** | Recent events automatically rank higher. Configurable half-life (default: 24h). |\n| **Auto-deduplication** | Switching between two apps 50 times doesn't create 50 events — duplicates merge within a configurable time window. |\n| **Auto-pruning** | When event count exceeds your limit, the lowest-relevance oldest events are removed. No cron jobs. |\n| **SQLite or PostgreSQL** | In-memory for dev, SQLite file for persistence, pgvector for production scale. |\n| **Local or OpenAI embeddings** | Local TF-IDF (128-dim, free, no network) or OpenAI `text-embedding-3-small` (1536-dim) for higher semantic quality. |\n| **HTTP server + CLI** | `npx context-engine-ai serve` — REST API in one command. |\n| **Full TypeScript** | Types for every interface. Works great with `@ts-check` in JS files too. |\n| **~64KB unpacked** | Tiny footprint. Ships only what's needed. |\n| **Sub-millisecond** | ~0.1ms per ingest, ~0.1ms per query with local embeddings (SQLite, 1000 events). |\n\n---\n\n## When to Use This\n\n**Good fit:**\n- Your AI agent needs real-time awareness of what's happening (user activity, system events, messages)\n- You want semantic search over a stream of structured events\n- You need something working in minutes, not days\n- You're building a prototype and don't want to set up infrastructure\n- You want temporal decay and deduplication handled for you\n\n**Not the right tool:**\n- You need to search over large documents or PDFs (use a RAG framework like LangChain or LlamaIndex)\n- You need persistent long-term memory across months of history (use a proper vector database)\n- You're indexing millions of documents (use pgvector or a dedicated vector DB directly)\n\n---\n\n## How It Compares\n\n| | context-engine-ai | RAG frameworks | Custom implementation |\n|---|---|---|---|\n| **Setup** | `npm install`, done | Vector DB + embedding API + retrieval chain | Days of plumbing |\n| **API keys** | No (local TF-IDF default) | Yes (OpenAI/Cohere/etc) | Depends |\n| **Temporal decay** | Built-in, configurable | Manual implementation | Build it yourself |\n| **Deduplication** | Built-in (cosine threshold + time window) | Manual | Build it yourself |\n| **Data model** | Event-oriented `{type, data}` | Document chunks | Your schema |\n| **Query interface** | Natural language | Natural language | SQL / custom |\n| **Storage** | SQLite (zero-config) → PostgreSQL | Pinecone/Weaviate/Chroma | Your choice |\n| **HTTP server** | `ctx.serve(3334)` — one line | Build it | Build it |\n| **Size** | ~64KB | 10-100MB+ with dependencies | Varies |\n\n---\n\n## Install\n\n```bash\nnpm install context-engine-ai\n```\n\n---\n\n## Quick Start\n\n### As a Library\n\n```js\nimport { ContextEngine } from 'context-engine-ai'\n\nconst ctx = new ContextEngine()\n\nawait ctx.ingest({ type: 'task', data: { title: 'Review PR #42', priority: 'high' } })\nawait ctx.ingest({ type: 'message', data: { from: 'Alice', text: 'deploy is broken' } })\n\nconst result = await ctx.query('any issues right now?')\nconsole.log(result.summary)\n// =\u003e \"[message] from: Alice, text: deploy is broken | [task] title: Review PR #42, priority: high\"\nconsole.log(result.events)\n// =\u003e StoredEvent[] sorted by relevance × recency\n\nawait ctx.close()\n```\n\n### With Persistence\n\n```js\nconst ctx = new ContextEngine({ dbPath: './my-context.db' })\n// Events survive restarts. Standard SQLite file — inspect with any SQLite tool.\n```\n\n### Production (PostgreSQL + pgvector)\n\n```js\nconst ctx = new ContextEngine({\n  storage: 'postgres',\n  pgConnectionString: 'postgresql://user:pass@localhost:5432/mydb',\n  embeddingProvider: 'openai',\n  openaiApiKey: process.env.OPENAI_API_KEY,\n})\n```\n\n### As an HTTP Server\n\n```js\nconst ctx = new ContextEngine({ dbPath: './context.db' })\nctx.serve(3334)\n```\n\nOr via CLI:\n\n```bash\nnpx context-engine-ai serve --port 3334\n```\n\n### As an MCP Server (Claude Desktop, Cursor, Windsurf)\n\nUse context-engine as a [Model Context Protocol](https://modelcontextprotocol.io) tool server. Any MCP-compatible client (Claude Desktop, Cursor, Windsurf, VS Code) can then call `ingest_event`, `query_context`, `get_recent`, and `clear_context` as native tools.\n\n```bash\nnpm install @modelcontextprotocol/sdk zod\nnode examples/mcp-server.js\n```\n\nAdd to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"context-engine\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/examples/mcp-server.js\"]\n    }\n  }\n}\n```\n\nThe agent can then call:\n- **`ingest_event`** — store any event (`type` + `data`)\n- **`query_context`** — semantic search: `\"any errors in the last hour?\"`\n- **`get_recent`** — latest N events by timestamp\n- **`clear_context`** — wipe the store\n\nSee [`examples/mcp-server.js`](./examples/mcp-server.js) for the full implementation.\n\n### REST Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/ingest` | Ingest an event `{ type, data }` |\n| `GET`  | `/context?q=...\u0026limit=10` | Semantic query |\n| `GET`  | `/recent?limit=20` | Recent events by timestamp |\n| `GET`  | `/count` | Number of stored events |\n| `DELETE` | `/events` | Clear all stored events |\n| `GET`  | `/health` | Health check |\n\n```bash\n# Ingest an event\ncurl -X POST http://localhost:3334/ingest \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"type\": \"deploy\", \"data\": {\"service\": \"api\", \"version\": \"2.1.0\", \"env\": \"production\"}}'\n\n# Query with natural language\ncurl \"http://localhost:3334/context?q=recent%20deployments\u0026limit=5\"\n\n# Get recent events\ncurl \"http://localhost:3334/recent?limit=10\"\n```\n\n---\n\n## Use Cases\n\n### 1. Give your AI agent situational awareness\n\nThe core use case. Ingest events as they happen — user actions, system alerts, messages, calendar entries — and query for relevant context when the agent responds.\n\n```js\nimport Anthropic from '@anthropic-ai/sdk'\nimport { ContextEngine } from 'context-engine-ai'\n\nconst ctx = new ContextEngine({ dbPath: './agent-context.db' })\nconst claude = new Anthropic()\n\n// Events stream in throughout the day\nawait ctx.ingest({ type: 'terminal', data: { command: 'npm test', output: '3 failed, 12 passed' } })\nawait ctx.ingest({ type: 'slack',   data: { from: 'Sarah', text: 'Auth service throwing 401s in staging' } })\nawait ctx.ingest({ type: 'error',   data: { service: 'auth', error: 'TokenExpiredError', count: 47 } })\nawait ctx.ingest({ type: 'pr',      data: { repo: 'backend', title: 'Fix OAuth token refresh', status: 'review_requested' } })\n\n// Agent gets relevant context for its response\nconst context = await ctx.query('what needs attention?', 5)\n\nconst response = await claude.messages.create({\n  model: 'claude-sonnet-4-6',\n  max_tokens: 1024,\n  system: `You are a developer assistant. Current context:\\n${context.summary}`,\n  messages: [{ role: 'user', content: 'What should I focus on?' }]\n})\n// Claude sees the auth errors, failing tests, and related PR — responds with specific advice\n```\n\n### 2. Desktop activity tracker\n\nTrack what you're doing across apps. Deduplication means switching between two windows 100 times creates 2 events, not 100.\n\n```js\nimport { ContextEngine } from 'context-engine-ai'\nimport { execSync } from 'child_process'\n\nconst ctx = new ContextEngine({ dbPath: './desktop.db', decayHours: 8 })\n\n// Poll active window every 5 seconds\nsetInterval(async () =\u003e {\n  const app = execSync(\n    `osascript -e 'tell app \"System Events\" to get name of first process whose frontmost is true'`,\n    { encoding: 'utf-8' }\n  ).trim()\n  await ctx.ingest({ type: 'window_focus', data: { app } })\n}, 5000)\n\n// Later: \"what was I doing this afternoon?\"\nconst result = await ctx.query('what was I working on?')\nconsole.log(result.summary)\n// =\u003e \"[window_focus] app: VS Code | [window_focus] app: Firefox | [window_focus] app: Slack\"\n```\n\n### 3. Webhook aggregation\n\nReceive events from GitHub, Slack, PagerDuty, or any webhook source. Query the combined stream in natural language instead of checking each service individually.\n\n```js\nimport express from 'express'\nimport { ContextEngine } from 'context-engine-ai'\n\nconst ctx = new ContextEngine({ dbPath: './ops.db', maxEvents: 5000, decayHours: 48 })\nconst app = express()\napp.use(express.json())\n\napp.post('/webhook/github', async (req, res) =\u003e {\n  const { action, pull_request, repository } = req.body\n  await ctx.ingest({\n    type: 'github_pr',\n    data: { action, title: pull_request?.title, repo: repository?.full_name }\n  })\n  res.sendStatus(200)\n})\n\napp.post('/webhook/pagerduty', async (req, res) =\u003e {\n  const { event } = req.body\n  await ctx.ingest({\n    type: 'alert',\n    data: { severity: event?.severity, summary: event?.summary?.slice(0, 200) }\n  })\n  res.sendStatus(200)\n})\n\n// One query across all sources\napp.get('/context', async (req, res) =\u003e {\n  const result = await ctx.query(req.query.q, parseInt(req.query.limit) || 10)\n  res.json(result)\n})\n\napp.listen(4000)\n```\n\n### 4. Other ideas\n\n- **Smart notifications** — Check what the user is doing before interrupting them\n- **Meeting prep** — Combine calendar + recent work + messages for automated briefings\n- **Log analysis** — Ingest structured logs, query them with plain English\n- **IoT / sensor fusion** — Unify events from multiple devices into one queryable stream\n- **Chat context** — Feed conversation history + user activity into LLM system prompts\n\n---\n\n## How It Works\n\n```\nEvents In          Embed           Store             Query\n─────────────┐    ┌──────┐    ┌────────────┐    ┌──────────────┐\napp_switch   │───\u003e│TF-IDF│───\u003e│  SQLite /   │\u003c───│ \"what is the │\ncalendar     │    │  or   │    │  pgvector   │    │  user doing?\"│\nmessage      │    │OpenAI │    │             │    └──────┬───────┘\nterminal     │    └──────┘    └────────────┘           │\ngit_commit   │                  dedup + prune     cosine similarity\n─────────────┘                                    + temporal decay\n                                                       │\n                                                  ┌────▼────┐\n                                                  │ Ranked  │\n                                                  │ Context │\n                                                  └─────────┘\n```\n\n### Step 1: Ingest\n\nEvents arrive as `{type, data}`. The engine serializes them to searchable text:\n\n```\n{ type: 'message', data: { from: 'Alice', text: 'PR ready' } }\n  → \"event:message from:Alice text:PR ready\"\n```\n\nThis text is embedded into a 128-dimensional vector (local TF-IDF) or 1536-dimensional (OpenAI). The engine then checks for near-duplicates — if a \u003e95% similar event was ingested in the last 60 seconds, it merges instead of storing a duplicate.\n\n### Step 2: Query\n\nYour natural language question is embedded and compared against every stored event using cosine similarity. Each result is then weighted by **temporal decay**:\n\n```\nfinalScore = cosineSimilarity(query, event) × relevance × 0.5^(age / halfLife)\n```\n\n**Concrete example** — you query `\"any errors?\"` with `decayHours: 24`:\n\n| Event | Cosine sim | Age | Decay | Final score |\n|-------|-----------|-----|-------|-------------|\n| `[error] service: auth, count: 47` | 0.92 | 5 min | 0.9998 | **0.92** |\n| `[error] service: api, count: 3` | 0.89 | 6 hours | 0.84 | **0.75** |\n| `[test] result: 2 failed` | 0.41 | 2 min | 0.9999 | **0.41** |\n| `[error] service: auth, count: 12` | 0.91 | 3 days | 0.125 | **0.11** |\n\nThe 5-minute-old auth error wins. The 3-day-old error — identical content — scores 8x lower. The `summary` string is pre-formatted for direct injection into LLM system prompts.\n\n### Step 3: Prune\n\nWhen event count exceeds `maxEvents`, the lowest-scoring oldest events are automatically removed. No cron jobs, no maintenance.\n\n### Local Embeddings\n\nThe default embedding provider uses TF-IDF with locality-sensitive hashing projected into 128 dimensions. No network calls, deterministic, sub-millisecond. It works well for structured event data where the vocabulary is predictable (event types, field names, common terms). Swap to OpenAI embeddings with one config change when you need true semantic search over ambiguous natural language.\n\n### Performance\n\nBenchmarked on Apple Silicon with local TF-IDF + SQLite (in-memory):\n\n| Operation | Latency | Notes |\n|-----------|---------|-------|\n| Ingest | ~0.1ms/event | Including embed + dedup check + store |\n| Query | ~0.1ms/query | Across 1000 stored events |\n| Memory | ~20MB heap | With 1000 events loaded |\n\n---\n\n## Configuration\n\n```js\nconst ctx = new ContextEngine({\n  // Storage\n  storage: 'sqlite',              // 'sqlite' (default) or 'postgres'\n  dbPath: './context.db',          // SQLite file path (default: in-memory)\n  pgConnectionString: '...',       // PostgreSQL connection string\n\n  // Embeddings\n  embeddingProvider: 'local',      // 'local' (TF-IDF, default) or 'openai'\n  openaiApiKey: '...',             // Required for OpenAI (or set OPENAI_API_KEY env var)\n\n  // Tuning\n  maxEvents: 1000,                 // Max stored events before pruning (default: 1000)\n  decayHours: 24,                  // Relevance half-life in hours (default: 24)\n  deduplicationWindow: 60000,      // Dedup time window in ms (default: 60s)\n  deduplicationThreshold: 0.95,    // Cosine similarity threshold for dedup (default: 0.95)\n})\n```\n\n### Storage: SQLite (default)\n\nZero config. Uses [better-sqlite3](https://github.com/WiseLibs/better-sqlite3). Stores embeddings as JSON arrays. Good for single-process use, prototyping, and edge deployments.\n\nPass `dbPath` to persist across restarts. Without it, uses in-memory storage (events lost on restart).\n\n### Storage: PostgreSQL + pgvector\n\nUses [pgvector](https://github.com/pgvector/pgvector) for native vector similarity search. Multi-process safe, production-ready, handles millions of events. Requires the `vector` extension to be installed.\n\n```js\nconst ctx = new ContextEngine({\n  storage: 'postgres',\n  pgConnectionString: 'postgresql://user:pass@localhost:5432/mydb',\n})\n```\n\n### Embeddings: Local (default)\n\nTF-IDF with locality-sensitive hashing. 128-dimensional vectors. No external calls, instant, deterministic. Performs well for matching structured event data to natural language queries.\n\n### Embeddings: OpenAI\n\nUses `text-embedding-3-small` (1536-dimensional). Higher semantic quality for complex or ambiguous queries. Requires an API key.\n\n```js\nconst ctx = new ContextEngine({\n  embeddingProvider: 'openai',\n  openaiApiKey: 'sk-...',  // or set OPENAI_API_KEY env var\n})\n```\n\n---\n\n## API Reference\n\n### `new ContextEngine(options?)`\n\nCreate a new engine instance. See [Configuration](#configuration) for all options.\n\n### `ctx.ingest(event): Promise\u003cStoredEvent\u003e`\n\nIngest an event. Embeds the event text, checks for duplicates, stores it, and prunes if over the limit. If a near-duplicate exists within the deduplication window, the existing event is updated instead of creating a new one.\n\n```ts\ninterface EventInput {\n  type: string                     // Event category (e.g. 'app_switch', 'message', 'error')\n  data: Record\u003cstring, unknown\u003e    // Event payload — any key/value pairs\n}\n\ninterface StoredEvent {\n  id: string\n  type: string\n  data: Record\u003cstring, unknown\u003e\n  timestamp: number\n  embedding: number[]\n  relevance: number                // 0.0 - 1.0\n}\n```\n\n### `ctx.query(question, limit?): Promise\u003cContextResult\u003e`\n\nSemantic search across stored events. Returns events ranked by cosine similarity to the query, weighted by temporal decay. Includes a pre-formatted `summary` string suitable for injecting into LLM prompts.\n\n```ts\ninterface ContextResult {\n  summary: string          // Human-readable: \"[type] key: val | [type] key: val\"\n  events: StoredEvent[]    // Ranked by relevance × decay\n  query: string            // The original query\n  timestamp: number        // When the query was executed\n}\n```\n\n### `ctx.recent(limit?): Promise\u003cStoredEvent[]\u003e`\n\nGet the most recent events ordered by timestamp. Default limit: 20.\n\n### `ctx.count(): Promise\u003cnumber\u003e`\n\nReturns the number of events currently stored.\n\n```js\nconst n = await ctx.count()\nconsole.log(`${n} events in context`)\n```\n\n### `ctx.clear(): Promise\u003cvoid\u003e`\n\nRemove all stored events.\n\n### `ctx.serve(port?): Server`\n\nStart an Express HTTP server. Default port: 3334. Returns a Node.js `http.Server`.\n\n### `ctx.close(): Promise\u003cvoid\u003e`\n\nClean shutdown. Closes database connections and HTTP server.\n\n### Utility Exports\n\nFor advanced use — build custom storage backends or embedding providers:\n\n```js\nimport {\n  SQLiteStorage,           // StorageAdapter implementation for SQLite\n  PostgresStorage,         // StorageAdapter implementation for PostgreSQL + pgvector\n  LocalEmbeddingProvider,  // TF-IDF embeddings (128-dim, no network)\n  OpenAIEmbeddingProvider, // OpenAI text-embedding-3-small (1536-dim)\n  createServer,            // Express app factory\n  cosineSimilarity,        // (a: number[], b: number[]) =\u003e number\n  computeDecay,            // (timestamp, now, halfLifeHours) =\u003e number\n  eventToText,             // (type, data) =\u003e string\n} from 'context-engine-ai'\n```\n\n### TypeScript\n\nFull type definitions included:\n\n```ts\nimport type {\n  StoredEvent,\n  EventInput,\n  ContextResult,\n  StorageAdapter,       // Implement this to add custom storage backends\n  EmbeddingProvider,    // Implement this to add custom embedding providers\n  EngineOptions,\n} from 'context-engine-ai'\n```\n\n---\n\n## Examples\n\nSee the [`examples/`](./examples) directory for runnable code:\n\n| Example | Description |\n|---------|-------------|\n| [`basic.js`](./examples/basic.js) | Event ingestion and semantic querying |\n| [`server.js`](./examples/server.js) | Running as an HTTP service |\n| [`ai-agent.js`](./examples/ai-agent.js) | Feeding context into Claude |\n| [`agent-context.js`](./examples/agent-context.js) | Building a structured context block for agent system prompts |\n| [`webhook-server.js`](./examples/webhook-server.js) | Multi-source webhook aggregation |\n| [`mcp-server.js`](./examples/mcp-server.js) | MCP tool server for Claude Desktop, Cursor, Windsurf |\n| [`custom-storage.js`](./examples/custom-storage.js) | Implementing a custom storage adapter |\n\n```bash\nnpx context-engine-ai demo          # Interactive demo — no setup needed\nnode examples/basic.js               # Library usage\nnode examples/ai-agent.js            # Agent integration (needs ANTHROPIC_API_KEY)\n```\n\n---\n\n## Pricing\n\nThe npm package is **free and open source** (MIT) — every feature, no limits, no API keys required.\n\nFor managed infrastructure, we offer a cloud API:\n\n| | **Open Source** | **Pro** | **Team** | **Enterprise** |\n|---|---|---|---|---|\n| **Price** | **Free** | **$29/mo** | **$99/mo** | Custom |\n| Full library + CLI + MCP | Yes | Yes | Yes | Yes |\n| Self-hosted (SQLite / PostgreSQL) | Yes | Yes | Yes | Yes |\n| Local + OpenAI embeddings | BYOK | Included | Included | Included |\n| **Managed Cloud API** | — | Yes | Yes | Yes |\n| Events/month | Unlimited | 50,000 | 500,000 | Unlimited |\n| Support | GitHub Issues | Email | Priority | Dedicated + SLA |\n\nEarly access: email **oneiro-dev@proton.me** with subject \"Cloud API Access\" — first adopters get 3 months free.\n\n[Full pricing details](./docs/pricing.md)\n\n---\n\n## Documentation\n\n- [Quick Start Guide](./docs/quick-start.md) — running in under 2 minutes\n- [Architecture Overview](./docs/architecture.md)\n- [Custom Adapters](./docs/custom-adapters.md)\n- [Deployment Guide](./docs/deployment.md)\n- [Pricing](./docs/pricing.md)\n\n## Requirements\n\n- Node.js \u003e= 18\n- No external services required (default configuration)\n- Optional: PostgreSQL with pgvector extension (for production scale)\n- Optional: OpenAI API key (for higher-quality embeddings)\n\n---\n\n## Development\n\n```bash\ngit clone https://github.com/Quinnod345/context-engine.git\ncd context-engine\nnpm install\nnpm run build     # Compile TypeScript\nnpm test          # Run test suite\nnpm run dev       # Watch mode\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md). Some ideas:\n\n- New storage adapters (Redis, DuckDB, Turso)\n- New embedding providers (Cohere, local ONNX models)\n- Browser extension for automatic context capture\n- Streaming ingestion via WebSocket\n\n## Star History\n\nIf context-engine-ai saves you time, a ⭐ on GitHub helps others find it.\n\n[![Star History Chart](https://api.star-history.com/svg?repos=Quinnod345/context-engine\u0026type=Date)](https://star-history.com/#Quinnod345/context-engine\u0026Date)\n\n## License\n\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQuinnod345%2Fcontext-engine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FQuinnod345%2Fcontext-engine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQuinnod345%2Fcontext-engine/lists"}