Nomos — Un asistente de IA personal que lee tus notas
Nomos
La mayoría de asistentes de IA empiezan cada conversación de cero. Nomos no. Toma tu vault de Obsidian — tus notas sobre proyectos, gente, objetivos, ideas a medio terminar — como memoria a largo plazo, lo embebe en un índice vectorial, y trae contexto relevante a cada conversación.
Pregunta "¿en qué debería centrarme esta semana?" y la respuesta sale de tus notas reales, tu calendario y artículos recientes de feeds que te importan. Pregunta "¿qué era eso que leí el mes pasado sobre IA en el edge?" y lo encuentra. El asistente se acuerda de cosas que le dices (memoria persistente entre sesiones), puede escribir notas de vuelta al vault, y corre completamente en infraestructura que tú controlas — solo la inferencia LLM y los embeddings pasan por un tercero.
Por qué existe
Yo mantengo casi todo lo que me importa en markdown plano en un vault de Obsidian. La parte frustrante de usar asistentes de IA mainstream es tener que ponerles al día cada vez. Nomos es la versión de “un asistente que me conoce” donde yo se define por mis notas, no por un perfil que mantiene una empresa.
El bonus: construirlo me obligó a explorar de verdad los loops agénticos, MCP, los pipelines de voz de baja latencia, y qué significa la privacidad por defecto en la práctica.
Cómo funciona
El vault como memoria. Nomos vigila el vault, divide cada nota en trozos, los embebe con BAAI/bge-large-en-v1.5, y los guarda en PostgreSQL con pgvector + un índice HNSW. La reindexación es incremental — los trozos sin cambios se saltan, así que un vault de 5000 notas no se vuelve a embebir entero con cada cambio.
Chat agéntico. Un loop en el backend ejecuta el LLM con seis herramientas disponibles:
search_notes— búsqueda semántica sobre el vaultread_note— trae el texto completo de una notawrite_note— crea o añade a una notaget_news— trae artículos RSS, puntuados contra tu vector de interesessuggest_calendar_event— sugiere un bloque de calendario según contextoupdate_memory— añade hechos duraderos a_nomos/memory.md, persistidos entre sesiones
El modelo decide cuándo llamar a qué. El frontend recibe la traza completa como Server-Sent Events: tokens de pensamiento, llamadas a herramientas, resultados, la respuesta final. Nada oculto.
Modo voz. Pulsar para hablar en la app Android. El pipeline es Groq Whisper-large-v3-turbo para STT, Groq GPT-OSS 20B para el LLM (inferencia rápida, barata), DeepInfra Kokoro-82M para TTS. El coste sale alrededor de 0,0024 $/minuto y la latencia percibida es sub-1-segundo — en parte por las decisiones de routing y en parte por reproducir audio de relleno mientras se resuelven las llamadas a herramientas.
App Android. Kotlin nativo + Jetpack Compose. Hilt para DI, Ktor para streaming SSE, SpeechRecognizer y CalendarContract nativos. La app gestiona sus modos de input (texto + voz) y renderiza los eventos de streaming según llegan.
Stack
Backend — FastAPI + uvicorn + gunicorn sobre Python 3.12. SQLAlchemy 2.0 (async) + asyncpg. PostgreSQL con pgvector. APScheduler para la reindexación periódica. sse-starlette para el protocolo de streaming.
Modelos (vía DeepInfra y Groq)
- LLM: Nemotron-3-Super-120B-A12B (chat), Groq GPT-OSS 20B (modo voz)
- Embeddings: BAAI/bge-large-en-v1.5
- STT: Groq Whisper-large-v3-turbo
- TTS: DeepInfra Kokoro-82M
Integración MCP — el trabajo reciente adopta Model Context Protocol para extraer un grafo de conocimiento sobre el vault.
Android — Kotlin, Jetpack Compose, Material 3, Hilt, Ktor, WorkManager.
Sync — Syncthing mantiene el vault de Obsidian sincronizado entre dispositivos y el VPS.
Deploy — Docker en un VPS de Hetzner, detrás de Coolify + Traefik, con Let’s Encrypt.
Cosas que me gustan
Modo voz por debajo del segundo. Orquestación multi-proveedor afinada por coste y latencia percibida, no solo por una. El audio de relleno tapa el silencio incómodo de las llamadas a herramientas para que la experiencia siga siendo conversacional y no mecánica.
SSE primero, con eventos estructurados. Cada paso que da el agente es un evento tipado que el cliente puede renderizar — thinking, tool_call, tool_result, token, error. Sin spinners “cargando…” tipo caja negra.
Privacidad por diseño. El vault se queda en tus dispositivos y tu VPS. Lo único que sale son prompts individuales y embeddings, enviados a un proveedor de inferencia, sin cuenta que ate las llamadas entre sí más allá de la API key.
Memoria persistente que es solo un fichero markdown. _nomos/memory.md se edita en Obsidian. El asistente lo actualiza con una tool call. Puedes leer lo que recuerda de ti. Puedes borrar entradas. Puedes hacer grep.
Reindexación incremental. Cuando cambia el vault, solo se vuelven a embebir los trozos modificados. Ahorra tiempo y coste de inferencia en un vault que crece a diario.
Estado
v1 está corriendo. Indexado, chat agéntico con seis herramientas, streaming SSE, app Android con voz + texto, sugerencias de calendario, memoria persistente — todo funcionando.
Roadmap v2: creación real de eventos de calendario (no solo sugerencia), historial de sesiones, notificaciones push, web clipper para capturar artículos al vault, y enriquecimiento de contactos.
La interfaz principal es la app Android. Un cliente web de chat está en la lista.
GitHub: github.com/IgnacioLD/nomos.