Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QYZodsX5a4ksWdrwKXSExX
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-Stdlibsqlite3, keine neue Abhängigkeit) mit Tabellensessionsundintroductions(Spalten:role,sender,session_id/introduced_at,updated_at; Primärschlüssel(role, sender)). worker.pyundbuilder.py:session_path()/sender_marker()und die zugehörigen Lese-/Schreibfunktionen (load_session,save_session,reset_session,add_first_reply_notice,mark_introduced) aufdb.pyumstellen.agent-codex.nix: neueAGENT_DB_PATH-Umgebungsvariable (${stateDir}/agent.db) incommonEnvironment.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) undpending_approval/pending_approval_repo(job_id, requested_by, commit_message, created_at bzw. job_id, repo_dir) indb.py. builder.py:save_start_pending/load_start_pending/delete_start_pendingsowiesave_pending_approval/load_pending_approval/delete_pending_approvalaufdb.pyumstellen.find_stash_ref()(Suche nach dem Marker-String ingit 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 diebuilder-*-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.nixoder Vikunja/GoToSocial — laut Recherche bereits korrekt (Bash-only bzw. bereits SQL-gestützt).
Annahmen
- Beide Rollen (
agent-codex-worker,agent-codex-builder) laufen alsType = "oneshot"-Services, die von ihrem jeweiligensystemd.pathsserialisiert getriggert werden -- pro Rolle läuft nie mehr als ein Prozess gleichzeitig gegenagent.db, SQLites Single-Writer-Grenze ist damit unkritisch. - Eine gemeinsame Datei
agent.dbfür beide Rollen (mitrole-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 dierole-Spalte bestehen.
Offene Risiken
- Falls zum Deploy-Zeitpunkt tatsächlich ein
start_pending- oderpending_approval-Vorgang offen ist und nicht rechtzeitig manuell aufgelöst wird, geht dieser Datensatz beim Umschalten verloren (die zugehörigengit stash-Einträge selbst bleiben aber erhalten und sind übergit stash listvon Hand wiederfindbar). - Unklar, ob
sqlite3unter dem bestehendensystemd-Sandboxing (ProtectSystem = "strict",ReadWritePaths) ohne weitere Anpassung in${stateDir}schreiben kann -- vermutlich ja, daStateDirectorybereits schreibbar ist, aber nicht verifiziert.
Erfolgskriterien
- Phase 1:
nix flake checkund Build von blunix erfolgreich;test_agent_codex.pygrün; nach Deploy zeigt eine neue Chat-Nachricht weiterhin korrektes Sitzungsverhalten (Fortsetzung//neu) und die Erstkontakt-Notiz erscheint nur beim ersten Kontakt -- beides jetzt ausagent.dbgelesen, nicht mehr aussessions//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.