Sign inSign up

nacrecontextlayer/nacre

By nacrecontextlayer

•Updated 5 minutes ago

Self-hosted knowledge index with fine-grained access control. MCP + REST. Apache 2.0.

Image
Machine learning & AI
Data science
Databases & storage
0

638

nacrecontextlayer/nacre repository overview

Nacre

⁠Nacre

Your index. Your access rules. Your perimeter. Agents see exactly what they're allowed to see.

nacre.work⁠ · Docs⁠ · Quickstart⁠ · Source⁠ · Releases⁠ · Discussions⁠

Nacre is a self-hosted knowledge index with fine-grained access control. Agents reach it over MCP, applications over a REST API. No chat interface, no company assistant — just the context layer underneath them.

⁠This image

One image, three processes, one migrator. The entry point decides which:

commandruns
node packages/api/dist/main.jsthe REST API and authorization service, port 8080 (default)
node packages/mcp/dist/main.jsthe MCP server, Streamable HTTP on port 8081
node packages/worker/dist/main.jsthe indexing pipeline: parse, chunk, embed
node packages/core/dist/migrate-main.jsthe schema migrator, run once before the others

It needs PostgreSQL, Qdrant and Redis beside it, the parser sidecar nacrecontextlayer/nacre-parser⁠ and an OpenAI-compatible embedding endpoint. The Compose files in the repository wire all of it; the Helm chart is for Kubernetes. Every variable is documented in docs/config.md⁠.

Tags: {version} and latest, amd64 and arm64. ghcr.io/nacre-work/nacre is the canonical address; this repository is a mirror pushed by the same build at the same tags, so the two are byte for byte the same image.

⁠Why

Vector search is a solved problem. What isn't solved: making sure an agent querying a company index sees exactly the documents the requesting user is cleared for — and being able to prove it to an auditor.

  • Permissions that inherit. Workspaces → layers, with read/write/admin inherited top-down. write does not imply read; admin implies both. Document-level grants and deny rules are commercial — this build refuses them and says so, rather than accepting a rule it cannot propagate.
  • Filtering happens inside the index. Access filters are applied during HNSW traversal, not after ranking, so top_k returns k permitted results rather than k minus whatever got stripped out.
  • MCP as a first-class surface. Streamable HTTP per the 2026-07-28 spec, and local STDIO for developer agents. Agents authenticate with a service account key; OAuth discovery is served (RFC 9728), and client registration is the authorization server's business rather than ours.
  • Hybrid retrieval, because agents ask for identifiers. Dense vectors and BM25 fused with reciprocal rank fusion, plus a cross-encoder rerank where a deployment configures one. An agent searching for SQLSTATE 23505, an invoice number or a variable name needs the literal match, and a dense-only index does not reliably return it.
  • Bring your own models. Embeddings through any OpenAI-compatible endpoint, bound per layer. Changing the model on an existing layer is a reindex that keeps search answering throughout, and it is gated on recall against a query set you supply before it switches over.
  • A command line client. npx @nacre.work/cli signs in, creates a layer, walks a directory into it and searches. A document that fails to index is a non-zero exit, so a nightly ingest cannot report success having indexed nothing.
  • Stays inside your network. Docker Compose, no phone-home.

⁠Quickstart

git clone https://github.com/nacre-work/nacre && cd nacre
cp .env.example .env
docker compose --profile minimal up -d

Full walkthrough: docs/quickstart.md⁠. On an Apple Silicon Mac, read docs/apple-silicon.md⁠ first — the images are arm64 and the stack is native, but the embedder is the one piece you run on the host. Upgrading between versions: docs/upgrading.md⁠.

⁠What it does

Create an organization, create a layer, grant someone read, ingest a document, poll the job to indexed, search and get the chunk back — and search as someone without the grant and get nothing while the vectors are still sitting in the index. Revoking a grant removes the document from the next search; the permitted set is computed per request, so there is nothing to wait for.

A document can be sent as JSON or uploaded as a form, and a PDF, an Office or OpenDocument file, an EPUB or an RTF is extracted by the parser sidecar. Both signals have to agree — the declared type and the bytes' signature — because a declared type the bytes contradict is a disagreement, and sniffing alone would make the declared type decoration.

Sign-in is email and password with rotating refresh tokens, an optional second factor (TOTP or WebAuthn), and tokens signed with a shared secret or an Ed25519 key whose public half is published at /.well-known/jwks.json. The access log is readable at GET /v1/audit — newest first, cursor-paged, as JSON, JSONL or CSV.

Search is rate limited per organization, unsafe methods take an Idempotency-Key, collections page by cursor, and a layer can be moved onto a different embedding model with search staying available throughout.

⁠Invariants

Six rules. Breaking any of them is a security incident, not a bug. Details in docs/authz.md⁠.

  1. The organization comes from the token and nowhere else.
  2. Access filtering is a pre-filter, never a post-filter.
  3. A failure to evaluate permissions denies access.
  4. "No permission" and "no such object" return identical responses.
  5. A deleted document is never returned, including before garbage collection.
  6. write does not imply read.

⁠Connectors

Reference connectors keep a source in sync with an index — git, S3, SQL, Google Drive, MongoDB and IMAP — each one container, configured through its environment. They are nacrecontextlayer/connector-<name>⁠ here and github.com/nacre-work/connectors⁠ at the source.

⁠License

Apache 2.0 — all of it. Everything in this image is in the public repository and stays there.

Multi-tenancy, SSO/SCIM, document-level deny rules, EMA, SIEM export, global admin and backup are commercial modules. They live in a separate private repository under a separate license and are not distributed with this image — see docs/licensing.md⁠ for the line between the two. Where this build meets one of them it refuses in the open: a deny rule or a document-scoped grant is answered 400 with the reason, rather than accepted and silently not enforced.

The Nacre name and mark are trademarks; see TRADEMARK.md⁠.

Tag summary

Content type

Image

Digest

sha256:0fe6d5232…

Size

96.6 MB

Last updated

5 minutes ago

docker pull nacrecontextlayer/nacre