Connect your tools once. Holo unifies the data, learns the procedures your team actually runs, and exposes them as callable tools over MCP and OpenAPI — so any agent (Claude, Cursor, ChatGPT, your own) plugs into the same foundation, with scoped access and full observability.
Bring your own agent. Layer today. Agent OS tomorrow.
Status: Pre-alpha. 20 connectors live (GitHub, GitLab, Slack, Notion, Grain, Pylon, HubSpot, Linear, Mintlify Docs, Prismic CMS, Zendesk Help Center, Webcrawl/Firecrawl, Google Drive, Airtable, Google Chat, Asana, Jira, Confluence, Stripe, Salesforce), hybrid RRF search, MCP + REST/OpenAPI, DCR OAuth provider, observability + audit + skill marketplace shipped. Not yet ready for production traffic; internal dogfood underway.
- How it works
- The name
- Why this exists
- What teams build on Holo
- Architecture
- Quickstart (self-host)
- Deploy (Railway)
- Development
- Roadmap and vision
- Contributing
- Editions
- License
- Connect the tools your work lives in — 20 connectors today across code & PM (GitHub, GitLab, Linear, Jira, Asana), chat (Slack, Google Chat), docs & knowledge (Notion, Confluence, Mintlify Docs, Prismic CMS, Webcrawl/Firecrawl), files (Google Drive, Airtable), GTM (HubSpot, Salesforce, Stripe), support (Zendesk, Pylon), and meetings (Grain). One OAuth or API key per source, allowlist-scoped at ingestion.
- Unify. Holo ingests, chunks, embeds, and indexes. Hybrid retrieval (pgvector + tsvector fused with RRF) over a single ACL-aware index.
- Expose. A small set of MCP tools and a parallel REST/OpenAPI surface let any agent — internal or external — search, fetch, and invoke learned procedures.
- Observe. Every agent call is logged, attributable, and replayable. Today: ingestion-time allowlists bound which channels, repos, and pages enter Holo at all. Next: per-agent tool allowlists and row-level data scopes finish the personas model.
The wedge in one sentence: stop re-implementing context fetchers per agent, and stop letting agents see everything just because the OAuth token does.
Holo is named after the Star Wars holocron — a small object encrypted with compressed knowledge from many sources, accessed by anyone with the right key. We shortened it to holo because nobody wants to type holocron init every time.
The metaphor maps directly: a holocron compresses what many people knew into one object any Jedi could query. Holo compresses what your company's tools collectively know into one endpoint any agent on your team can call. Same shape, different century.
Engineering teams in 2026 don't ship one custom AI agent — they ship several. A Slack-triggered Cursor agent over the codebase. A Notion-based agent that prepares interview rubrics from Grain recordings. A customer-success copilot over Pylon and HubSpot. Each agent solves a different workflow. Each one re-implements its own context-fetching pipeline.
The cost compounds with every new agent. Cross-agent context is impossible because the context layer is a per-agent fork. When a Notion page moves or a Slack channel archives, every agent breaks individually.
Holo is the missing shared layer — the queryable context layer under all your team's agent operations and the procedural extraction layer that turns scattered artifacts into invokable skills. Two adjacent YC RFSs (AI Operating System for Companies, Diana Hu; Company Brain, Tom Blomfield) describe the bet. Holo is the open-source, self-hostable take.
Who consumes Holo: every agent on a team. Claude in Cursor over the codebase. A custom Slack bot for support. ChatGPT Actions for an external partner. An internal copilot for customer success. None of them re-implement the retrieval layer; all of them inherit the same scopes, the same audit trail, and the same set of learned procedures.
Holo is a primitive, not a product. These are the four shapes the same layer takes in the first month of use — same backend, same audit trail, different consumers. The first three drive an agent over MCP; the fourth is plain REST with no agent in the loop.
A founder or security lead pastes a customer's questionnaire into a chat agent. Holo pulls prior answers from Notion, the architecture docs, and the actual repo for evidence, then drafts responses with a link back to every source. The week-long scramble before each enterprise deal turns into a one-pass review.
search("data retention policy") → bash cat /notion/security/retention.md → bash cat /github/acme/api/docs/data-handling.md → draft answers with citations
A Pylon or Zendesk webhook fires on a new ticket. Holo pulls the customer's history, the matching Mintlify docs page, and the closest past resolution, and posts a draft reply for the human to approve. Time-to-first-response drops; tone stays consistent across the team.
search(ticket.subject) → bash cat /pylon/tickets/<id>.md → bash cat /mintlify/<page>.md → draft reply for approval
Five minutes before a meeting with Acme, a calendar-triggered agent searches Grain transcripts, the HubSpot deal record, and any open Pylon issues, and posts a digest to the prep doc. Account owners walk in knowing exactly where things stand instead of opening four tabs in the parking lot.
search("Acme Corp") → bash cat /grain/<date>/<title>-<id>.md → bash cat /pylon/tickets/<id>.md → digest to prep doc
A dashboard search box, a Slack /ask command, or an internal Retool app calls the REST surface directly. Ops, design, PM, and revops get ranked results across all 20 connectors with deep links back to the source — no agent required, no MCP client, no LLM in the path. The same retrieval primitive that powers the agents above is also the one humans hit when they just want to find something.
POST /v1/search { query, limit } → ranked chunks with snippet_url back to source
Three apps. 21 packages. 20 connectors. AGPL-3.0 (Community Edition).
flowchart LR
subgraph A["Agents (MCP or REST clients)"]
direction TB
A1["Claude · Cursor"]
A2["ChatGPT Actions"]
A3["Slack bot · custom"]
end
subgraph H["Holo"]
direction TB
GW["apps/gateway · Hono<br/>MCP /mcp · REST /v1<br/>OAuth 2.1 + PKCE · DCR"]
WEB["apps/web · Next.js 16<br/>dashboard · Better Auth<br/>OAuth callbacks · DCR UI"]
WK["apps/worker · NestJS + BullMQ<br/>ingest · chunk · embed · sync<br/>step() checkpoints"]
PG[("Postgres 16<br/>pgvector + tsvector + RRF<br/>ACL-aware index")]
RD[("Redis 7<br/>BullMQ queue")]
end
subgraph S["Sources (20 connectors)"]
direction TB
S1["Code & PM<br/>GitHub · GitLab · Linear<br/>Jira · Asana"]
S2["Chat & Meetings<br/>Slack · Google Chat · Grain"]
S3["Docs & Knowledge<br/>Notion · Confluence · Mintlify<br/>Prismic · Webcrawl"]
S4["Files<br/>Google Drive · Airtable"]
S5["GTM<br/>HubSpot · Salesforce · Stripe"]
S6["Support<br/>Zendesk · Pylon"]
end
A1 -->|"search · fetch · invoke"| GW
A2 --> GW
A3 --> GW
GW --> PG
GW --> RD
WEB --> PG
WEB -. "OAuth / API key" .-> S
WK --> PG
WK --> RD
WK -->|"sync · webhook"| S
| Layer | Choice |
|---|---|
| Dashboard | apps/web — Next.js 16, React 19. Marketing, sign-in, sidebar app shell, all OAuth callbacks, MCP DCR endpoints. |
| Gateway | apps/gateway — Hono. MCP JSON-RPC at POST /mcp and OpenAPI/REST at /v1/*. Scalar API reference at /docs. Default port 8080. |
| Worker | apps/worker — NestJS standalone + BullMQ. Per-connector ingestion, embedding pipeline, sync scheduler with cursor store, ACL extraction. step() checkpoint helper for crash-resumable jobs. |
| ORM / DB | Drizzle 0.45 on Postgres 16 + pgvector + pg_trgm |
| Cache / Queue | Redis 7 (maxmemory-policy=noeviction) |
| Auth | Better Auth 1.6 — GitHub OAuth + email OTP (Resend); multi-tenant organization plugin; OAuth-provider routes for MCP DCR (RFC 7591 / 9728 / 8414). |
| Search | packages/retrieval-core — pgvector + tsvector fused with RRF in a single SQL CTE; dual-model embedding fallback (OpenAI + Voyage); acl_subjects && user_subjects filter. |
| Connectors | packages/connectors — 20 connectors: GitHub, GitLab, Slack, Notion, Grain, Pylon, HubSpot, Linear, Mintlify Docs, Prismic, Zendesk, Webcrawl (Firecrawl-backed), Google Drive, Airtable, Google Chat, Asana, Jira, Confluence, Stripe, Salesforce. Mix of OAuth (refreshable & non), API key, service account, and no-auth. Allowlist enforcement via the connector_allowlists table (glob or exact-id, audit-trailed). |
| Skills | packages/skills — Anthropic skill format, golden-set + ROUGE-L eval harness, marketplace publish flow with redaction. MCP exposes list_skills, get_skill, execute_skill. |
| Custom tools | packages/custom-tools — CLI-as-tool registration (e.g. bq query, psql -c …) without writing a connector. |
| CLI | packages/cli — npx @holo/cli init. |
Full reasoning, alternatives, and migration paths in docs/ARCHITECTURE.md.
mkdir my-holo && cd my-holo
npx @holo/cli init
# fill the placeholders the wizard prints in .env, then:
docker compose --profile app up -d
open http://localhost:3000Why
--profile app? Plaindocker compose up -dbrings up just the infra (postgres + redis), which is what you want for local development.--profile appadds the three application containers (web,gateway,worker) on top — the right mode for self-hosting.
Requirements: Docker 24+, Node 20+ (only for npx).
Connect your agent:
{
"mcpServers": {
"holo": {
"url": "http://localhost:8080/mcp",
"headers": { "Authorization": "Bearer <token-from-/connect-agent>" }
}
}
}REST equivalent:
curl -X POST http://localhost:8080/v1/search \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"q": "how do we onboard a new ATS partner?", "topK": 5}'Self-hosters need one public URL (DNS + TLS + tunnel/proxy) pointing at the web service on :3000. The web app reverse-proxies agent traffic (/mcp, /v1/*, webhooks like /slack/*) to the gateway internally — see ADR 0009 for the design and the two-origin override.
Quick local tunnel:
ngrok http 3000 # or: cloudflared tunnel run <your-tunnel>Then set WEB_PUBLIC_URL and BETTER_AUTH_URL in .env to the tunnel URL and restart. MCP_PUBLIC_URL derives automatically — no need to set it.
The template provisions five services: holo-web (Next.js), holo-gateway (Hono MCP + REST), holo-worker (NestJS + BullMQ), postgres (pgvector/pgvector:pg16), and redis (7-alpine).
Coolify and other self-hosted PaaS are on the roadmap (
docs/ROADMAP.md↗). The repo ships adocker-compose.ymlthat works with most of them today, but we're focused on a single, well-supported deploy path for the initial launch.
Three categories, three different mechanisms:
| Category | Vars | How they get set |
|---|---|---|
| Auto-wired by Railway | DATABASE_URL, REDIS_URL |
Reference variables (${{Postgres.DATABASE_URL}}, ${{Redis.REDIS_URL}}) — set them once on holo-web/holo-gateway/holo-worker after the DB and Redis services come up. |
| You generate (secrets) | POSTGRES_PASSWORD, BETTER_AUTH_SECRET, HOLO_TOKEN_ENCRYPTION_KEY |
openssl rand -base64 32 for each. Paste into the project's env panel before the first deploy. POSTGRES_PASSWORD must match what DATABASE_URL references. |
| You provide (public URLs + OAuth) | BETTER_AUTH_URL, WEB_PUBLIC_URL, GITHUB_LOGIN_CLIENT_ID/_SECRET, ANTHROPIC_API_KEY |
Set after the first deploy gives you the public hostnames. BETTER_AUTH_URL and WEB_PUBLIC_URL point at holo-web's public URL. The GitHub OAuth app's callback must be ${BETTER_AUTH_URL}/api/auth/callback/github. Single-origin model: MCP_PUBLIC_URL is derived from WEB_PUBLIC_URL by default — set it explicitly only if you intentionally publish the gateway on a separate hostname (see ADR 0009). |
Connector credentials (Slack, GitHub App, GitLab, HubSpot, Salesforce, Pylon, Notion, Grain, Linear, Airtable, Asana, Jira, Confluence, Stripe, Zendesk, Google Drive / Chat service account, Prismic, Mintlify, Webcrawl/Firecrawl) are not required at boot — leave them blank, deploy, then add them per-connector in the Holo dashboard once apps/web is reachable. The only worker-side env that gates a connector at boot is FIRECRAWL_API_KEY (powers the Webcrawl connector, since it's Holo-team-operated rather than per-org).
Full env reference: .env.example.
Note on the Railway template format.
railway.toml's multi-service block ([[services]]) is best-effort — Railway's first-class multi-service experience is via the published Template Marketplace, which we haven't shipped yet (docs/ROADMAP.md↗). After clicking the button, verify each service in the Railway dashboard and set reference variables. Tracking issue welcome.
If you deployed Holo before ADR 0009 and currently expose both holo-web and holo-gateway publicly, migrate to single-origin without downtime in this order:
- On
holo-web— addGATEWAY_INTERNAL_URLpointing at the gateway's internal address (e.g.,http://${{Gateway.RAILWAY_PRIVATE_DOMAIN}}:8080on Railway,http://gateway:8080on Docker Compose / Coolify). Redeploy. The/mcpand/v1/*rewrites now have a working internal target. - On
holo-gatewayandholo-worker— setMCP_PUBLIC_URLto the same value asWEB_PUBLIC_URL. (Or unsetMCP_PUBLIC_URLonholo-webonly; it derives fromWEB_PUBLIC_URL.) - Update external services — OAuth callbacks (GitHub login, connector OAuth flows) and webhook URLs (Slack Events/Commands/Interactivity, Stripe, GitHub App, Google Chat, Teams) to point at the single
holo-weborigin. - Remove the gateway's public domain in your hosting dashboard and delete the obsolete DNS record.
Doing step 1 before step 4 avoids a window where /mcp returns 502 because the web has no proxy target yet.
git clone https://github.com/maakle/holo.git
cd holo && pnpm install
pnpm bootstrap # generates .env with random secrets, starts postgres + redis, runs migrations
# Add GitHub OAuth credentials to .env (sign-in + connector — see CONTRIBUTING.md)
pnpm dev # web + gateway + worker, hot reloadpnpm bootstrap is idempotent and handles first-run plumbing. pnpm dev runs scripts/check-env.mjs first, so missing env vars fail fast with a clear message instead of mid-boot stack traces.
Prefer cloud dev? The repo ships a .devcontainer/ — open in GitHub Codespaces or VS Code Dev Containers and pnpm bootstrap runs automatically.
Two GitHub OAuth apps are required (login + connector); see decision 0001 for why the split is intentional. Full setup notes in CONTRIBUTING.md. Per-connector OAuth setup (Slack, GitHub, etc.) lives in docs/connectors/.
docs/ROADMAP.md— what's next, milestone-by-milestonedocs/VISION.md— why holo exists, in 200 wordsdocs/decisions/— architectural decision records
The MVP is intentionally narrow: connect tools → unify into a substrate → expose via MCP and OpenAPI → bring your own agent (Claude, Cursor, ChatGPT, Slack bot, etc.). Anything beyond that is parked.
What's stubbed out today and why — click to expand
Specifically, the following surfaces ship as 501 stubs today and are deferred to a post-launch milestone:
- Skills (
/skills) — manual artifact labeling and Claude-driven skill synthesis from labeled examples - Procedure auto-discovery (
/skills/discover, nightly cron) — clusters cross-connector artifacts into work episodes and proposes named procedures for the user to accept / reject - Skill runs (
/skills/runs) — execution history and observability for synthesized skills - Marketplace (
/marketplace) — publishing accepted skills for other orgs to install
The implementation is preserved in the repo (packages/skills/, packages/discovery/, apps/web/src/lib/synthesize-and-persist.ts, apps/web/src/lib/discovery-db.ts, the procedure_* tables) so re-enabling is route-handler restoration, not a re-build. The plan that produced the auto-discovery code is at docs/superpowers/plans/2026-05-05-procedure-auto-discovery.md. Full implementation history is on the feat/procedure-auto-discovery branch through commit 38f49de.
Why deferred: the auto-discovery loop only pays off once the substrate has rich cross-connector signal (Slack threads referencing PRs, Grain calls tagged to HubSpot deals, etc.). MVP design partners' data is mostly single-connector — the algorithm is correct but starves for input. We'd rather ship the substrate, expose it via MCP/OpenAPI, watch agents use it for a quarter, and let the procedure layer emerge from real usage instead of synthesizing it speculatively.
Read CONTRIBUTING.md before opening a PR. First-time contributors will be prompted to sign the CLA. Good first issues tagged good-first-issue.
When you ship a user-visible feature, also add a PostHog event for it — see docs/analytics.md. Analytics are optional: leave the POSTHOG_* env vars unset and the whole stack runs with zero outbound analytics traffic.
Holo ships in two editions in this same repo:
- Community Edition (CE) — AGPL-3.0. Always free to self-host for your company. Covers the entire core: all 20 connectors, hybrid search, MCP + REST gateway, OAuth provider, dashboard, worker, agent observability, skill synthesis + execution + marketplace, multi-tenant orgs, the CLI. If a file's path doesn't contain
/ee/, it's CE and it's AGPL-3.0. Building a hosted commercial product on top of holo without the AGPL source-disclosure obligation requires a commercial license — open an issue. - Enterprise Edition (EE) — commercial license. Lives under
**/ee/**. Free to read, fork, and run in development; production use requires a paid subscription. EE surfaces (rolled out incrementally):- 👥 Collaboration — share chats and agents with members of your organization.
- 🔐 Single Sign-On — Google OAuth, OIDC, SAML; SCIM for group sync and user provisioning.
- 🛡️ Role-Based Access Control — differentiated roles below the org owner (restricted member tiers, custom roles) and per-resource RBAC over agents, actions, skills, and connectors. CE invites everyone as a full collaborator.
- 📊 Analytics — usage broken down by team, LLM, agent, skill, and connector.
- 🕵️ Per-call audit log + Query History — tamper-evident hash chain over every tool invocation; long-retention, exportable audit of every agent and human query; configurable retention, SIEM hooks.
- 💻 Custom code — pre/post-processing hooks to strip PII, reject sensitive queries, or run custom analysis.
- 🎨 Whitelabeling — custom name, logo, banners, brand color, and domain.
Full edition breakdown, what's CE vs EE today, and the contribution rules for each: LICENSING.md.
- Community Edition — AGPL-3.0
- Enterprise Edition — commercial
See LICENSING.md for the breakdown.
