{"id":47692082,"url":"https://github.com/baiganio/aperio","last_synced_at":"2026-05-28T20:01:07.830Z","repository":{"id":343110238,"uuid":"1176308591","full_name":"BaiGanio/aperio","owner":"BaiGanio","description":"One brain. Every AI agent. Nothing forgotten. — Self-hosted memory layer via MCP + Postgres + pgvector","archived":false,"fork":false,"pushed_at":"2026-05-23T07:39:05.000Z","size":12892,"stargazers_count":6,"open_issues_count":32,"forks_count":3,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-23T09:34:01.109Z","etag":null,"topics":["docker","lancedb","local-ai","local-embeddings","mcp","ollama","pgvector","postgres","self-hosted"],"latest_commit_sha":null,"homepage":"https://baiganio.github.io/aperio/","language":"JavaScript","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/BaiGanio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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},"funding":{"open_collective":"aperio"}},"created_at":"2026-03-08T22:10:54.000Z","updated_at":"2026-05-23T07:37:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/BaiGanio/aperio","commit_stats":null,"previous_names":["baiganio/aperio"],"tags_count":185,"template":false,"template_full_name":null,"purl":"pkg:github/BaiGanio/aperio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaiGanio%2Faperio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaiGanio%2Faperio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaiGanio%2Faperio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaiGanio%2Faperio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BaiGanio","download_url":"https://codeload.github.com/BaiGanio/aperio/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaiGanio%2Faperio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33624221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"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":["docker","lancedb","local-ai","local-embeddings","mcp","ollama","pgvector","postgres","self-hosted"],"created_at":"2026-04-02T15:45:41.888Z","updated_at":"2026-05-28T20:01:07.815Z","avatar_url":"https://github.com/BaiGanio.png","language":"JavaScript","funding_links":["https://opencollective.com/aperio"],"categories":[],"sub_categories":[],"readme":"\u003ca id=\"top\"\u003e\u003c/a\u003e\n\u003cdiv align=\"center\"\u003e\n\u003ch1\u003e✨ Aperio\u003c/h1\u003e\n\n**One brain. Every agent. Nothing forgotten.**     \nA self-hosted personal memory layer for AI agents. SQLite (or Postgres) + MCP + Ollama.   \nZero-config by default; one file holds your memories, wiki, and code graph.  \nYour context, always available.  \n\u003c!-- \n##### • Download 👉 [Aperio-lite](https://github.com/BaiGanio/aperio/releases/latest/download/aperio-lite.zip) for non-code users. • Small tool for big ideas • [How to Install \u0026 Use?](https://github.com/BaiGanio/aperio/wiki/How-to-Install-\u0026-Use-Aperio%E2%80%90lite%3F) •      \n--\u003e \n\u003c/div\u003e\n\n\u003c!-- HEADER --\u003e \n\u003cp align=\"center\"\u003e\n  • \n  \u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e\n  • \n  \u003ca href=\"#architecture\"\u003eArchitecture\u003c/a\u003e\n  • \n  \u003ca href=\"#philosophy\"\u003ePhilosophy\u003c/a\u003e\n  • \n  \u003ca href=\"#ai-providers\"\u003eAI Providers\u003c/a\u003e\n  • \n  \u003ca href=\"https://github.com/BaiGanio/aperio/wiki/MCP-Tools-Guide\" target=\"_blank\"\u003eHow To Use?\u003c/a\u003e \n  •  \n  \u003ca href=\"#privacy\"\u003ePrivacy\u003c/a\u003e \n  • \n  \u003ca href=\"#security\"\u003eSecurity\u003c/a\u003e\n  •  \n  \u003ca href=\"https://github.com/BaiGanio/aperio/discussions/24\"\u003eDesign Decisions\u003c/a\u003e\n  • \n\u003c/p\u003e\n\u003cdiv align=\"center\"\u003e   \n\n#### • 🌐 Site: [https://baiganio.github.io/aperio](https://baiganio.github.io/aperio) •\n\u003c!-- [![Bounties Available](https://img.shields.io/badge/bounties-active-brightgreen)](./PAYMENT.md) --\u003e \n[![Downloads](https://img.shields.io/github/downloads/baiganio/aperio/total?style=flat-square)](https://github.com/baiganio/aperio/releases)\n![Latest Release](https://img.shields.io/github/v/release/BaiGanio/aperio) \n![GitHub contributors](https://img.shields.io/github/contributors/baiganio/aperio)\n[![Last Commit](https://img.shields.io/github/last-commit/baiganio/aperio)](https://github.com/baiganio/aperio)\n[![CodeQL](https://github.com/baiganio/aperio/actions/workflows/ci.codeql.yml/badge.svg)](https://github.com/baiganio/aperio/actions/workflows/ci.codeql.yml)\n[![codecov](https://codecov.io/github/BaiGanio/aperio/graph/badge.svg?token=WUIXIYJBR2)](https://codecov.io/github/BaiGanio/aperio)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=BaiGanio_aperio\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=BaiGanio_aperio)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/989578993b87414db9ff64a2b3c22989)](https://app.codacy.com/gh/BaiGanio/aperio/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade)\n[![Dependabot](https://img.shields.io/badge/dependabot-enabled-025E8C?logo=dependabot)](https://github.com/baiganio/aperio/security/dependabot)\n[![Security Policy](https://img.shields.io/badge/security-policy-green?logo=github)](https://github.com/baiganio/aperio/security/policy)\n\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003c!-- \u003csub\u003e💡 \u003cb\u003ePro Tip:\u003c/b\u003e Visit \u003ca href=\"https://github.com/BaiGanio/aperio/wiki/How-to-Install-\u0026-Use-Aperio%E2%80%90lite%3F\"\u003eHow to Install \u0026 Use Aperio‐lite?\u003c/a\u003e for extensive installation instructions.\u003cbr\u003e --\u003e\n  💡 \u003cb\u003ePro Tip:\u003c/b\u003e Visit the \u003ca href=\"https://github.com/BaiGanio/aperio/wiki\"\u003eAperio Wiki\u003c/a\u003e or \u003ca href=\"https://github.com/BaiGanio/aperio/discussions\"\u003eDiscussions\u003c/a\u003e for extensive documentation on advanced topics.\u003cbr\u003e\n   🔍 \u003cb\u003eExplore more:\u003c/b\u003e \u003ca href=\"https://github.com/BaiGanio/aperio/issues/3\"\u003eEarly Testing Contributors\u003c/a\u003e • \u003ca href=\"https://github.com/BaiGanio/aperio/discussions/14\"\u003eFAQ\u003c/a\u003e • \u003ca href=\"https://github.com/BaiGanio/aperio/wiki/Troubleshooting\"\u003eTroubleshooting\u003c/a\u003e\n\u003c/p\u003e\n\n---\n## 🏗️ (Quick) Project Structure \n```txt\n📂 aperio/          \u003c---=  You are here if You are Developer. He-he ;/\n├── 📂 db/\n│   ├── index.js                  # Store factory — auto-selects Postgres or SQLite\n│   ├── sqlite.js                 # SQLite + sqlite-vec + FTS5 adapter (zero config, default)\n│   ├── postgres.js               # Postgres + pgvector adapter (Docker)\n│   ├── types.js                  # Shared DB types\n│   ├── 📂 migrations/            # Postgres SQL (memories + wiki + codegraph)\n│   └── 📂 migrations-sqlite/     # SQLite SQL (same schemas, FTS5 + vec0)\n├── 📂 docker/\n│   └── docker-compose.yml        # pgvector/pgvector:pg16\n├── 📂 docs/\n│   └── index.html                # Landing page for GitHub Pages\n├── 📂 id/\n│   └── whoami.md                 # Instructions for AI agent identity (edit this!)\n├── 📂 lib/\n│   ├── agent.js                  # Agent core — Anthropic / DeepSeek / Ollama loops\n│   ├── terminal.js               # Terminal chat client\n│   ├── 📂 emitters/              # CLI and WebSocket stream emitters\n│   ├── 📂 handlers/              # Attachment and memory handlers\n│   ├── 📂 helpers/               # Embeddings, logger, port, shutdown, Ollama health\n│   ├── 📂 routes/                # Express API routes + path safety guards\n│   ├── 📂 utils/                 # Chat utilities\n│   └── 📂 workers/               # Deduplication, reasoning adapters, skill loader\n├── 📂 lib/codegraph/             # Pre-indexed code knowledge graph (symbols, calls, imports)\n│   ├── indexer.js                # Backend dispatcher (Postgres or SQLite)\n│   ├── watcher.js                # chokidar-backed live reindex\n│   ├── extract-ts.js             # tree-sitter JS/TS/JSX/TSX extractor\n│   └── 📂 backends/              # postgres.js · sqlite.js\n├── 📂 mcp/\n│   ├── index.js                  # MCP server entry point\n│   └── 📂 tools/\n│       ├── memory.js             # remember · recall · update_memory · forget · backfill_embeddings · deduplicate_memories\n│       ├── codegraph.js          # code_search · code_outline · code_context · code_callers · code_callees · code_repos\n│       ├── files.js              # read_file · write_file · append_file · scan_project\n│       ├── shell.js              # run_node_script · run_shell · syntax_check\n│       ├── web.js                # fetch_url\n│       └── image.js              # read_image · preprocess_image\n├── 📂 public/\n│   └── index.html                # Web UI — themes, streaming, sidebar\n├── 📂 skills/                    # Memory, reasoning, tools, coding standards, etc.\n├── 📂 tests/      \n├── .env.example                  # Pre-set quick configuration\n├── package.json                  # Dependencies\n└── server.js                     # Express + WebSocket + agent loop\n \n```\n\n\u003e **💡 Tip:** **`whoami.md`** controls the identity of the AI agent.    \n\u003e - It is the most impactful file to customize.\n\n---\n\n## Getting Started \n### Prerequisites\n- Node.js 18+ — download from [https://nodejs.org/en/download](https://nodejs.org/en/download)\n- [Docker Desktop](https://www.docker.com/products/docker-desktop/) — (optional, for Postgres mode)\n- Ollama — download from [https://ollama.com/download](https://ollama.com/download) (optional, for local AI)\n- [Anthropic API key](https://console.anthropic.com) — (optional, for cloud AI)\n- [DeepSeek API key](https://platform.deepseek.com) — (optional, for cloud AI)\n- [Google Gemini API key](https://aistudio.google.com/apikey) — (optional, for cloud AI)\n- [Voyage AI API key](https://www.voyageai.com/) — (optional, for cloud embeddings)\n\n### Step 1. Clone \u0026 Configure Environment Variables\nDedicated `dev` branch stripped from the file/folder noise. Only what's needed.\n```bash\n# dedicated developer branch - no extra files\ngit clone --depth 1 -b dev https://github.com/BaiGanio/aperio.git\ncd aperio\n\n# restore dependencies\nnpm install\n```\n\u003e Ready to use `.env.example` for a fully local setup:\n```env\n# cp .env.example .env\n\nAI_PROVIDER=ollama\nOLLAMA_MODEL=qwen2.5:3b\nEMBEDDING_PROVIDER=transformers    # fully local, no API key required\n# DB_BACKEND=sqlite               # default; uncomment to override\n# SQLITE_PATH=./var/aperio.db     # default location for the single-file DB\n```\n\n### Step 2. Databases \u0026 Migrations\n\nAperio supports two storage backends. **You don't need to choose** — auto-detect picks\nthe right one based on whether Docker is running:\n\n| Backend | When to use | Requires |\n|---------|-------------|----------|\n| **SQLite + sqlite-vec** (default) | No Docker, quick start, single user. Single file at `var/aperio.db`. | Nothing extra |\n| **Postgres + pgvector** | Multi-agent, persistent, production-like | Docker |\n\n```bash\n# SQLite is the default — no extra steps needed.\n# Skip the Docker commands below and go directly to Step 3.\n```\n\n\u003e **💡 Tip:** Set `DB_BACKEND=sqlite` in `.env` to force SQLite, or `DB_BACKEND=postgres` for Postgres.   \n\u003e If not set, Aperio auto-detects: uses Postgres when Docker is running, SQLite otherwise.\n\n```bash\n# POSTGRES MODE — start the database and run migrations\ncd docker \u0026\u0026 docker compose up -d \u0026\u0026 cd ..\nnpm run migrate\n```\n### Step 3. Install Ollama \u0026 Pull Models\n\u003e **💡 Tip:** Skip this step entirely if you are using Anthropic or DeepSeek as your `AI_PROVIDER`.\n```bash\nollama serve                     # use separate terminal\n```\n```bash\nollama pull qwen2.5:3b           # LLM — lightweight, fast, good tool-calling\n# ollama pull llama3.1           # LLM — solid tool-calling, no reasoning\n# ollama pull qwen3:4b           # LLM — strong reasoning, thinking mode support\n```\n### Step 4. Start Aperio Web UI\n```bash\nnpm run start:local              # localhost:31337 → browser opens automatically\n```\n### Step 5. Start Aperio terminal chat\n```bash\nnpm run chat:local               # runs as proxy or standalone\n```\n\n\u003e That's it. No API keys. No cloud. Full semantic memory on your machine.\n\n### Q: Now what?\n\n\u003e💡 Stuck on the installation steps? — check [Troubleshooting](https://github.com/BaiGanio/aperio/wiki/Troubleshooting) wiki.\n\n\u003e💡 Check [Aperio MCP Tools Guide](https://github.com/BaiGanio/aperio/wiki/MCP-Tools-Guide) wiki for extended examples.   \n\u003e💡 Check [Commands](https://github.com/BaiGanio/aperio/wiki/Commands) wiki for the available options to run the app.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## Architecture\n\u003cimg alt=\"Aperio architecture\" src=\"https://raw.githubusercontent.com/BaiGanio/aperio/master/.github/images/aperio-architecture.png\" /\u003e\n\n#### Q: Feel a need to read?\n\u003e **💡 Tip:** Visit [Architecture \u0026 Design](https://github.com/BaiGanio/aperio/discussions/24) for **in-depth** explanations.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## Round-table mode (two-agent cross-review)\n\nAperio can boot a **second agent** alongside the primary so that any chat turn\ncan be cross-reviewed before it reaches you. Two agents take turns: **Agent A**\nanswers, **Agent B** reviews, A revises, B re-reviews — until they reach\nexplicit `AGREED` or a hard round cap is hit. A single consensus bubble is\nrendered when they agree; otherwise both positions are shown side-by-side.\n\n**Enable it** with `ROUNDTABLE_AGENTS` in `.env`:\n\n```env\n# Format: provider:model,provider:model\nROUNDTABLE_AGENTS=anthropic:claude-haiku-4-5-20251001,deepseek:deepseek-chat\nROUNDTABLE_MAX_ROUNDS=3\n```\n\nWhen set, the chat UI gains a **Discuss** toggle next to the send button.\nToggle it ON to route the next turn through the round-table; OFF behaves\nidentically to single-agent chat. If `ROUNDTABLE_AGENTS` is unset or only one\npair parses, the toggle stays disabled and the app behaves exactly as before.\n\nPersonas live in `id/whoami-primary.md` and `id/whoami-verifier.md` — edit them\nto tune how each agent answers or critiques.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## Code Graph\n\nAperio ships a **pre-indexed code knowledge graph** so an agent can query\nyour codebase instead of reading 50 files to answer \"who calls X?\" or\n\"where is Y defined?\". Symbols, calls, imports, and `extends` edges are\nextracted with tree-sitter (JS / TS / JSX / TSX) and stored alongside\nyour memories.\n\nTwo ways to use it:\n\n```bash\n# 1. One-shot index of the current directory\nnode lib/codegraph/indexer.js .\n\n# 2. Live mode — start the server with a file watcher that reindexes on save\nAPERIO_CODEGRAPH=on npm run start:local\n```\n\nThe graph respects `APERIO_ALLOWED_PATHS_TO_READ`, so you can index\nmultiple repos at once (e.g. Aperio + a side project). The sidebar in\nthe web UI has a \"Code\" panel for searching symbols and walking\ncallers / callees visually; the model uses the same data via the\n`code_*` MCP tools listed below.\n\n**Backend support:** Postgres and SQLite both work; LanceDB has no graph\nstore. With SQLite (the default), the graph lives in the same\n`var/aperio.db` file as your memories.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## MCP Tools\n\nAperio exposes **28 tools** over MCP. Any MCP-compatible agent (Cursor, Windsurf, Claude, etc.) can call them.\n\n| Category | Tool | What it does |\n|----------|------|-------------|\n| **Memory** | `remember` | Save a memory with type, title, tags, importance, and optional expiry |\n| | `recall` | Semantic or full-text search across all memories |\n| | `update_memory` | Update an existing memory by ID; tombstones the old version, re-generates its embedding |\n| | `forget` | Delete a memory by ID |\n| | `backfill_embeddings` | Generate embeddings for memories that are missing one |\n| | `deduplicate_memories` | Find and merge near-duplicate memories by cosine similarity |\n| **Wiki** | `wiki_write` | Create or update a wiki article (LLM-authored, cited synthesis); upserts by slug, bumps revision |\n| | `wiki_search` | Hybrid full-text + semantic search over articles — call before `wiki_write` |\n| | `wiki_list` | Browse articles newest-first by tag / status / `updated_since` |\n| | `wiki_get` | Fetch a full article by slug, with breadcrumb and optional stale-refresh |\n| **Code Graph** | `code_search` | Hybrid FTS + semantic search over pre-indexed symbols (functions, classes, methods, consts) |\n| | `code_outline` | List every symbol in a file by line — cheap map before reading |\n| | `code_context` | Fetch the source slice for a qualified symbol, with leading doc and line padding |\n| | `code_callers` | Walk the reverse call graph (depth-capped) — who calls this? |\n| | `code_callees` | Walk the forward call graph (depth-capped) — what does this call? |\n| | `code_repos` | List indexed repos with file / symbol counts and last-indexed timestamp |\n| **Files** | `read_file` | Read a code or text file (max 500 lines per call, paginated via `offset`) |\n| | `write_file` | Create or overwrite a file (subject to write-path guard) |\n| | `append_file` | Append content to an existing file without touching the rest |\n| | `edit_file` | Replace an exact string in a file (`replace_all` for multiple occurrences) |\n| | `scan_project` | Traverse a project folder — returns a file tree and reads key files |\n| | `generate_xlsx` | Generate a multi-sheet `.xlsx` workbook, served for download |\n| **Shell** | `run_node_script` | Run a `.js` script inside an allowed write path; returns its output |\n| | `syntax_check` | Check a JavaScript file for syntax errors without executing it |\n| **Web** | `fetch_url` | Fetch a URL, strip HTML, truncate at 15 000 characters |\n| **Image** | `read_image` | Load an image (file path or base64) for the agent to analyze |\n| | `preprocess_image` | Normalize an image to RGB PNG before sending to a local VLM (strips alpha, letterboxes to 896×896) |\n| | `describe_image` | Send an image to a local Ollama vision model (VLM) and return a text description |\n\n\u003e PowerPoint files are generated by writing a script (see `skills/pptx/`) and running it via `run_node_script` — there is no dedicated `pptx` tool.\n\n\u003e **💡 Tip:** Check [Aperio MCP Tools Guide](https://github.com/BaiGanio/aperio/wiki/MCP-Tools-Guide) for call examples.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## Philosophy\nAperio is open source and self-hosted because **your memories is yours**.\n- It runs entirely on your machine - no API keys, no data leaving your network, no cloud dependency.   \n- Default is local and private. The option - self-hosted. The price - free forever.   \n- Cloud AI is available as a power upgrade, but you will be never forced to use it.    \n\n| | |\n|---|---|\n| 🔒 **Local by default** | ☁️ **Cloud as upgrade** |\n| Ollama + local embeddings — zero external calls | Claude / DeepSeek for deep research \u0026 heavy tasks |\n\n| | |\n|---|---|\n| 🗄️ **Your brain, your data** | 🖥️ **MCP-native** |\n| Postgres or SQLite lives on your machine. You own it. | Any MCP agent plugs in — Cursor, Windsurf, etc. |\n\n| |\n|---|\n| ✅ **Free to run** | |\n| No subscription. No per-message cost. Just your hardware. | |\n\n\u003e #### ‼️ What Aperio Is Not!\n\n| | |\n|---|---|\n| 🚫 **Not a cloud service** | 🚫 **Not a managed product** |\n| No hosted version, no SaaS, no managed infra | No support contracts, SLAs, or guaranteed uptime |\n\n| | |\n|---|---|\n| 🚫 **Not a plugin or extension** | 🚫 **Not a replacement for your AI** |\n| It's a self-hosted server you run yourself | A memory layer alongside Claude, Cursor, etc. |\n\n| | |\n|---|---|\n| 🚫 **Not plug-and-play** | 🚫 **Not production-hardened** |\n| Needs Node.js, Docker, and basic terminal comfort | Early software, built in the open, improving fast |\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## AI Providers\n\nSwitch with a single line in `.env`. Everything else — memories, tools, UI — stays identical.\n\n```env\nAI_PROVIDER=ollama       # \"ollama\" | \"anthropic\" | \"deepseek\" | \"gemini\"\n```\n\n### ⬡ Ollama (Default — Local, Free, Private)\n\nNo API keys, no data leaving your machine.\n\n```env\nAI_PROVIDER=ollama\nOLLAMA_MODEL=qwen2.5:3b\nOLLAMA_BASE_URL=http://localhost:11434\n```\n\nRecommended models (pull with `ollama pull \u003cmodel\u003e`):\n\n| Model | Best for |\n|-------|----------|\n| `qwen2.5:3b` | Default — lightweight, fast, good tool-calling |\n| `llama3.1` | Solid tool-calling, no thinking/reasoning overhead |\n| `qwen3:4b` | Strong reasoning, thinking mode |\n| `deepseek-r1:32b` | Heavy reasoning, requires ≥ 60 GB RAM |\n\n\u003e **💡 Tip:** Set `CHECK_RAM=true` in `.env` to let Aperio auto-select a model based on available RAM.\n\n### ✦ Anthropic Claude (Optional — Cloud Upgrade)\n\nFor heavy research, complex multi-step reasoning, or the strongest tool-calling available.\n\n```env\nAI_PROVIDER=anthropic\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-haiku-4-5-20251001\n```\n\nAvailable models (set via `ANTHROPIC_MODEL`):\n\n| Model | Notes |\n|-------|-------|\n| `claude-haiku-4-5-20251001` | Fast and cost-efficient — good default |\n| `claude-sonnet-4-6` | Balanced performance and cost |\n| `claude-opus-4-7` | Most capable, highest cost |\n\n### ◈ DeepSeek (Optional — Cloud Upgrade)\n\nCost-effective cloud alternative with strong reasoning capabilities.\n\n```env\nAI_PROVIDER=deepseek\nDEEPSEEK_API_KEY=sk-...\nDEEPSEEK_MODEL=deepseek-chat\n```\n\nSign up at [platform.deepseek.com](https://platform.deepseek.com). No vision support — image tools are disabled in DeepSeek mode.\n\n### ◆ Google Gemini (Optional — Cloud Upgrade)\n\nLarge context window with native vision support.\n\n```env\nAI_PROVIDER=gemini\nGEMINI_API_KEY=...\nGEMINI_MODEL=gemini-2.0-flash\n```\n\nGet a key from [aistudio.google.com](https://aistudio.google.com/apikey).\n\n---\n\n## Embeddings\n\nEmbeddings power semantic search across your memories. Aperio supports two providers:\n\n```env\nEMBEDDING_PROVIDER=transformers   # \"transformers\" | \"voyage\"\n```\n\n### HuggingFace Transformers (Default — Fully Local)\n\nDownloads `mixedbread-ai/mxbai-embed-large-v1` (ONNX, quantized) on first run. No daemon, no API key, no network calls after the initial download.\n\n```env\nEMBEDDING_PROVIDER=transformers\n```\n\n### Voyage AI (Optional — Cloud)\n\nHigher-quality embeddings, free tier: 50M tokens/month.\n\n```env\nEMBEDDING_PROVIDER=voyage\nVOYAGE_API_KEY=pa-...\n```\n\nSign up at [dash.voyageai.com](https://dash.voyageai.com).\n\n#### Q: Is that all?\n\u003e **💡 Tip:** Check out our wiki pages [AI Agents Comparison](https://github.com/BaiGanio/aperio/wiki/AI-Agents-Comparison) \u0026 [Embeddings](https://github.com/BaiGanio/aperio/wiki/Embeddings) for more details.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## Privacy\n\n### Reading Files with Local AI\n\nOllama itself has no file system access — it's purely an inference engine.\nAperio's MCP layer bridges the gap.\n\nWhen you ask the AI to read a file, here's what actually happens:\n```\nYou       →  \"read /path/to/server.js and explain the WebSocket handler\"\nMCP Server →  calls read_file tool, loads the file from disk\nOllama    →  receives the file contents as context, reasons over it\nYou       ←  answer based on your actual code\n```\n\nThe model never touches your file system directly.\nAperio reads the file and injects the content into the conversation.\n\n#### Q: You call this privacy?\n\u003e 💡 Check out our wiki page [MPC Tools](https://github.com/BaiGanio/aperio/wiki/MPC-Tools) for more details.  \n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n## Security\nAperio runs on your machine and has access to your file system through the `scan_project`, `write_file`, `append_file`, and `read_file` tools. File operations are gated by a path safety system — read and write access are controlled independently.\n\n### File System Access\n\nAll file operations go through `lib/routes/paths.js`, which resolves and validates every path before it reaches the disk.\n\nTwo environment variables control what is accessible:\n\n```env\n# Allow read operations only inside these directories (comma-separated absolute paths)\nAPERIO_ALLOWED_PATHS_TO_READ=/Users/yourname/projects,/Users/yourname/documents\n\n# Allow write operations only inside these directories (comma-separated absolute paths)\nAPERIO_ALLOWED_PATHS_TO_WRITE=/Users/yourname/projects\n```\n\n**How path resolution works:**\n\n1. Both values default to the current working directory (`process.cwd()`) when not set — which is the Aperio project root when you run `npm run start:local`.\n2. Paths are resolved to absolute form at startup. `~` is expanded to the working directory.\n3. A request to read or write `/some/path/file.txt` is allowed only if its resolved absolute path starts with one of the permitted directories. Paths outside the allow-list are rejected with a clear error message before any I/O occurs.\n4. Read and write guards are separate. You can grant broad read access while keeping write access narrow — for example, read your entire `~/projects` tree but only write inside the Aperio project root.\n\n**What the model can and cannot do:**\n\n| Operation | Guard | Default scope |\n|-----------|-------|---------------|\n| `read_file` | `APERIO_ALLOWED_PATHS_TO_READ` | Project root |\n| `write_file` | `APERIO_ALLOWED_PATHS_TO_WRITE` | Project root |\n| `append_file` | `APERIO_ALLOWED_PATHS_TO_WRITE` | Project root |\n| `scan_project` | `APERIO_ALLOWED_PATHS_TO_READ` | Project root |\n\nAdditionally, `read_file` enforces:\n- **Extension allow-list** — only code and text files (`.js`, `.ts`, `.py`, `.md`, `.json`, `.sql`, `.sh`, etc.)\n- **Size cap** — files larger than 500 KB are rejected\n- **Pagination** — reads at most 500 lines per call; use the `offset` parameter to page through larger files\n\n### Shell Execution (`run_shell`)\n\nBy default the model can only execute `.js` files (the `run_node_script` tool). The optional `run_shell` tool widens this to a fixed allow-list of real binaries — used for QA steps that need them, such as pptx visual QA (`soffice` → `pdftoppm`) or grepping extracted text for leftover placeholders. It is **off by default** and gated by two environment variables:\n\n```env\n# Master switch — enables run_shell at all. When unset, the tool refuses every call.\nAPERIO_ENABLE_SHELL=1\n\n# Opt-in for LOCAL Ollama models. Cloud providers (Anthropic/Gemini/DeepSeek) get\n# run_shell as soon as the master switch is on; local models stay node-only unless\n# you also set this, since smaller local models are prone to tool-call thrashing.\nAPERIO_SHELL_LOCAL=1\n```\n\nConstraints, enforced in `mcp/tools/shell.js`:\n\n| Guard | Behavior |\n|-------|----------|\n| Allow-list | Only `node, npm, git, ls, cat, grep, rg, find, head, tail, python3, soffice, pdftoppm` run |\n| Operators | `;`, `\u0026\u0026`, `\\|\\|`, `\u0026`, `\u003c`, `\u003e`, backticks, `$()` are rejected; a single `\\|` pipe is permitted |\n| Working dir | Commands run in the active session workspace (or an explicit `cwd` within an allowed write path) |\n| Limits | 60 s timeout, 200 KB output cap (shared with `run_node_script`) |\n| Per-model gate | Disabled providers/models never see the tool at all (see `isShellAllowedFor` in `lib/agent/index.js`) |\n\n📄 Take a notes:\n- Only run Aperio on a machine you trust\n- Do not expose the MCP server or web UI to the public internet without authentication\n- Review any file write operations before confirming them — `write_file` overwrites completely with no undo\n- The AI model can be prompted (or hallucinate) to write to sensitive paths — always review before confirming\n- Never commit your `.env` file — it contains your database URL and API keys\n- Write paths should be equal to or a strict subset of read paths\n\n#### Q: And this is it?\n\u003e 💡 Check out our wiki page [Path safety](https://github.com/BaiGanio/aperio/wiki/Path-Safety) for more details.\n\n\u003cp align=\"right\"\u003e\n  [\u003ca href=\"#top\"\u003eBack to top ↑\u003c/a\u003e]\n\u003c/p\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**One brain. Every agent. Nothing forgotten.**\n\n*From Latin* aperire *— to open, to reveal, to bring into the light.*\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaiganio%2Faperio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaiganio%2Faperio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaiganio%2Faperio/lists"}