# Convenciones de archivos — vault osint Estándar para organizar la información de personas (y, a futuro, dominios y casos) en el vault `osint` (`/home/enmanuel/Obsidian/osint`). Toda extracción desde otros vaults o desde sesiones de navegación OSINT debe dejar los archivos siguiendo este estándar. ## 1. Estructura física (estándar: plano + subcarpeta de documentos) ``` osint/ README.md _self.md # ficha del titular (Enmanuel), referencia, NO es objetivo personas/ .md # ficha de la persona (su "index") / # carpeta con las notas-documento de esa persona .md dominios/ organizaciones/ # empresas/entidades (mismo patrón .md + /) lugares/ # direcciones/lugares de interés casos/ inbox/ attachments/ personas/ / -NN. # imágenes/PDFs de esa persona ``` Regla: la ficha vive como `.md` suelto en `personas/` (todas las fichas listables en un nivel); sus documentos en una subcarpeta homónima; los binarios en `attachments/personas//`. ## 2. Slug El `slug` es la clave estable de una persona. Se deriva del nombre completo: - minúsculas, sin acentos ni `ñ` (transliteración: `ñ`→`n`, `á`→`a`, …) - espacios y separadores → `-` - solo `[a-z0-9-]`, sin guiones dobles ni al inicio/fin Ejemplo: `Enmanuel Gutiérrez Pérez` → `enmanuel-gutierrez-perez`. ## 3. Ficha de persona — `personas/.md` Frontmatter: ```yaml tipo: persona nombre: "Enmanuel Gutierrez Perez" # nombre legible original aliases: ["Enmanuel Gutierrez Perez"] # nombres viejos para que wikilinks previos resuelvan slug: enmanuel-gutierrez-perez sexo: hombre # hombre|mujer|null fecha_nacimiento: 1997-03-05 # ISO o null dni: 54370345R # o null direccion: "Calle Eugenia Rios 14, 29718 Almachar, Malaga" # texto plano, no wikilink pais: españa tags: [persona, osint] fuente: "NotasDeObsidian/personas/Enmanuel Gutierrez Perez.md" # origen de la extracción ``` Body, secciones en este orden (omitir las vacías): ```markdown ## Documentos - [[enmanuel-gutierrez-perez/dni|DNI]] - [[enmanuel-gutierrez-perez/certificado-digital|Certificado digital]] ## Relaciones - [[manuel-gutierrez-gamez|Manuel Gutierrez Gamez]] — hermano ## Notas Texto libre de investigación. ``` ## 3b. Esquema canónico del frontmatter de persona Todas las fichas `personas/.md` comparten el mismo conjunto de campos, en este orden. Campos sin valor se dejan como `null` (o `[]` para listas) — nunca se omiten, para que el cálculo de datapoints y el score de completitud sean consistentes. ```yaml tipo: persona nombre: "Nombre Apellidos" slug: nombre-apellidos aliases: [] # otros nombres por los que aparece sexo: null # hombre | mujer | null fecha_nacimiento: null # ISO YYYY-MM-DD | null dni: null telefono: null email: null direccion: null # texto plano pais: null relaciones: [] # ["[[slug]] — parentesco/rol"] contexto: null # familia | aurgiobsidian | ... (origen/circulo) fuente: "" # nota/vault de procedencia tags: [persona, osint] ``` Campos extra heredados (p.ej. `horoscopo`) se conservan al final del frontmatter. **Datapoints y score de fiabilidad.** Los campos de identidad que cuentan para el score de completitud son: `sexo, fecha_nacimiento, dni, telefono, email, direccion, pais` (7). El score de una ficha es `campos_identidad_presentes / 7 * 100`. Una ficha por debajo del 100% tiene datapoints faltantes. El total de datapoints de una persona suma además sus documentos, attachments y relaciones. Lo calcula `projects/osint/tools/person_datapoints.py`. ## 4. Nota-documento — `personas//.md` Una nota-documento agrupa los attachments de un tipo de documento de la persona. `` canónico (deriva del título original quitando el nombre de la persona y normalizando): | Título original (ejemplos) | doc-slug | doc_tipo | |---|---|---| | `Dni X`, `DNI de X` | `dni` | dni | | `Certificado Digital X` | `certificado-digital` | certificado | | `Carnet de conducir de X`, `Documentos Carnet Conducir X` | `carnet-conducir` | carnet | | `Fotos X`, `Fotos de X` | `fotos` | fotos | | `Vida Laboral X` | `vida-laboral` | laboral | | `Nominas X` | `nominas-` | laboral | | `Documentos X` (Abanca, BBVA, Cajamar…) | `documentos-` | banco | | `Modelo 100 X`, `Alta autonomo X` | `modelo-100`, `alta-autonomo` | fiscal | | `Datos empadronamiento X` | `empadronamiento` | otro | | `Contrato X` | `contrato-` | contrato | | (sin patrón claro) | slug del título sin el nombre | otro | Frontmatter: ```yaml tipo: documento doc_tipo: dni # dni|certificado|carnet|fotos|banco|fiscal|laboral|contrato|otro persona: "[[enmanuel-gutierrez-perez]]" fuente: "NotasDeObsidian/Dni Enmanuel Gutierrez.md" ``` Body: los embeds reescritos a la ruta de attachments de la persona: ```markdown ![[attachments/personas/enmanuel-gutierrez-perez/dni-1.jpg]] ![[attachments/personas/enmanuel-gutierrez-perez/dni-2.jpeg]] ``` ## 5. Attachments — `attachments/personas//` - Cada binario referenciado por una nota-documento se mueve a `attachments/personas//`. - Se renombra a `-NN.` (1-indexed, en el orden en que aparece en la nota), preservando la extensión original en minúsculas. Ej: `dni-1.jpg`, `dni-2.jpeg`, `documentos-abanca-1.pdf`. - Si el nombre original es relevante, se anota en el body de la nota-documento como comentario. ## 6. Entidades que NO son personas Notas como `FenixFood SL`, `Documento Endesa`, `Documentos Aduanas …` van a `organizaciones/`; las direcciones/lugares (`Calle Eugenia Rios …`) van a `lugares/`. Ambas carpetas siguen el mismo patrón que `personas/`: `.md` como ficha + subcarpeta `/` para sus documentos + `attachments///` para sus binarios. El frontmatter usa `tipo: organizacion` / `tipo: lugar` en vez de `tipo: persona`. ## 7. Relaciones y direcciones - **Relaciones** entre personas (`Hermano de [[X]]`) se normalizan a la sección `## Relaciones` de la ficha, enlazando al `slug` de la otra persona con alias legible. - **Direcciones**: en el frontmatter `direccion` como texto plano (no wikilink). Si una dirección es entidad de investigación propia, tiene además su ficha en `lugares/.md`, y la persona la enlaza con `direccion: "[[lugares/|texto legible]]"` si se quiere navegable. ## 8. Idempotencia de la extracción El migrador debe ser re-ejecutable: si una persona ya existe en osint con su slug, se actualiza (no se duplica). Los attachments ya movidos no se vuelven a mover. ## 9. Scans de red (recon) Todo escaneo de red de una investigación —WHOIS, RDAP, DNS, nmap, traceroute, ping— se **archiva SIEMPRE en OSINT**. No existen scans sueltos: el resultado queda como nota navegable en el vault y como fila consultable en la base de datos. Lo gestionan las funciones del grupo de capacidad `recon` del registry (dominio `cybersecurity`); ver `docs/capabilities/recon.md`. ### 9.1 Nota del scan en el vault Cada scan produce una nota Markdown bajo la carpeta del dominio escaneado: ``` dominios//recon/-.md ``` donde `` es uno de `whois | rdap | dns | nmap | traceroute | ping` y el timestamp tiene granularidad de minuto. Frontmatter de la nota: ```yaml tipo: scan-red scan_tipo: whois # whois|rdap|dns|nmap|traceroute|ping target: "ejemplo.com" # objetivo original (dominio, host o IP) slug: ejemplo.com # slug del target (clave de la carpeta) fecha: 2026-06-14T13:18:00 # ISO, momento del scan herramienta: whois # CLI usada (whois, dig, nmap, ...) tags: [scan-red, whois, recon] ``` Body: cabecera con target/tipo/herramienta/fecha, un `## Resumen` opcional con los campos destacados del scan, y la salida cruda completa (`raw`) dentro de un bloque de código. La nota es la **capa crítica**: si no se puede escribir, el guardado falla. ### 9.2 Tabla `network_scans` (DuckDB, service osint_db) Además de la nota, cada scan se registra en la tabla `network_scans` (schema `main`) de la base DuckDB que posee el service `osint_db` (single-writer), vía `POST http://127.0.0.1:8771/api/scan`. Columnas: | Columna | Qué | |---|---| | `id` | Identificador del scan | | `target` | Objetivo original (dominio/host/IP) | | `target_slug` | Slug del target (clave de agrupación) | | `scan_type` | `whois \| rdap \| dns \| nmap \| traceroute \| ping` | | `tool` | CLI usada (whois, dig, nmap, ...) | | `scan_ts` | Timestamp ISO del scan | | `note_path` | Ruta relativa de la nota en el vault | | `summary` | JSON con los campos resumidos del scan | | `created_at` | Timestamp de inserción | Es la **capa best-effort**: si `osint_db` está caído o no expone el endpoint, el guardado degrada a solo-nota (`registered=False` + aviso) sin fallar. El re-ingest del vault NO borra `network_scans` —es una tabla de datos vivos, no derivada de las notas. ### 9.3 Cómo lanzar y guardar El camino canónico es el pipeline one-shot del registry, que escanea y archiva en una sola llamada: ```bash cd /home/enmanuel/fn_registry ./fn run recon_osint # p.ej. ./fn run recon_osint ejemplo.com whois ``` Para un nmap pesado (full-tcp, vuln, udp-top) lanzar en segundo plano por la duración: ```bash nohup ./fn run recon_osint scanme.nmap.org nmap --profile full-tcp --timeout-s 7200 \ > /tmp/recon-fulltcp.log 2>&1 & ``` Alternativa atómica (controlas el scan y lo guardas aparte) desde Python, importando las funciones del registry —no se reescriben: ```python import sys; sys.path.insert(0, "python/functions") from cybersecurity import dns_records from cybersecurity.save_scan_to_osint import save_scan_to_osint scan = dns_records("ejemplo.com") if scan["status"] == "ok": save_scan_to_osint("ejemplo.com", "dns", scan["raw"], summary={"A": scan["records"].get("A")}, tool="dig") ``` ### 9.4 Cómo consultar scans guardados Desde una nota del vault, con un bloque `osintdb` (plugin osint-db) que consulta la tabla: ````markdown ```osintdb SELECT scan_type, tool, scan_ts, note_path FROM network_scans WHERE target_slug = 'ejemplo.com' ORDER BY scan_ts DESC ``` ```` O contra el service directamente vía `/api/query` (mismo SQL). El slug del target se deriva igual que en todo el vault: ```python import re slug = re.sub(r"[^a-z0-9._-]+", "-", target.lower()) ``` > Nota: el `slug` de un dominio/host (p.ej. `ejemplo.com`, `192.168.1.10`) conserva puntos y > guiones porque el set permitido es `[a-z0-9._-]`; difiere del slug de persona de la sección 2, > que solo admite `[a-z0-9-]`.