Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QYZodsX5a4ksWdrwKXSExX
132 lines
6.6 KiB
Markdown
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.
|