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

132 lines
6.6 KiB
Markdown

# 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.