Skip to content

maakle/holo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

388 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Holo

Holo

The agent context layer for your company.

CI Community Edition: AGPL-3.0 Enterprise Edition: commercial Status: pre-alpha Documentation GitHub stars

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.


Table of contents


How it works

  1. 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.
  2. Unify. Holo ingests, chunks, embeds, and indexes. Hybrid retrieval (pgvector + tsvector fused with RRF) over a single ACL-aware index.
  3. 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.
  4. 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.


The name

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.


Why this exists

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.


What teams build on Holo

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.

1. Security questionnaires answered with citations (security & compliance)

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

2. Drafted support replies with the right sources attached (customer support)

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

3. Every call starts with full context (sales / CS)

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

4. One search box across every system (everyone else)

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

Architecture

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
Loading
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/clinpx @holo/cli init.

Full reasoning, alternatives, and migration paths in docs/ARCHITECTURE.md.


Quickstart (self-host)

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:3000

Why --profile app? Plain docker compose up -d brings up just the infra (postgres + redis), which is what you want for local development. --profile app adds 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}'

One public URL

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.


Deploy (Railway)

Deploy on Railway

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 a docker-compose.yml that works with most of them today, but we're focused on a single, well-supported deploy path for the initial launch.

How environment variables work

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.

Migrating from a two-host deployment

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:

  1. On holo-web — add GATEWAY_INTERNAL_URL pointing at the gateway's internal address (e.g., http://${{Gateway.RAILWAY_PRIVATE_DOMAIN}}:8080 on Railway, http://gateway:8080 on Docker Compose / Coolify). Redeploy. The /mcp and /v1/* rewrites now have a working internal target.
  2. On holo-gateway and holo-worker — set MCP_PUBLIC_URL to the same value as WEB_PUBLIC_URL. (Or unset MCP_PUBLIC_URL on holo-web only; it derives from WEB_PUBLIC_URL.)
  3. 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-web origin.
  4. 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.


Development

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 reload

pnpm 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/.


Roadmap and vision

Deferred from the MVP

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.

Contributing

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.

Editions

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.

License

See LICENSING.md for the breakdown.

About

The agent context layer for all your companies knowledge

Resources

License

AGPL-3.0, Unknown licenses found

Licenses found

AGPL-3.0
LICENSE
Unknown
LICENSE-EE

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages