Nacre

Capa de contexto autoalojada y consciente de permisos. La búsqueda devuelve solo lo que el llamador puede leer.

Documentación

Nacre

Nacre

Tu índice. Tus reglas de acceso. Tu perímetro.
Los agentes ven exactamente lo que se les permite ver.

nacre.work · Documentación · Inicio rápido · Discusiones


Nacre es un índice de conocimiento autoalojado con control de acceso de grano fino. Los agentes acceden a él mediante MCP, y las aplicaciones mediante una API REST. Sin interfaz de chat, sin asistente de empresa — solo la capa de contexto que los sustenta.

Por qué

La búsqueda vectorial es un problema resuelto. Lo que no está resuelto: garantizar que un agente que consulta un índice de empresa vea exactamente los documentos para los que el usuario solicitante está autorizado — y poder demostrarlo ante un auditor.

  • Permisos que se heredan. Espacios de trabajo → capas, con read/write/admin heredados de arriba hacia abajo. write no implica read; admin implica ambos. Las concesiones a nivel de documento y las reglas de denegación son comerciales — esta compilación las rechaza y lo dice, en lugar de aceptar una regla que no puede propagar.
  • El filtrado ocurre dentro del índice. Los filtros de acceso se aplican durante el recorrido HNSW, no después de la clasificación, por lo que top_k devuelve k resultados permitidos en lugar de k menos lo que se haya eliminado.
  • MCP como superficie de primera clase. HTTP transmisible según la especificación del 28 de julio de 2026, y STDIO local para agentes de desarrollo. Los agentes se autentican con una clave de cuenta de servicio; el descubrimiento OAuth se sirve (RFC 9728), y el registro de clientes es asunto del servidor de autorización, no nuestro.
  • Recuperación híbrida, porque los agentes piden identificadores. Vectores densos y BM25 fusionados con fusión de rango recíproco, más un reordenamiento con codificador cruzado donde una implementación lo configure. No se ofrece como diferenciador — la línea anterior es la honesta — pero un agente que busca SQLSTATE 23505, un número de factura o un nombre de variable necesita la coincidencia literal, y un índice solo denso no la devuelve de forma fiable.
  • Trae tus propios modelos. Incrustaciones mediante cualquier endpoint compatible con OpenAI, vinculado por capa. Cambiar el modelo en una capa existente es un reindexado que mantiene la búsqueda respondiendo durante todo el proceso, y está condicionado a la recuperación contra un conjunto de consultas que tú proporcionas antes de que cambie.
  • Un cliente de línea de comandos. npx @nacre.work/cli inicia sesión, crea una capa, recorre un directorio e indexa, y busca — las cuatro invocaciones de curl que el inicio rápido detalla, para cuando quieres el resultado en lugar del contrato. Un documento que no se indexa produce una salida distinta de cero, por lo que una ingesta nocturna no puede informar éxito habiendo indexado nada.
  • Permanece dentro de tu red. Docker Compose, sin llamadas a casa.

Inicio rápido

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

Guía completa: docs/quickstart.md.

En un Mac con Apple Silicon, lee docs/apple-silicon.md primero — las imágenes son arm64 y el stack es nativo, pero el incrustador es la única pieza que ejecutas en el host.

Estructura

packages/api        REST API and authorization service
packages/mcp        MCP server (Streamable HTTP + STDIO)
packages/worker     indexing pipeline: parse, chunk, embed
packages/core       data model, permission resolver, shared types
packages/sdk        TypeScript SDK
packages/admin      community admin UI
services/parser     Python sidecar: bytes → {text, blocks, metadata}
docs/               specifications — normative, and ahead of the code

Estado

Temprano, y funciona. El ciclo funciona de extremo a extremo y se ha manejado a mano contra un PostgreSQL real y un Qdrant real: crear una organización, crear una capa, conceder a alguien read, ingestar un documento, consultar el trabajo hasta indexed, buscar y obtener el fragmento — y buscar como alguien sin la concesión y obtener nada mientras los vectores siguen en el índice. Ambas superficies funcionan, REST y MCP sobre Streamable HTTP y STDIO por igual. Revocar una concesión elimina el documento de los resultados, y el recálculo que actualiza las etiquetas del índice se ejecuta en el trabajador con una métrica sobre cuánto está retrasado.

La búsqueda tiene límite de velocidad por organización, los métodos no seguros requieren un Idempotency-Key, las colecciones se paginan por cursor, y el reordenamiento se ejecuta en la ruta de búsqueda cuando una implementación configura un reordenador. Los vectores marcados como eliminados se recogen, y el SDK y la interfaz de administración están escritos.

Iniciar sesión funciona: correo electrónico y contraseña, con tokens de actualización rotativos que terminan la sesión si uno se reproduce. init crea el primer administrador e imprime una contraseña generada una vez. El SSO es un módulo comercial.

El registro de acceso es legible: GET /v1/audit, más reciente primero, paginado por cursor, como JSON, JSONL o CSV. org_admin ve qué documentos se leyeron — la pregunta que un registro de auditoría existe para responder — y platform_admin ve acciones administrativas y nunca eso, que es la regla 2 aplicada al diario.

Una capa se puede mover a un modelo de incrustación diferente. Qdrant no añadirá un vector con nombre a una colección que ya existe, por lo que la colección se reemplaza en lugar de alterarse: cada punto se copia sin calcular incrustaciones, una declaración para cambiar el puntero, luego re-incrustar una capa a la vez. La búsqueda sigue disponible y sigue siendo una consulta durante todo el proceso. Antes de que una capa cambie, su conjunto de consultas de referencia se puntúa contra el nuevo modelo y una migración que perdiera recuperación se detiene en lugar de activarse — esa puerta está desactivada hasta que escribas un conjunto, porque necesita documentos que solo tú puedes elegir.

Un documento se puede subir como formulario además de enviarse como JSON, y un PDF se extrae mediante el sidecar del analizador. Ambas señales deben coincidir — la parte declara application/pdf y los bytes comienzan con %PDF- — porque un tipo declarado que los bytes contradicen es un desacuerdo, y solo olfatear haría que el tipo declarado fuera decoración. Cualquier otro formato binario se rechaza en el borde, y un PDF escaneado sin capa de texto se rechaza en lugar de indexarse como nada.

Los tokens se pueden firmar con una clave Ed25519 en lugar de un secreto compartido, en cuyo caso la mitad pública se publica en /.well-known/jwks.json y solo el proceso que emite tokens tiene la privada.

docker compose --profile minimal up se ha ejecutado desde un clon limpio, y todo el ciclo se ha manejado a través de él.

Lo que no está construido es lo que cubre una licencia comercial, y docs/licensing.md lo enumera: multiinquilino, SSO, permisos a nivel de documento y reglas de denegación, ID-JAG, exportación SIEM, un administrador global, cuotas y gráficos Helm de alta disponibilidad.

docs/ es la especificación, y todavía va por delante del código en algunos lugares — comienza con docs/authz.md, del que depende todo lo demás.

Invariantes

Seis reglas. Romper cualquiera de ellas es un incidente de seguridad, no un error. Detalles en docs/authz.md.

  1. La organización proviene del token y de ningún otro lugar.
  2. El filtrado de acceso es un pre-filtro, nunca un post-filtro.
  3. Un fallo al evaluar permisos deniega el acceso.
  4. "Sin permiso" y "objeto inexistente" devuelven respuestas idénticas.
  5. Un documento eliminado nunca se devuelve, incluso antes de la recolección de basura.
  6. write no implica read.

Licencia

Apache 2.0 — todo. Todo lo anterior está en este repositorio y permanece ahí.

El multiinquilino, SSO/SCIM, reglas de denegación a nivel de documento, EMA, exportación SIEM, administración global y copias de seguridad son módulos comerciales. Viven en un repositorio privado separado bajo una licencia separada y no se distribuyen con este — consulta docs/licensing.md para la línea entre ambos y la única pregunta que la decide.

Donde esta compilación se encuentra con uno de ellos, lo rechaza abiertamente: una regla deny o una concesión a nivel de documento se responde 400 con el motivo, en lugar de aceptarse y no aplicarse silenciosamente.

El nombre y la marca Nacre son marcas comerciales; consulta TRADEMARK.md.

Apoyo a este proyecto

No hay nivel alojado, ni recuento de asientos ni nada medido aquí, por lo que la mitad abierta no gana nada por ser usada — que es el punto, y también por qué vale la pena decir quién lo paga. Los módulos comerciales lo hacen, y son para las organizaciones que los necesitan; un desarrollador que ejecuta esto en un portátil nunca es la persona a la que se le pide.

Si te ahorró una semana, el botón Patrocinar en la parte superior de este repositorio es la otra forma de decirlo. Nada en este repositorio está detrás de él, y nada lo estará.