This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/intent/agent-codex-state-sqlite-migration.md
2026-09-05 16:34:53 +02:00

6.6 KiB

Intent: agent-codex-State (Sessions, Freigaben) von Dateien auf SQLite umstellen

Status: Phase 1 umgesetzt, verifiziert (53 Tests, Smoke-Test gegen den echten AGENT_DB_PATH) und auf blunix deployed (2026-09-05, Commit fdf3ea9). Phase 2 (Freigabe-Workflows) weiterhin offen, eigener Auftrag.

Ziel

Auslöser: ein per Tailscale zugesandtes PDF ("Bash versus SQL im Agentic Workflow") mit der Kernthese, dass strukturierter Agenten-Zustand (Memory, Freigaben, Relationships) deklarativ in SQL gehört, während Bash/Shell die Ebene für offene Computerarbeit (Filesystem, Git, Prozesse) bleibt. Eine Repo-Recherche hat hosts/blunix/localServices/agent-codex/ als konkreten, akuten Kandidaten identifiziert: der XMPP-Codex-Agent (agent@/builder@bot.0ff.space) verwaltet Sessions, Erstkontakt-Marker und beide Freigabe-Workflows (/annehmen+/ablehnen, /freigeben+/verwerfen) komplett als JSON-Dateien in Verzeichnissen — das im PDF beschriebene Muster ohne Schema, Transaktionen oder Query-Planner. Das README dokumentiert bereits einen daraus resultierenden Vorfall (30.07.2026): ein nixos-rebuild switch killte per SIGTERM einen laufenden Builder-Job, der Datensatz blieb verwaist in builder-processing/ liegen, bis nachträglich ein SIGTERM-Handler ergänzt wurde. Ziel dieses Auftrags: die Freigabe-/Sitzungs-Datensätze in eine lokale SQLite-Datenbank überführen, damit solche Zustände strukturell konsistent bleiben und per SQL statt ls/cat einsehbar sind — ohne die Job-Queue- und Ausführungsebene (pfadgetriggerte systemd-Services, Codex-Aufrufe, Git-Operationen) anzutasten, die laut derselben PDF-Logik zu Recht imperativ/dateibasiert bleibt.

Umfang

Zwei Phasen, jede mit eigenem Abschluss und eigenem Deploy:

Phase 1 — Sessions und Erstkontakt-Marker:

  • Neues gemeinsames Modul hosts/blunix/localServices/agent-codex/db.py (Python-Stdlib sqlite3, keine neue Abhängigkeit) mit Tabellen sessions und introductions (Spalten: role, sender, session_id/introduced_at, updated_at; Primärschlüssel (role, sender)).
  • worker.py und builder.py: session_path()/sender_marker() und die zugehörigen Lese-/Schreibfunktionen (load_session, save_session, reset_session, add_first_reply_notice, mark_introduced) auf db.py umstellen.
  • agent-codex.nix: neue AGENT_DB_PATH-Umgebungsvariable (${stateDir}/agent.db) in commonEnvironment.
  • test_agent_codex.py: betroffene Tests auf eine temporäre SQLite-Datei pro Testfall umstellen statt Tempdir-Dateien.

Phase 2 — Freigabe-Workflows (builder-start-pending/, builder-pending/):

  • Tabellen start_pending (job_id, sender, requested_by, body, created_at) und pending_approval/pending_approval_repo (job_id, requested_by, commit_message, created_at bzw. job_id, repo_dir) in db.py.
  • builder.py: save_start_pending/load_start_pending/ delete_start_pending sowie save_pending_approval/ load_pending_approval/delete_pending_approval auf db.py umstellen. find_stash_ref() (Suche nach dem Marker-String in git stash list) bleibt unverändert — der Datensatz selbst wird nur abfragbar statt nur als Datei lesbar.

Beide Phasen jeweils mit dem üblichen blunix-Verify-Pfad (nix flake check → drvPath-Eval → Build → diff-closures → dry-activate → switch) und dem bestehenden manuellen Vorsichtsschritt aus dem README (systemctl is-active agent-codex-builder.service vor dem Switch prüfen).

Explizit ausgeschlossen

  • Die Job-Queue selbst (inbox/, processing/, failed/ und die builder-*-Pendants) bleibt dateibasiert — sie ist die pfadgetriggerte (systemd.paths, PathExistsGlob) Ausführungsebene, keine abzufragende Business-Struktur; eine Umstellung würde laut PDF ("SQL -> Queue -> Shell") nur eine schlechtere Shell hinter SQL verstecken.
  • Kein automatisiertes Migrationsskript für bestehende Datei-Datensätze. Sessions/Introductions sind verlustlos ersetzbar (nächste Nachricht startet nötigenfalls neu); offene start_pending/pending_approval-Vorgänge werden vor dem jeweiligen Deploy im Chat manuell aufgelöst (/annehmen, /ablehnen, /freigeben, /verwerfen).
  • Kein job_events-Audit-Log (PDF-Muster "Event Sourcing") — separat vormerken, nicht Teil dieses Auftrags.
  • Keine Änderung an find_stash_ref()s String-Matching-Mechanik selbst (robusterer Stash-Bezug über Commit-Hash statt Marker-Text) — eigener, späterer Auftrag, falls gewünscht.
  • Kein Eingriff in hosts/pinix/localServices/webhook.nix oder Vikunja/GoToSocial — laut Recherche bereits korrekt (Bash-only bzw. bereits SQL-gestützt).

Annahmen

  • Beide Rollen (agent-codex-worker, agent-codex-builder) laufen als Type = "oneshot"-Services, die von ihrem jeweiligen systemd.paths serialisiert getriggert werden -- pro Rolle läuft nie mehr als ein Prozess gleichzeitig gegen agent.db, SQLites Single-Writer-Grenze ist damit unkritisch.
  • Eine gemeinsame Datei agent.db für beide Rollen (mit role-Spalte) ist einfacher zu betreiben als zwei getrennte Dateien, ohne die bestehende Rollentrennung (getrennte Queues, getrennte Sender-Allowlists) aufzuweichen -- die Trennung bleibt rein logisch über die role-Spalte bestehen.

Offene Risiken

  • Falls zum Deploy-Zeitpunkt tatsächlich ein start_pending- oder pending_approval-Vorgang offen ist und nicht rechtzeitig manuell aufgelöst wird, geht dieser Datensatz beim Umschalten verloren (die zugehörigen git stash-Einträge selbst bleiben aber erhalten und sind über git stash list von Hand wiederfindbar).
  • Unklar, ob sqlite3 unter dem bestehenden systemd-Sandboxing (ProtectSystem = "strict", ReadWritePaths) ohne weitere Anpassung in ${stateDir} schreiben kann -- vermutlich ja, da StateDirectory bereits schreibbar ist, aber nicht verifiziert.

Erfolgskriterien

  • Phase 1: nix flake check und Build von blunix erfolgreich; test_agent_codex.py grün; nach Deploy zeigt eine neue Chat-Nachricht weiterhin korrektes Sitzungsverhalten (Fortsetzung//neu) und die Erstkontakt-Notiz erscheint nur beim ersten Kontakt -- beides jetzt aus agent.db gelesen, nicht mehr aus sessions//senders/.
  • Phase 2: ein kompletter /annehmen- und ein kompletter /freigeben-Durchlauf funktionieren unverändert aus Nutzersicht; sqlite3 agent.db 'SELECT * FROM pending_approval' zeigt einen offenen Vorgang korrekt an, solange er nicht abgeschlossen ist.
  • Alte Zustandsverzeichnisse (sessions/, builder-sessions/, senders/, builder-senders/, builder-start-pending/, builder-pending/) sind nach beiden Phasen in einem Folgecommit entfernt.