Files
fn_registry/docs/capabilities/duckdb.md
T
egutierrez 927437a8d8 feat(infra): grupo claude-fleet — FleetView TUI + orquestacion de Claudes
Sistema FleetView para centralizar la flota de procesos Claude Code vivos en una
sola ventana kitty + tmux (socket aislado -L fleet) con un panel TUI:

- list_claude_fleet (+ tipo claude_fleet): escanea ~/.claude/sessions + goals +
  runtime, valida procesos vivos (anti-PID-reciclado), join por sessionId.
- list_resumable_claudes (+ tipo resumable_claude): sesiones cerradas reanudables.
- wrappers tmux: tmux_new_claude_window (con --resume), tmux_swap_window_into_console
  (preserva ancho del sidebar), tmux_map_claude_panes.
- launch_kittyclaude: comando entrypoint; instala atajos alt+flechas/enter/n/0/k/r,
  mouse on, remain-on-exit off; fija el ancho del sidebar con hooks.
- docs/capabilities/claude-fleet.md + entrada en el INDEX.

Incluye ademas funciones datascience en progreso (excel/duckdb/postgres) y ajustes
varios de docs e infra de otra sesion, agrupados aqui para no perderlos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 00:04:41 +02:00

6.5 KiB

Capability: duckdb

Operar bases de datos DuckDB desde el registry: abrir/crear bases, consultas read-only seguras, conversion CSV -> Parquet, deduplicacion por hash y carga de series temporales. DuckDB es el motor analitico embebido del ecosistema (OLAP local, archivos .duckdb, lectura directa de CSV/Parquet/JSON).

Pieza central del patron BD como fuente de verdad + Obsidian como vista (project osint): la app osint_db posee la DuckDB maestra y este grupo aporta las primitivas de acceso.

Funciones

ID Firma Que hace
duckdb_open_go_infra DuckDBOpen(path string) (*sql.DB, error) Abre (o crea) una base DuckDB desde Go. Path vacio o :memory: abre en memoria.
duckdb_query_readonly_py_infra duckdb_query_readonly(db_path, sql, params=None, max_rows=10000) -> dict Consulta read-only segura: conexion read_only=True, params posicionales ?, filas como list[dict] con tipos normalizados a JSON (date/datetime -> isoformat, Decimal -> float, bytes -> base64). Devuelve {status, columns, rows, row_count, truncated} sin lanzar.
duckdb_execute_py_infra duckdb_execute(db_path, sql, params=None) -> dict Ejecuta UNA sentencia de escritura (INSERT/UPDATE/DELETE/DDL) en conexion read-write, commit, devuelve {status, rowcount} sin lanzar. Primitivo de escritura del grupo (complementa a duckdb_query_readonly).
duckdb_upsert_py_infra duckdb_upsert(db_path, table, rows, key_cols, update_cols=None) -> dict UPSERT idempotente INSERT ... ON CONFLICT (key_cols) DO UPDATE SET ... actualizando SOLO update_cols. Excluir columnas de update_cols permite que un re-upsert NO las pise (ownership selectivo: la DB es la verdad). Devuelve {status, inserted, updated}.
csv_to_parquet_duckdb_py_core csv_to_parquet_duckdb(csv_path, parquet_path, column_casts=None, overwrite=False) -> bool Convierte CSV -> Parquet con read_csv_auto. column_casts fuerza tipos por columna. No reescribe si el parquet existe y overwrite=False.
dedup_duckdb_table_by_hash_py_pipelines dedup_duckdb_table_by_hash(duckdb_path, table, exclude_cols=None) -> dict Pipeline: anade columna row_hash (md5 de columnas de datos) idempotentemente y borra filas duplicadas conservando la primera insercion.
load_ohlcv_from_duckdb_go_finance LoadOHLCVFromDuckDB(dbPath, query string) ([][]float64, error) Carga datos OHLCV ejecutando una query SQL sobre una base DuckDB (consumo desde apps Go de finanzas).
duckdb_list_tables_py_infra duckdb_list_tables(db_path) -> dict Introspección read-only: lista las tablas (information_schema.tables, schema main) ordenadas. Devuelve {status, tables}.
duckdb_table_schema_py_infra duckdb_table_schema(db_path, table) -> dict Introspección read-only: schema de una tabla (DESCRIBE). Devuelve {status, table, columns:[{name,type}]}. Útil para mapear tipos a otro motor (p.ej. PostgreSQL).
excel_to_duckdb_py_infra excel_to_duckdb(xlsx_path, duckdb_path, table, sheet=None, mode='replace') -> dict Puente de entrada Excel→DuckDB: ingiere una hoja .xlsx a una tabla con la extensión nativa excel de DuckDB. replace/append. Devuelve {status, table, row_count}.
duckdb_to_postgres_py_pipelines duckdb_to_postgres(duckdb_path, table, pg_dsn, pg_table=None, mode='replace', key_cols=None, batch_size=5000) -> dict Puente de salida DuckDB→Postgres: mapea tipos, crea la tabla y sincroniza filas. Desbloquea que Metabase/Grafana/Superset (que no hablan DuckDB) lean los datos. Devuelve {status, pg_table, rows_synced, created}.

Puentes: Excel → DuckDB → Postgres → visualización

DuckDB es el centro del stack de datos: el motor analítico embebido. Los datos entran desde Excel y salen hacia BI:

cd /home/enmanuel/fn_registry
python/.venv/bin/python3 - <<'PYEOF'
import sys
sys.path.insert(0, "python/functions")
from infra import excel_to_duckdb, duckdb_list_tables, duckdb_query_readonly
from pipelines.duckdb_to_postgres import duckdb_to_postgres

# 1. Excel -> DuckDB (extensión nativa, sin pandas)
excel_to_duckdb("/tmp/ventas.xlsx", "/tmp/datos.duckdb", "ventas", sheet="ventas")
print(duckdb_list_tables("/tmp/datos.duckdb"))

# 2. Analítica en DuckDB
print(duckdb_query_readonly("/tmp/datos.duckdb",
    "SELECT categoria, SUM(importe) AS total FROM ventas GROUP BY 1")["rows"])

# 3. DuckDB -> Postgres (para que Metabase/Grafana lo lean)
# dsn = "postgresql://captacion:<pass>@localhost:5433/trends"
# duckdb_to_postgres("/tmp/datos.duckdb", "ventas", dsn, pg_table="ventas", mode="replace")
PYEOF
  • Evidence.dev lee el .duckdb directamente (nativo) — no necesita el puente a Postgres.
  • Metabase / Grafana / Superset no hablan DuckDB → usa duckdb_to_postgres y apunta la herramienta al Postgres espejo.

Ejemplo canonico

Consulta read-only desde cualquier sesion (la conexion se abre read_only=True y se cierra siempre):

cd /home/enmanuel/fn_registry
python/.venv/bin/python3 - <<'PYEOF'
import sys
sys.path.insert(0, "python/functions")
from infra import duckdb_query_readonly

res = duckdb_query_readonly(
    "projects/osint/apps/osint_db/data/osint.duckdb",
    "SELECT contexto, COUNT(*) AS n FROM persons GROUP BY contexto ORDER BY n DESC",
    max_rows=50,
)
print(res["status"], res["row_count"])
for row in res["rows"]:
    print(row)
PYEOF

Conversion CSV -> Parquet en una linea:

./fn run csv_to_parquet_duckdb datos.csv datos.parquet

Gotchas del grupo

  • Single-writer: DuckDB permite UN solo proceso escritor por archivo. Si un service (ej. osint_db) posee la base, el resto de procesos deben leer con read_only=True (duckdb_query_readonly ya lo hace) o pasar por la API HTTP del service. Las funciones de escritura (duckdb_execute, duckdb_upsert) abren en read-write y SOLO debe usarlas el proceso dueño de la base (dentro de su write lock), nunca un cliente concurrente.
  • Version del motor: el formato de archivo puede cambiar entre versiones mayores de DuckDB. El venv del registry lleva duckdb 1.5.x; no mezclar con CLIs/WASM antiguos sobre el mismo archivo.
  • read_only=True exige que el archivo exista — no crea bases nuevas.

Fronteras

  • NO cubre SQLite (sqlite_open_go_infra y el grupo de operations.db van aparte).
  • NO cubre el render de resultados a Markdown/notas — eso es render_markdown_table_py_core + upsert_sentinel_block_py_core (grupo obsidian).
  • El analisis exploratorio pesado (notebooks) vive en analysis/ con sus propios venvs.