- 0038: lanzar Chrome/Edge/Brave externo con --remote-debugging-port + --user-data-dir por profile, control via CDP desde cdp-cli Go. Decision Go vs C++ in-process documentada; deja la puerta abierta a un cliente C++ minimo solo para streaming en el futuro. Supersedes 0032. - 0039: gestor de cookies/sesiones por profile via CDP — list, export EditThisCookie, import, clear selectivo, health checks con selectores, locks cuando un enricher esta usando el profile. - 0040: profiles como concepto de primera clase — metadata (color, icon, browser_preference, UA, project, template), templates anon/auth/work/ investigation, ProfilePicker reusable, project default, tag en executions.metrics. Actualiza 0038 para apuntar a 0040 como duenio del UX de profiles.
11 KiB
id, title, status, priority, created, depends_on, related
| id | title | status | priority | created | depends_on | related | ||
|---|---|---|---|---|---|---|---|---|
| 0040 | Gestion de multiples profiles de browser como concepto de primera clase | pending | high | 2026-05-04 |
|
|
Contexto y objetivo
0038 ya soporta tecnicamente N profiles en paralelo (cada uno con
--user-data-dir propio y puerto CDP propio). 0039 gestiona las
cookies dentro de cada profile. Falta la capa de gestion humana:
que cada profile sea un "usuario" identificable con metadata, que el
agente y el humano puedan elegir cual usar en cada momento, y que
existan templates para los casos tipicos del flujo OSINT.
Caso real: el usuario tiene en paralelo
personal— su cuenta real de LinkedIn / Gmail / X.osint_anon— sin login, user-agent neutro, sin extensiones, para scraping no atribuido.corp_aurgi— cuenta corporativa con SSO.linkedin_alt— cuenta secundaria para busquedas masivas.investigation_<caso>— profile temporal por investigacion concreta.
Hoy no hay forma de distinguir uno de otro mas alla del nombre de carpeta. Este issue convierte el "profile" en una entidad propia con metadata, ciclo de vida y selector unificado.
Modelo de profile
Cada profile es una fila en browser_profiles (ya creada en 0039)
ampliada con metadata operativa:
CREATE TABLE browser_profiles (
name TEXT PRIMARY KEY, -- 'personal', 'osint_anon', ...
display_name TEXT, -- 'Personal — Lucas'
color TEXT, -- '#7B61FF' para badge en UI
icon TEXT, -- nombre Tabler: 'user', 'mask', 'building'
browser_preference TEXT, -- 'chrome' | 'edge' | 'brave' | 'auto'
default_user_agent TEXT, -- override; null = el del browser
default_headless INTEGER DEFAULT 0, -- bool
proxy TEXT, -- 'http://user:pass@host:port' o null
project_id TEXT, -- FK opcional a projects/*/project.md
template TEXT, -- 'anon' | 'authenticated' | 'work' | null
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_used_at TIMESTAMP
);
name sigue siendo el nombre de carpeta (local_files/browser_profiles/<name>/).
El resto es metadata pura — el directorio fisico no cambia.
UX: panel Profiles
Pestaña dedicada (separada del panel Browsers del 0038, que sigue
mostrando solo runtime de instancias vivas):
┌─ Profiles ────────────────────────────────────────────────────────────┐
│ [+ New] [Clone] [Import .json] [Filter: all|active|by-project ▼] │
│ │
│ ● personal 👤 Chrome Personal — cuenta real [edit] │
│ ● osint_anon 🎭 Chrome Anon scraping (UA neutro) [edit] │
│ ○ corp_aurgi 🏢 Edge SSO Aurgi [edit] │
│ ○ linkedin_alt 👥 Chrome Cuenta secundaria LI [edit] │
│ ○ inv_caso_2026_03 🔍 Chrome Investigacion <proyecto X> [edit] │
│ │
│ Selected: personal │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Browser: Chrome 130 Display name: Personal — Lucas │ │
│ │ UA: (default) Proxy: - │ │
│ │ Project: (global) Template: authenticated │ │
│ │ Folder: local_files/browser_profiles/personal/ (124 MB) │ │
│ │ Last used: 2 hours ago Cookies: 312 in 47 domains │ │
│ │ │ │
│ │ [Launch] [Launch headless] [Sessions] [Cookies] [Delete] │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
- Color + icon dan distincion visual rapida en cualquier lugar del app donde aparezca el profile (badge en Toolbar, tag en executions, ...).
- ● vivo / ○ parado (estado runtime, leido del panel
Browsers). - "Sessions" abre el panel del
0039filtrado por este profile.
Templates
Botones de [+ New] ofrecen 4 templates con defaults distintos:
| Template | UA default | Headless | Notas tipicas |
|---|---|---|---|
anon |
Mozilla/5.0 ... Chrome/130 (neutro, sin client hints) |
true | scraping sin atribucion, sin login |
authenticated |
UA real del browser | false | tu cuenta real, requiere login interactivo |
work |
UA real | false | cuenta corporativa con SSO |
investigation |
UA neutro | false | profile efimero por caso, ligado a un project |
El template solo prerellena los campos al crear — despues se editan.
Seleccion de profile al lanzar enricher
Cuando un enricher CDP se invoca (desde Echo, jobs queue o boton manual) necesita decidir el profile. Reglas en orden:
- Param explicito
browser_profile=<name>→ usa ese. - Project default — si la entidad/operacion pertenece a un project
y existe un profile con
project_id=<proj>marcado como default → usa ese. - Template hint — si el enricher tiene
prefers_template: authenticated(ej.fetch_webpage_browserpara LinkedIn) → propon los profiles con ese template ordenados porlast_used_at. - Fallback →
default(siempre existe, templateanon).
Si la regla 1 no se cumple y hay ambiguedad, Echo pregunta:
"Para enriquecer este perfil de LinkedIn necesito una sesion. Tengo
personal(auth, last used 2h ago),linkedin_alt(auth, 3 dias),osint_anon(sin auth). ¿Cual uso?"
En la UI, cualquier dialogo que dispare un enricher CDP muestra un dropdown de profile con el sugerido pre-seleccionado.
Operaciones por profile
| Accion | Implementacion |
|---|---|
| Create | Crea fila + carpeta vacia. No lanza browser. |
| Clone | cp -r carpeta + nueva fila. Util para "voy a probar algo, hago clone de mi profile real". |
| Rename | Update fila + mv carpeta + actualizar browser_locks y referencias en jobs queue. |
| Delete | Confirm modal. Borra fila + carpeta. Falla si profile esta vivo. |
| Export full | Tar de la carpeta + manifest. Util para llevar profile a otro PC (con warning de secrets). |
| Import full | Untar + registrar fila. |
| Set as project default | Marca el profile como default para enrichers que operen sobre entidades del proyecto. |
Las operaciones de cookies/sesiones (0039) siguen siendo otro panel
y otro nivel.
Profile como tag en executions
Cada execution de un enricher CDP guarda el browser_profile usado
en sus metrics. Permite consultas tipo:
-- Cuantas paginas LinkedIn enriquecio cada profile?
SELECT json_extract(metrics, '$.browser_profile') as profile, COUNT(*)
FROM executions
WHERE function_id LIKE 'fetch_webpage_browser%'
AND json_extract(metrics, '$.url') LIKE '%linkedin.com%'
GROUP BY profile;
-- Profiles que han fallado mas en la ultima semana
SELECT profile, SUM(status='failure') as failures
FROM executions
WHERE created_at > date('now', '-7 days')
GROUP BY profile
ORDER BY failures DESC;
Plan de implementacion
| Fase | Entregable |
|---|---|
| 0040a | Schema de browser_profiles ampliado + migracion de profiles preexistentes (los del 0038 quedan como filas con metadata vacia). |
| 0040b | Panel Profiles read-only: lista + detalle. Lee carpetas existentes, muestra tamaño en disco, last_used_at. |
| 0040c | CRUD basico: New (con templates), Edit, Delete, Rename, Clone. |
| 0040d | Selector de profile en cualquier dialogo de enricher CDP — componente reusable ProfilePicker que aplica las reglas de seleccion de §"Seleccion de profile al lanzar enricher". |
| 0040e | Project default — UI para marcar profile X como default del project Y. Rule engine en cdp-cli lee este default. |
| 0040f | Tag browser_profile en executions.metrics automatico desde cdp-cli. |
| 0040g | Export/import full de profile (tar + manifest). Al importar, dialog para mapear si ya existe el nombre. |
| 0040h | Echo gana herramienta MCP browser_profile_pick para preguntar al usuario cuando hay ambiguedad. |
Riesgos y mitigaciones
| Riesgo | Mitigacion |
|---|---|
| Borrar profile destruye 1 GB de cache | Confirm modal con tamaño. Opcion "delete cookies only, keep cache" para casos intermedios. |
Confundir personal con linkedin_alt y postear con la cuenta equivocada |
Color + icon prominentes en cualquier UI. Echo SIEMPRE confirma profile antes de acciones de escritura (post, like, message — fuera de v1 igualmente). |
Profile default se borra por accidente |
Bloqueado: no se puede eliminar el profile literal default, solo renombrar (y se autocrea uno vacio). |
| Race condition al renombrar mientras enricher corre | El rename adquiere el browser_lock (de 0039) primero — falla si esta tomado. |
| Schema drift entre profiles creados a mano y registrados | Boton Scan folders en panel: detecta carpetas en browser_profiles/ sin fila en BD y propone registrarlas. |
Definicion de hecho
- Tengo 5 profiles visibles en el panel Profiles con icon/color distintos, cada uno con su browser_preference y notas.
- Lanzo un enricher
fetch_webpage_browserdesde el menu contextual de un nodoUrl, aparece un dropdown de profile condefaultpre-seleccionado y puedo cambiar apersonalantes de ejecutar. - Marco
corp_aurgicomo default del project<X>→ al enriquecer una entidad de ese project, el dropdown viene pre-seleccionado encorp_aurgi. - Clono
personalapersonal_test, modifico cookies en el clon, ypersonaloriginal sigue intacto. - Borro un profile vivo → falla con mensaje claro "profile in use, stop the browser instance first".
- Echo me pregunta "uso
personalolinkedin_alt?" cuando lanza un scraping LinkedIn y no hay default de project. - Una query SQL sobre
executions.metrics->browser_profileagrupa correctamente todos los fetches por profile usado.
Fuera de alcance
- Sync de profiles entre PCs — los profiles tienen secrets (cookies de auth). El export/import manual es la via. Sync automatico fuera de v1.
- Compartir profile entre apps del registry — hoy
local_files/es por-app. Si en el futuro otra app necesita los mismos profiles, se decide entonces si centralizar en~/.fn/browser_profiles/o symlinks. - Browser non-chromium (Firefox) — un profile Firefox tiene formato
distinto. Misma decision que
0038: solo chromium-based. - Profile encryption at rest — Chrome ya cifra secrets con DPAPI (Win) / Keychain (Mac). Linux usa cifrado debil pero esta fuera de nuestro control.