Skip to content

deagentic/keystone

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

109 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Keystone — Unified Knowledge MCP for Grupo Deacero

Servidor MCP (Model Context Protocol) que expone una base de conocimiento corporativa unificada — ADRs, perfiles de proyecto, patrones de adopción, skills y un grafo de WikiLinks — para cualquier cliente LLM (Claude, Gemini, Cursor, etc.) operando dentro de Grupo Deacero, con thread-safety y autorización por scope.


Tabla de contenido


¿Qué es Keystone?

Grupo Deacero opera más de 200 empresas con documentación fragmentada entre wikis, repos, drives y conocimiento tácito. Keystone centraliza ese conocimiento en una Knowledge Database (KDB) indexada por búsqueda híbrida (BM25 + embeddings) y la expone como un servidor MCP estándar. Cualquier agente o IDE compatible con MCP puede consultarla, contribuir nuevas páginas y resolver decisiones de arquitectura sin recrawlear fuentes dispersas.

El proyecto fue inicializado con Cornerstone (template cookiecutter-mcp v0.13.0), comparte gobernanza con el ADR organizacional ORG-ADR-0001, y está optimizado para correr como contenedor Docker o lanzarse directo por stdio desde un cliente MCP.

Características

  • Búsqueda híbrida (RRF) — combina BM25 (rank_bm25) y similitud coseno sobre embeddings text-embedding-004 de Gemini con Reciprocal Rank Fusion (k=60).
  • Grafo de conocimiento in-memory — extracción de [[WikiLinks]] y BFS confidence-weighted (src/keystone/domain/graph.py, ADR-0004).
  • Thread-safeSearchEngine protegido por threading.RLock con patrón snapshot-then-release (ADR-0006). Las operaciones de scoring son lock-free.
  • Autorización por scopeteam, project y org validadas server-side via ctx.request_context.meta["user" / "project"] (ADR-0006). Identidad no forjable por el caller.
  • Almacenamiento Obsidian-compatible — páginas en Markdown con frontmatter YAML, validadas contra el modelo Pydantic WikiPage (extra='forbid').
  • Arquitectura hexagonal enforced con import-linter (capas domain → ports → adapters, independencia inbound/outbound).
  • 6 herramientas MCP: búsqueda híbrida, contexto de proyecto, ADRs organizacionales, patrones por fingerprint, navegación de grafo y ingesta.
  • Gobernanza multi-agente — hooks de sesión para Claude Code y Gemini CLI, swarm file-based vía tmux, y skills en .agents/ sincronizadas desde deagentic/cornerstone-agents.
  • Quality gates: cobertura 100 % (pytest-cov), ruff, mypy, import-linter, gates personalizados (ADR, GitOps, SemVer, red-team de MCP). En CI (GitHub Actions): gate red-team (tools/red_team_mcp.py). Los demás gates (pytest, ruff, mypy, import-linter) corren localmente / pre-commit — pendiente integrarlos a CI.

Inicio rápido

Requisitos

  • Python >= 3.11
  • Docker y Docker Compose (opcional, pero recomendado)
  • Una GEMINI_API_KEY válida para embeddings (sin ella, la búsqueda semántica devuelve un vector constante y solo BM25 aporta señal).

Instalación local (desarrollo)

git clone https://github.com/deagentic/keystone.git
cd keystone

# Entorno virtual
python -m venv .venv
source .venv/bin/activate

# Instalación editable
pip install -e ".[dev]"

# Hooks
pre-commit install

Configura tu .env en la raíz del repo:

GEMINI_API_KEY=tu_clave_aqui
KDB_DATA_DIR=./wiki
AGENTIC_TELEMETRY_URL=

Nota de seguridad: nunca commitees .env ni claves. .gitignore ya cubre .env, pero confírmalo antes del primer push.

Levantar con Docker

docker compose up --build

El servicio expone la imagen en python:3.11-slim, monta un volumen persistente store_data en /data/store, y arranca python -m keystone.server. Nota: el servidor actualmente corre por stdio; el puerto 8000 declarado en Dockerfile/compose.yml está reservado para un transporte HTTP futuro (ver Known issues).

Conectar un cliente MCP

Para Claude Desktop, agrega a claude_desktop_config.json:

{
  "mcpServers": {
    "keystone": {
      "command": "python",
      "args": ["-m", "keystone.server"],
      "cwd": "/ruta/absoluta/al/repo",
      "env": {
        "KDB_DATA_DIR": "/ruta/absoluta/al/repo/wiki",
        "GEMINI_API_KEY": "..."
      }
    }
  }
}

Configuración

Variables de entorno reconocidas:

Variable Default Propósito
KDB_DATA_DIR ./wiki Directorio raíz donde Keystone carga y escribe páginas *.md.
GEMINI_API_KEY Habilita embeddings reales con text-embedding-004.
AGENTIC_TELEMETRY_URL vacío Endpoint opcional para telemetría del cliente Cornerstone. Vacío = no-op.
AGENTIC_TELEMETRY_DEBUG 0 Logs de debug del cliente de telemetría.
CORNERSTONE_ADR_PATH docs/adr Path que el gate adr_gate.py valida en cada Edit/Write.

Herramientas MCP expuestas

Las seis tools viven en src/keystone/adapters/inbound/mcp.py y delegan a _*_logic puras (testables sin FastMCP). El helper _is_authorized(page, user, user_project) centraliza la autorización por scope (ADR-0006).

Tool Firma Descripción
kdb_search query: str, domain: Optional[str] = None, ctx: Optional[Context] = None Búsqueda híbrida BM25 + semántica con RRF. Devuelve top 5 con id, title, confidence, repo, excerpt. Filtra por scope.
kdb_get_project_context project: str, ctx: Optional[Context] = None Agrega páginas por source_project y retorna stack, dominios y lista de id/title. Filtra por scope.
kdb_get_org_adr adr_id: str Recupera un ADR organizacional (página con scope=="org" y "architecture" in domain). No recibe ctx — cualquier caller puede leerlo, pero el resultado ya está acotado a páginas org/architecture.
kdb_list_patterns fingerprint: Dict, ctx: Optional[Context] = None Devuelve AdoptionPatterns cuya etiqueta tags=["pattern"] coincide con el stack del fingerprint. Filtra por scope.
kdb_get_related page_id: str, depth: int = 1, tags: Optional[List[str]] = None, ctx: Optional[Context] = None BFS confidence-weighted sobre el grafo de WikiLinks. depth ∈ [1,3], cap de 10 resultados. Excluye deprecated, prioriza verified. Poda nodos no autorizados antes del traversal.
kdb_ingest metadata: Dict, content: str Valida contra WikiPage (estricto), rechaza identificadores prohibidos, auto-genera id (kb-<uuid8>) y last_updated, escribe atómicamente y refresca el índice BM25 en memoria.

ctx es inyectado por el transport MCP (no lo suministra el caller). Transporta user y project para autorización scope-based — ver ADR-0006.

Reglas de autorización (ADR-0006): páginas scope="team" solo se devuelven cuando user == page.contributed_by; páginas scope="project" solo cuando user_project == page.project; scope="org" siempre visible. (WikiPage.scope acepta org | project | team.)

Los modelos Pydantic (WikiPage, ADR, AdoptionPattern, ProjectProfile) están en src/keystone/domain/wiki.py y rechazan campos no declarados.

Estructura del repositorio

keystone/
├── src/keystone/              # Paquete runtime (hexagonal)
│   ├── server.py              # Composition root (stdio)
│   ├── adapters/
│   │   ├── inbound/mcp.py     # FastMCP tools (@mcp.tool) + _is_authorized
│   │   ├── fs_adapter.py      # I/O atómico + path-traversal guard
│   │   └── gemini_embed_adapter.py
│   ├── domain/
│   │   ├── search.py          # SearchEngine (BM25 + RRF, RLock)
│   │   ├── graph.py           # KnowledgeGraph + BFS confidence-weighted
│   │   └── wiki.py            # Modelos Pydantic
│   └── ports/                 # (placeholder, ver Known issues)
├── tests/
│   ├── features/*.feature     # Escenarios BDD (Gherkin)
│   ├── step_defs/*.py         # Glue pytest-bdd
│   ├── integration/, unit/
│   └── test_telemetry.py
├── docs/adr/                  # ADRs locales + org/
├── wiki/                      # Seed KDB + taxonomy.md
├── tools/                     # Gates y discovery toolbox
├── .agents/                   # Skills sincronizadas
├── .claude/, .gemini/         # Hooks por IDE
├── .swarm/                    # Coordinación multi-agente (tmux)
├── .telemetry/                # Cliente OTel + envelope
├── .mcp.json                  # Configuración de MCP externo
├── pyproject.toml             # Deps + tooling
├── Dockerfile, docker-compose.yml
└── README.md, AGENTS.md, CLAUDE.md, GEMINI.md

Desarrollo

Convenciones

  • Branching: feat/<feature>, fix/<bug> (ver CONTRIBUTING.md).
  • Commits: Conventional Commits (feat:, fix:, docs:, test:).
  • Linting: ruff check . && ruff format . (line length 100, target py311).
  • Tipos: mypy src/ (vía pre-commit).
  • Arquitectura: lint-imports antes de PR (3 contratos: layers, independence, forbidden).

Test

pytest                            # Unit + BDD vía pytest-bdd
pytest --cov-fail-under=100       # Gate de cobertura
behave                            # Si tienes step-defs en formato behave puro

Workflow ADR

  1. Crea el ADR en docs/adr/ADR-XXXX-titulo.md siguiendo MADR.
  2. El gate tools/adr_gate.py lo valida en cada Edit/Write (hook PreToolUse, 60 s timeout).
  3. Los ADRs organizacionales (docs/adr/org/) son read-only — sincronizados desde deagentic/cornerstone-kdb (ORG-ADR-0001).

Calidad y gates

Gate Herramienta Cuándo corre
Lint ruff check, ruff format pre-commit + CI
Tipos mypy src/ pre-commit
Arquitectura hexagonal import-linter pre-commit + manual
Cobertura ≥ 100 % (branch) pytest-cov pytest
BDD pytest-bdd pytest
ADR Gate tools/adr_gate.py Hook PreToolUse de Claude Code
GitOps Gate tools/gitops_gate.py Hook PreToolUse (Bash)
Red-team MCP tools/red_team_mcp.py Manual / CI (obligatorio per AGENTS.md)
SemVer tools/enforce_semver.py Pre-tag

Known issues

  • Transporte: Dockerfile expone 8000 pero server.py corre por stdio. Decidir si se agrega un transporte HTTP/SSE o se quita la exposición de puerto.
  • ports/ vacío: el contrato domain → ports → adapters está declarado en import-linter pero ports/__init__.py no define Protocols todavía.
  • outbound/ vacío: FSAdapter y GeminiEmbedAdapter viven en adapters/ (un nivel arriba) en vez de adapters/outbound/.
  • Embeddings en ingest: SearchEngine.add_or_update_page reconstruye BM25 pero no recomputa el embedding de la página recién ingerida. Los resultados semánticos quedan rezagados hasta el próximo cold-start.
  • Grafo reconstruido por request: _get_related_logic reconstruye el KnowledgeGraph en cada llamada — src/keystone/adapters/inbound/mcp.py tiene un TODO(perf) para cachear.
  • Transport auth no integration-tested: _get_user_from_context / _get_project_from_context tienen cobertura unitaria completa, pero falta un test end-to-end que levante un FastMCP real con ctx.request_context.meta controlado (ADR-0006).
  • sonar-project.properties todavía contiene placeholders sin renderizar ({cookiecutter.project_slug}, __PYTHON_VERSION__).
  • docs/adr/index.md lista ADR-0004 como proposed aunque el ADR ya está accepted — desincronización a corregir.
  • Artefactos commiteados: .coverage 2, stdout.log, stderr.log, logs/ — candidatos a limpiar.

Documentación adicional

  • docs/architecture.md — vista de arquitectura nivel arquitecto con diagramas Mermaid (C4, dominio, concurrencia, flujos MCP).
  • docs/Keystone-Arquitectura-Ejecutiva.docx — resumen ejecutivo para stakeholders de Grupo Deacero.
  • AGENTS.md — el "Supreme Mandate" del proyecto: capacidades del agente, gates obligatorios, taxonomía de skills.
  • CLAUDE.md / GEMINI.md — instrucciones específicas por IDE-agent.
  • docs/adr/ — ADRs locales y organizacionales.
  • wiki/taxonomy.md — dominios del KDB (ot-ics, infra, security, backend, finance, hr, architecture; frameworks IEC 62443 / ISO 27001 / políticas internas).

Licencia y propiedad: Grupo Deacero. Repo público para fomentar colaboración con socios y proveedores. No publicar credenciales, secretos ni datos operativos sensibles.

About

Keystone: Unified Knowledge MCP for DeAcero

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors