Documentación · Fuentes de datos
Cada sistema, un conector cada vez.
Un cerebro está tan al día como lo que lo alimenta. Esto es cómo apuntar brainiphy a una carpeta, un preset, una API REST o una URL pública — y cómo escribir tú el conector cuando tu CRM no es ninguno de esos.
El contrato es más pequeño de lo que parece: una función que devuelve una lista de registros. Una vez la fuente está dentro, sincronizar y programar es lo que la mantiene honesta.
Añadir fuentes de datos
Cinco tipos de fuente, y cada uno te dice de entrada si te deja deberes — antes de que elijas. Añade tantas como quieras, cada una con su propio intervalo de consulta.
| Fuente | Cuando tus datos son | Lo que te queda a ti | Flag |
|---|---|---|---|
| carpeta local | Una carpeta en este Mac, incluida una carpeta sincronizada de Drive o Dropbox. | listo para usar | --mirror <carpeta> |
| preset | Un sistema para el que brainiphy ya trae un conector terminado. | listo para usar | --preset <nombre> |
| api http | Cualquier API REST que no tenga preset. | requiere código | --api <url-base> |
| url | Una página web pública. graphify la descarga una vez; no es una fuente viva. | una vez | graphify add <url> |
| a medida | Una base de datos, una exportación local, cualquier otra cosa. | requiere código | (sin flag) |
Una carpeta local
Se genera completa con rsync -a --delete, así que un fichero borrado en el origen desaparece del cerebro en vez de quedarse como un nodo obsoleto.
$ brain new-connector ~/clients/acme docs --mirror ~/Dropbox/acmeCopia en vez de enlazar, porque graphify no sigue enlaces simbólicos y una carpeta enlazada sencillamente no se indexaría nunca. Además convierte los tipos de fichero que graphify no sabe leer — CSV, JSON — en un registro Markdown por fila, y nombra en su resumen todo lo que siga siendo ilegible, en vez de dejarlo fuera del grafo en silencio.
Un preset
El preset que viene hoy es GoHighLevel / LeadConnector — contactos, oportunidades, pipelines, conversaciones, calendarios, usuarios y formularios de una subcuenta. Añadir otro preset es dejar un fichero en el paquete y darlo de alta, que es justo la idea: los presets son el camino rápido, no el límite.
$ brain presets
$ brain new-connector ~/clients/acme crm --preset gohighlevel --var LOCATION_ID=abc123Una API REST
Tira de --api antes que de la plantilla básica para cualquier cosa REST. Un conector que se escribe urllib a mano vuelve a introducir los cuatro fallos que el cliente HTTP incluido existe para evitar: un user-agent por defecto que está vetado, una segunda petición sin proteger para la página siguiente, ningún reintento ante fallos transitorios, y un permiso que falta informado como si fuera un fallo de autenticación.
$ brain new-connector ~/clients/acme billing --api https://api.example.comLo que queda es una función collect_* por cada tipo de objeto. Antes de escribir ninguna, prueba el conector generado contra la API real: informa de qué objetos puede leer de verdad tu credencial y no escribe nada. Es la forma más rápida de descubrir si un token tiene los permisos que dabas por supuestos.
Una URL pública
Algo puntual, no una fuente viva — graphify la descarga una vez. No hay conector de por medio.
$ graphify add https://example.com/handbook
$ brain sync ~/clients/acme --fullEscribir un conector
brain new-connector genera un script que ya cumple el contrato. En la mayoría de casos solo rellenas fetch_records().
SOURCE_SYSTEM = "hubspot"
def fetch_records() -> list[dict]:
token = get_secret("graphify-acme-hubspot")
req = urllib.request.Request(
"https://api.example.com/v3/records",
headers={"Authorization": f"Bearer {token}"},
)
with urllib.request.urlopen(req, timeout=30) as resp:
data = json.load(resp)
return [
{"id": r["id"], "title": r["name"], "body": r["notes"]}
for r in data["results"]
]Cada registro necesita id, title y body; cualquier otra clave se escribe en el frontmatter del Markdown. El main() de la plantilla se encarga de --out, de la normalización y de nombrar los ficheros de forma estable.
El contrato
Si alguna vez escribes uno desde cero, esto es todo lo que tiene que hacer:
- Aceptar
--out <dir>y escribir allí Markdown normalizado mediantefrontmatter.write_record(). - Nombrar los ficheros con un slug estable del ID remoto del registro, para que repetir la ejecución sobrescriba en el sitio en vez de acumular una segunda copia de todo como nodos nuevos del grafo.
- Salir con
0si va bien y distinto de cero si falla, con un resumen legible por humanos en la salida estándar. - Leer las credenciales solo a través de
keychain.get_secret()— nunca como argumento de línea de comandos y nunca escritas en el código, ya que el historial de la shell, el listado de procesos y los logs de launchd las filtrarían todos.
Nada en el orquestador se bifurca según el tipo de conector que sea un script. En tiempo de ejecución todo conector es simplemente un ejecutable que cumple el contrato de arriba, y por eso soportar un tipo de fuente nuevo significa escribir un script y nunca ampliar brainiphy.
Elegir enfoque, del más barato al más caro
| Si la fuente es | Haz esto | Código que escribes |
|---|---|---|
| Una carpeta local que ya está en disco | --mirror <carpeta> | ninguno |
| Contenido alcanzable por una URL pública | graphify add <url> | ninguno |
| Un sistema para el que Claude ya tiene un conector MCP | Llámalo desde el sync.py generado en vez de montar la autenticación de cero. | un poco |
| Una API REST | --api <url-base> | un collect_* por objeto |
| Cualquier otra cosa — una base de datos, una exportación local | La plantilla básica. | un fetch_records() |