Ir al contenido

Arquitectura

Refleja la arquitectura file-backed y git-native. El trabajo de base está en su lugar en las capas de almacenamiento y secretos; los paneles de React que consumen los nuevos stores file-backed aún están siendo migrados desde el path legacy de SQLite.

httui-notes es un editor markdown de escritorio construido sobre Tauri (backend Rust + frontend React). Almacena runbooks + configuración en archivos planos, sincroniza vía git, y guarda secretos en el keychain del sistema operativo. SQLite sigue presente, pero solo como cache y estado efímero.

Desktop app ─┐
TUI binary ─┼─ todos leen el mismo vault en disco
MCP server ─┘ (repo git con .md + .toml)
PathRol
httui-core/Librería compartida pura Rust: parsers, executors, configuración del vault, secretos, wrapper de git CLI. Sin deps de GUI.
httui-desktop/src-tauri/Backend Tauri v2. Conecta comandos Tauri, posee el watcher en ejecución + el sidecar del chat.
httui-desktop/src/Frontend React + TypeScript. Editor CodeMirror 6, Chakra UI v3, stores Zustand.
httui-tui/Binario de terminal (viewer read-only + executor para v1; el TUI editor completo es scope futuro).
httui-mcp/Binario del servidor MCP. 14 herramientas (list/read/create/update notes, search, connections, environments).
httui-sidecar/Proceso Node.js que la desktop app lanza para la feature de chat (Claude Agent SDK).
httui-web/Landing page de marketing (app Vite separada).

El vault es un repo git común y corriente. httui agrega un directorio .httui/ más algunos archivos de configuración conocidos en la raíz:

my-vault/
├── runbooks/ # archivos .md con bloques ejecutables
├── connections.toml # definiciones de conexión compartidas
├── connections.local.toml # override personal (gitignored)
├── envs/
│ ├── local.toml
│ ├── staging.toml
│ ├── staging.local.toml # override personal (gitignored)
│ └── prod.toml
├── .httui/
│ ├── workspace.toml # defaults del workspace (committed)
│ └── workspace.local.toml # override personal (gitignored)
├── .gitignore # auto-incluye el bloque *.local.toml
└── notes.db # cache SQLite (gitignored)

Los archivos commiteados se pueden revisar como diffs en un PR. Los hermanos .local.toml hacen deep-merge sobre su base al leer; los writes siempre apuntan al archivo base (ADR 0004).

Las preferencias por máquina (tema, fuente, densidad, keybindings, backend de secretos, toggles de MCP) viven en ~/.config/httui/user.toml (XDG en Linux; en otros, el directorio de configuración nativo del SO).

DatoVive enSincronizado vía git
Runbooks (.md)repo
Definiciones de conexiónconnections.toml
Contraseñas de conexiónOS keychainno (por máquina)
Variables de entorno (no secretas)envs/<name>.toml [vars]
Variables de entorno (secretas)OS keychain (el TOML lleva una ref {{keychain:...}})no
Overrides personales*.local.tomlno (gitignored)
Defaults del workspace.httui/workspace.toml
Preferencias por máquina~/.config/httui/user.tomlno
Historial de runsSQLite block_run_historyno
Cache de resultados de bloquesSQLite block_resultno
Introspección de schemaSQLite schema_cacheno
Sesiones de chatSQLite sessions / messagesno
Vault activo / layout de panes / posiciones de scrollSQLite app_configno

Las siete claves de prefs de UI (theme, auto_save_ms, editor_font_size, default_fetch_size, history_retention, vim_enabled, sidebar_open) se mantuvieron en SQLite durante el MVP; la migración a v1 las mueve a user.toml [ui]. Las claves de session-state (vaults, active_vault, pane_layout, active_pane_id, active_file, scroll_positions) se quedan en SQLite porque son writes por keystroke.

Forma del código — httui-core/src/vault_config/

Sección titulada «Forma del código — httui-core/src/vault_config/»

La capa de configuración file-backed vive en este módulo:

ArchivoRol
connections_store.rsCRUD sobre connections.toml vía keychain. Cacheado por mtime.
environments_store.rsCRUD sobre envs/*.toml y tracking del env activo en user.toml.
workspace_store.rsCRUD sobre .httui/workspace.toml.
user_store.rsCRUD sobre ~/.config/httui/user.toml con resolución XDG.
merge.rsDeep-merge para overrides *.local.toml (ADR 0004).
gitignore.rsAugmenta automáticamente el .gitignore del vault con los patrones canónicos *.local.toml.
migration.rsMigración one-shot de las tablas SQLite del MVP al layout de archivos. Idempotente + dry-run + backup.
missing_secrets.rsScanner de primer arranque para refs {{keychain:...}} que aún no están pobladas.
scaffold.rsEsqueleto default del vault + heurística is_vault().
watch_paths.rsClasificador de paths puro consumido por el watcher (Connections / Env / Workspace).
validate.rsCheck anti-cleartext-secret + validación estructural.
atomic.rsHelper de write atómico (archivo temporal + fsync + rename, ADR 0003).

Todos los stores cachean por (base_mtime, local_mtime) para que las ediciones externas a cualquier lado invaliden correctamente. Los paths de mutación leen solo el base para evitar promover overrides al archivo committed (audit-003).

Las referencias {{backend:address}} en TOML resuelven en tiempo de lectura a través de un trait SecretBackend (httui-core/src/secrets/). La implementación default es Keychain (delega al crate keyring / OS keychain). Backends futuros — Touch ID, Windows Hello, 1Password CLI, pass — se conectan detrás del mismo trait sin cambios en los callsites (Epics 14-16).

El parser (secrets/parser.rs) reconoce cuatro prefijos de backend: keychain, 1password, pass, env. Cualquier otra cosa es un parse error.

El validador rechaza valores de secretos en texto plano escritos en secciones [secrets] — un error fuerte, no un warning. El escape hatch es # httui:allow-cleartext según ADR 0002.

Un único watcher a nivel del SO (crate notify, recursivo) en la raíz del vault. El dispatcher rutea eventos:

  • *.md → flujo file-reloaded existente (lee contenido, emite al frontend, ConflictBanner si está dirty)
  • TOML de configuración observada (vía watch_paths::classify) → emite evento config-changed con { category, path, env? }. Los stores invalidan caches por mtime; el cutover de frontend pendiente agregará una llamada a Store::invalidate_cache() al recibir el evento.

Debounce: 500 ms para .md, 250 ms para TOML (ADR 0003).

┌──────────────────────────┐ ┌──────────────────────────┐
│ Tauri main (Rust) │ │ Node.js sidecar │
│ │ ◀──┤ (Claude Agent SDK) │
│ - executor registry │ │ │
│ - file watcher │ │ lanzado en el primer │
│ - keychain bridge │ │ mensaje de chat; NDJSON │
│ - chat permission broker│ │ sobre stdin/stdout │
└──────────────────────────┘ └──────────────────────────┘
│ Tauri IPC (invoke / Channel)
┌──────────────────────────┐
│ React + Vite (webview) │
│ │
│ - editor CodeMirror 6 │
│ - paneles Chakra UI │
│ - stores Zustand │
└──────────────────────────┘

El sidecar se verifica vía ping/pong y se respawnea en caso de fallo con backoff exponencial. El permission broker del chat (httui-desktop/src-tauri/src/chat/permissions.rs) intercepta las llamadas a herramientas antes de preguntarle al usuario.

Las decisiones de arquitectura viven bajo docs/adr/:

Las decisiones futuras siguen el mismo template (Status / Context / Decision / Consequences / References).

Qué NO está aquí (fuera de scope por ahora)

Sección titulada «Qué NO está aquí (fuera de scope por ahora)»

La superficie deliberadamente excluida:

  • Sin web app — solo desktop + TUI.
  • Sin CLI runner — httui run runbook.md --env=staging es idea para v2.
  • Sin self-host con Docker — el vault es un repo git; ese es el servidor de sync.
  • Sin rediseño formal del lifecycle de ejecución de bloques — el actual “run / cancel” es suficiente por ahora.
  1. httui-core/src/blocks/parser.rs — markdown → block AST.
  2. httui-core/src/executor/{http,db}/ — paths de ejecución de bloques.
  3. httui-core/src/vault_config/ — la capa de storage descrita arriba.
  4. httui-desktop/src/components/blocks/ — paneles React para HTTP / DB.
  5. httui-desktop/src/stores/ — estado Zustand.

CLAUDE.md en la raíz del repo tiene las notas de arquitectura vigentes que usan los agentes de IA; es intencionalmente más granular que este archivo y trackea los paths reales + line counts de los módulos calientes.