PersonalKnowHow
Convierte tu historial de LinkedIn/GitHub/cursos en un grafo de conocimiento consultable a través de MCP, utilizando búsqueda semántica real en lugar de coincidencia de palabras clave.
Documentación
Únete a la lista de espera · Demo en vivo · Problemas
Convierte un historial disperso de aprendizaje/trabajo personal — LinkedIn, GitHub, plataformas de cursos, correos de finalización de Gmail, repositorios de proyectos hermanos — en un grafo de conocimiento unificado, consultable con búsqueda semántica en lugar de coincidencia de palabras clave. Ejecútalo localmente con tus propios datos en dos comandos, sin necesidad de cuenta — o consulta los servidores MCP reales y desplegados descritos más abajo.

Pidiendo a Claude (a través del servidor MCP desplegado) que evalúe una oferta de trabajo contra el grafo — evidencia real extraída del historial de LinkedIn/GitHub, no una suposición. (video en resolución completa)
Pruébalo localmente en 60 segundos
Sin cuenta de Cloudflare, sin registro, nada desplegado — solo tu propia máquina.
git clone https://github.com/Georgi-Petkov/personalknowhow.git
cd personalknowhow
python quickstart.py
python ingest/query_local.py "what do I know about X"
quickstart.py detecta automáticamente las fuentes que ya están disponibles en tu máquina y omite el resto con una razón clara — como mínimo, una CLI de GitHub ya autenticada (gh auth login) o tus repositorios de proyectos hermanos son suficientes para obtener resultados reales. query_local.py incrusta tu grafo con un modelo local pequeño (BAAI/bge-small-en-v1.5 mediante sentence-transformers, descargado una vez desde Hugging Face en la primera ejecución — la única dependencia de red real del modo local, distinta de necesitar una cuenta en la nube) y clasifica los resultados por similitud de coseno, el mismo enfoque que usan los servidores MCP desplegados.
¿Quieres tu propio historial de LinkedIn en el grafo, no solo evidencia de GitHub/proyectos locales? Solicita tu exportación en linkedin.com → Configuración y privacidad → Privacidad de datos → Obtén una copia de tus datos, luego:
python quickstart.py --linkedin ~/Downloads/LinkedInDataExport.zip
python ingest/query_local.py "what do I know about X"
quickstart.py se encarga de descomprimir y enrutarlo al script de ingesta correcto por sí mismo — sin colocación manual de archivos, sin banderas que averiguar. (Solicitar la exportación ocurre completamente en el sitio de LinkedIn y puede tomar unos minutos para que la preparen — todo lo posterior son los dos comandos anteriores).
Cada otra fuente (edX, DataCamp, Gmail) necesita su propia configuración única (un archivo JSON completado manualmente o credenciales OAuth) — quickstart.py detecta y omite cada una de forma elegante con una razón de una línea si no está configurada; consulta ingest/CLAUDE.md para detalles por fuente si quieres agregar una.
Prueba la demo en vivo
https://personalknowhow-demo.kxtwrdzt6g.workers.dev/mcp es un servidor MCP real y desplegado — pero no es una página web. Abrir esa URL en un navegador envía un GET simple, y los servidores MCP solo hablan POST con formato JSON-RPC, así que verás un {"error":{"message":"Method not allowed."}} desnudo. Eso es esperado, no está roto — significa que lo estás viendo de la manera incorrecta.
La forma real de usarlo es como conector MCP. En Claude Desktop, edita claude_desktop_config.json (ubicación del archivo de configuración):
{
"mcpServers": {
"personalknowhow-demo": {
"command": "npx",
"args": ["mcp-remote", "https://personalknowhow-demo.kxtwrdzt6g.workers.dev/mcp"]
}
}
}
Reinicia Claude Desktop, luego pregunta algo como "usa personalknowhow-demo para verificar si tengo experiencia con Django" — Claude llama a la herramienta query_knowhow a través de MCP y recibe evidencia con coincidencia semántica (cursos, proyectos, certificaciones) con puntuaciones de similitud, sin necesidad de autenticación.
Si solo quieres confirmar que el servidor está vivo sin configurar un cliente:
curl -s https://personalknowhow-demo.kxtwrdzt6g.workers.dev/mcp \
-X POST -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
Un 200 con una respuesta JSON-RPC confirma que está vivo — el encabezado Accept anterior es obligatorio; sin él, el servidor devuelve correctamente 406 Not Acceptable, que es un error diferente, también esperado, del GET del navegador anterior.
Por qué existe esto
Las listas de finalización de cursos y los currículums con coincidencia de palabras clave son una señal débil de lo que alguien realmente sabe. Este proyecto construye un grafo de conocimiento real a partir de fuentes primarias (no resúmenes autoinformados), incrusta cada entrada con un modelo de incrustación real y lo expone como una herramienta MCP consultable — para que "¿tengo experiencia con Django?" se responda recorriendo evidencia real (el README de un proyecto, una finalización de curso, un respaldo) con una puntuación de similitud adjunta, no una suposición.
Arquitectura
ingest/ Source-specific scripts → common schema
{title, type, provider, date, description, domain_tags}
corpus/ Generated markdown, one subfolder per source (not tracked — see Privacy below)
graph.json Extracted nodes/edges from corpus/ (not tracked)
mcp/ Public MCP server (Cloudflare Worker) — semantic search, no auth
mcp-private/ Private MCP server — same search, bearer-token gated, adds
signal-only evidence (job applications, career interests)
Fuentes de ingesta: LinkedIn (a través de la https://learn.microsoft.com/en-us/linkedin/dma/member-data-portability/overview, solo UE — consulta docs/linkedin-connector-notes.md para notas sobre la alternativa de exportación manual para otras regiones), GitHub (a través de la CLI gh, excluyendo forks — un fork es evidencia de navegación, no de construcción), finalizaciones de cursos de DataCamp/edX/Skilljar, Gmail (correos de finalización de otras plataformas) y repositorios de proyectos hermanos (auto-descubiertos, evidenciados mediante README + nombres de archivos rastreados + un pase de palabras clave, no autoinformados).
ingest/merge.py deduplica entre fuentes (idempotente — seguro de re-ejecutar). ingest/build_graph.py extrae nodos/aristas del frontmatter corpus/ hacia graph.json.
La capa RAG
Tanto mcp/ como mcp-private/ son Cloudflare Workers sin estado (createMcpHandler, sin Durable Object) que incrustan cada entrada del corpus con Workers AI (@cf/baai/bge-base-en-v1.5, 768-dim) en el momento de la exportación, e incrustan la cadena de consulta en el momento de la solicitud, luego clasifican por similitud de coseno. Se exponen dos herramientas MCP: query_knowhow(topic) para búsqueda semántica y list_by_type(type) para un listado simple. El servidor privado además etiqueta cada resultado con un evidence_tier (demonstrated vs. signal_only), para que una solicitud de empleo o una entrada de interés profesional nunca pueda confundirse con prueba de una habilidad.
Diseño de privacidad
corpus/ y graph.json nunca son públicos — ningún código orientado al público los lee directamente. La única fuente de datos pública sancionada es mcp/public_entries.json, construida por ingest/build_public_export.py mediante una lista de permitidos de cierre ante fallo: solo las categorías de corpus explícitamente listadas (cursos, proyectos, certificaciones, educación, respaldos, puestos, perfil, recomendaciones, artículos) se exportan. Una nueva categoría de corpus se excluye por defecto hasta que alguien la agregue deliberadamente a la lista de permitidos — la misma disciplina que mantiene las solicitudes de empleo y los datos de interés profesional fuera del servidor público por completo; esos datos solo existen en mcp-private/, protegidos detrás de un token de portador, y nunca se confirman en este repositorio tampoco (consulta .gitignore).
Herramientas de agente profesional
Una segunda capa construida sobre el mismo corpus: ingest/analyze_job_postings.py puntúa ofertas de trabajo extraídas contra la cobertura de habilidades conocida usando las mismas incrustaciones (similitud de coseno calificada known/peripheral, no coincidencia binaria de palabras clave), ingest/cv_tailor.py compara los requisitos de una oferta contra viñetas de CV con un sistema explícito de dos niveles (coincidencias de términos exactos vs. coincidencias semánticamente relacionadas, estas últimas siempre etiquetadas como "verificar antes de afirmar" en lugar de afirmadas), y ingest/recommend_courses.py cruza catálogos de cursos contra brechas de cobertura.
Ejecutar fuentes de ingesta individuales manualmente
python quickstart.py (consulta la parte superior de este README) ejecuta automáticamente todo lo siguiente para las fuentes que detecte. Para un control más fino — una sola fuente, banderas no predeterminadas o re-ejecutar solo un paso después de un cambio en el corpus — ejecuta cualquiera de estos directamente:
pip install -r requirements.txt
# Run a specific ingest source, e.g.:
python ingest/github_ingest.py
python ingest/linkedin_api_ingest.py --domains PROFILE,POSITIONS,SKILLS
# Deduplicate corpus after any ingest run
python ingest/merge.py
# Build graph.json from corpus/
python ingest/build_graph.py
Cada script ingest/*_ingest.py es independiente — ejecuta las fuentes que te correspondan. Todos escriben markdown en corpus/<source>/ usando el esquema compartido a continuación.
Esquema del corpus
Cada archivo markdown en corpus/ usa este frontmatter YAML:
---
title: "Advanced Python Programming"
type: "course" # course | certification | position | project | education | ...
provider: "LinkedIn Learning"
date: "2024-01-15"
description: "Free-text summary."
domain_tags:
- python
- programming
---
Despliega tu propio servidor MCP alojado (opcional, necesita una cuenta de Cloudflare)
El modo local (arriba) es suficiente para consultar tu propio grafo — esta sección es solo para alojarlo como un servidor MCP real al que otros clientes/personas puedan conectarse, de la misma manera que funciona la demo en vivo.
cd mcp && npm install && npm run deploy # public server
cd mcp-private && npm install && npm run deploy # private server
cd mcp-private && npm run secret # set PRIVATE_MCP_TOKEN
Ambos necesitan una cuenta de Cloudflare con acceso a Workers AI (enlace [ai], remote = true en wrangler.toml). Reconstruir las incrustaciones después de un cambio en el corpus:
CLOUDFLARE_ACCOUNT_ID=... CLOUDFLARE_AI_TOKEN=... python ingest/build_public_export.py
CLOUDFLARE_ACCOUNT_ID=... CLOUDFLARE_AI_TOKEN=... python ingest/build_private_export.py
Agregar una nueva fuente de ingesta
- Crea
ingest/<source>_ingest.pyque lea la exportación cruda y escriba archivos markdown encorpus/<source>/usando el esquema anterior. merge.pyybuild_graph.pyno requieren cambios — escaneancorpus/de forma genérica.- Si la nueva categoría debe ser pública alguna vez, agrégala deliberadamente a
ALLOWLISTeningest/build_public_export.py— se excluye por defecto de lo contrario.
