Files
grok-bot 812d493bd6 feat(loop): live progress with heartbeat, turns, and goal-file
Emit phase start/done events, 20s status ticks during long agent/compact/
handoff work, and post-step turns/tools/notes/summary for clm run.
Add --quiet (keeps end summary) and --goal-file via resolve_goal.
2026-08-05 10:36:47 +02:00

21 KiB
Raw Permalink Blame History

Getting Started — CLM

Ziel: In ca. 15–25 Minuten CLM offline installieren, den Outer Loop einmal laufen lassen und CONTINUE / COMPACT / HANDOFF an echten Artefakten nachvollziehen.

Kein API-Key nötig. Der Guide nutzt den mitgelieferten SimulatedAgent und das Fixture tests/fixtures/sample_transcript.json.

Alle Befehle vom Repository-Root ausführen (cd ins geklonte Repo). Pfade und Session-IDs sind so gewählt, dass du die Blöcke 1:1 kopieren kannst.


Worum geht’s?

Lange Agent-Sessions füllen das Context Window: mehr Messages, Tool-Outputs und Historie → höhere Token-Kosten, schlechtere Recall und irgendwann harte Limits. Manuelles „Zusammenfassen und neu starten“ ist fehleranfällig und nicht auditierbar.

CLM (Context Lifecycle Management) ist ein framework-agnostischer Outer Control Loop über dem ausführenden Agenten. Pro Step misst es Tokens/Context und entscheidet:

Aktion Bedeutung Typische Auswirkung
CONTINUE Context im grünen Bereich Nächster Agent-Step, keine Intervention
COMPACT Soft-Threshold überschritten Context verdichten, Snapshot ins Memory, Messages kürzen (nach Verify)
HANDOFF Hard-Threshold, Phase-Grenze oder Verify-Fail Strukturiertes Manifest schreiben, Session-Übergang / Stop

CLM ersetzt deinen Agenten nicht — es beobachtet und steuert ihn (SimulatedAgent offline; konfigurierbare Live-Adapter z. B. Grok Build — siehe coding-agents.md).

CLM Kontext-System

Outer Loop (Decision Engine), Orchestrierung und Context Management Core um die Working Session. Details: architecture.md.


Wie der Outer Loop tickt

Pro Step läuft grob dieser Zyklus:

1. Agent.step(messages)          → neue Messages, Token-Counts, task_status
2. MetricsMonitor.update(...)    → TokenSnapshot, append metrics.jsonl
3. DecisionEngine.decide(...)    → CONTINUE | COMPACT | HANDOFF (+ trigger, rationale)
4. Aktion ausführen:
     CONTINUE  → nächster Step
     COMPACT   → CompactionPipeline (+ Verify), dann oft weiter
     HANDOFF   → HandoffPipeline (Manifest), Loop stoppt typischerweise

Soft- vs. Hard-Threshold

Schwelle CLI-Flag Rolle
soft_compact --soft-compact Ab hier darf/soll verdichtet werden (Context retten, Session fortsetzen)
hard_handoff --hard-handoff Ab hier ist Weiterarbeiten riskant → strukturierter Handoff

Im Profil coding (Default) liegen die eingebauten Defaults bei ca. soft ≈ 250 000 und hard ≈ 350 000 Tokens. In den Demo-Szenarien überschreiben wir die Werte absichtlich, damit das 4-Step-Fixture deterministisch CONTINUE, COMPACT oder HANDOFF zeigt.

Default-Metrik für Schwellen: session-kumulativ tokens.total_tokens (Summe über Steps). Optional kann die Engine auf Window-Schätzung (context_tokens) umgestellt werden — das ist fortgeschritten und hier nicht nötig. Details: metrics.md.

Entscheidungsreihenfolge (Alltagssprache)

Die Engine prüft Regeln in fester Priorität (vereinfacht):

  1. Externe Phasengrenze (z. B. nach clm signal --phase-done) und Policy „lieber handoff“ → HANDOFF
  2. Tokens ≥ hard → HANDOFF (trigger=hard_handoff)
  3. Tokens ≥ soft (und genug Steps seit letztem Compact) → COMPACT (trigger=soft_compact)
  4. Sonst → CONTINUE (trigger=none)

Zusätzlich (P2): schlägt die Verified Compaction fehl, erzwingt der Loop einen Handoff mit trigger=verify_fail — die Messages bleiben dann unangetastet.

Jede Entscheidung landet in decisions.jsonl mit action, trigger, rationale, step_index, total_tokens.


Das Demo-Fixture

Datei: tests/fixtures/sample_transcript.json

Der SimulatedAgent spielt daraus 4 deterministische Steps einer kleinen Auth-/Login-Story ab (kein LLM-Call). Jeder Step liefert u. a. messages_added, input_tokens, output_tokens, task_status.

Step ~kumuliert total_tokens task_status Inhalt (kurz)
1 12 800 running Auth-Modul lesen / Login skizzieren
2 60 300 running Handler implementiert, Datei geschrieben
3 149 500 running Tests gelaufen, offene Punkte
4 244 900 completed MVP-Scope fertig

Damit sind die Demo-Thresholds nachvollziehbar:

Szenario soft / hard Erwartetes Verhalten
Nur CONTINUE 500 000 / 600 000 Alles ≪ soft → 4× continue, Task completed
COMPACT 1 000 / 500 000 Schon nach Step 1 soft überschritten → mehrmals compact, trotzdem completed
HANDOFF 5 000 / 20 000 Nach Step 1 oft compact; ab Step 2 (~60k) hard → handoff + Manifest

Voraussetzungen

  • Python ≥ 3.12 (python --version)
  • uv empfohlen (schnell, Lockfile uv.lock im Repo)
    • Alternativ: python -m venv .venv + pip install -e ".[dev]"
  • Git-Checkout dieses Repos
  • Optional: mise — pinnt Tool-Versionen laut mise.toml (Python/uv). Kein Ersatz für uv beim Installieren der Python-Dependencies

1. Installation

uv venv legt eine projektlokale virtuelle Umgebung unter .venv/ an. Das editable Install (-e ".[dev]") verknüpft das Package clm aus src/ und zieht Dev-Tools (pytest, ruff, mypy).

uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
clm --help

Erwartung: CLI-Hilfe mit u. a.:

Befehl Rolle im Einstieg
init Workspace .clm/ anlegen
decide DecisionEngine dry-run
run Outer Loop mit pluggablem Agent (--agent, Default: Simulated + Script)
status Letzte Metrics/Decisions einer Session
compact / handoff Manuell auf persistiertem state.json
export, calibrate, signal, backup, experiment Später / Ops (P3–P4)

Optional Qualität prüfen (sollte grün sein):

pytest -q
# optional: ruff check src tests && mypy src/clm

Alternative mit mise

Wenn mise installiert ist, liefert mise.toml Python 3.12 und eine gepinnte uv-Version. Dependencies bleiben bei uv / uv.lock.

mise install
mise run install
mise run check    # ruff + mypy + pytest
clm --help

Hinweis: Ohne Shell-Hook (eval "$(mise activate zsh)") greifen Pins vor allem über mise run / mise exec. Der klassische uv-Pfad oben funktioniert unabhängig davon.


2. Workspace anlegen

CLM speichert Runtime-Artefakte unter einem Home-Verzeichnis (Default: .clm im CWD). init legt die Struktur und eine leere Memory-Basis an.

clm init --path .clm

Erwartung (Auszug): Initialized CLM home at … und Unterordner.

Pfad Zweck
memory/MEMORY.md Einstieg / Overview des datei-basierten Long-Term Memory
memory/topics/ Themen-Snapshots
memory/logs/ Memory-Logs
sessions/ Pro Session: state.json, metrics.jsonl, decisions.jsonl
manifests/ Handoff-Manifeste (JSON)
backups/ Memory-Backups (clm backup …)
exports/ Exportierte Metrics/Reports
calibrations/ Empfohlene Thresholds (clm calibrate --write)

Warum --path? Du kannst mehrere Homes parallel nutzen (z. B. Demo vs. Experiment) oder Artefakte außerhalb des Repo halten. Wichtig: Sobald du nicht .clm im CWD nutzt, denselben --path bei allen Folge-Befehlen angeben — sonst sucht CLM am Default und meldet „home not found“.

.clm/ ist typischerweise lokal (Sessions/Manifeste stehen oft in .gitignore bzw. sollen nicht committed werden). Das ist beabsichtigt.


3. Entscheidung dry-run (ohne Agent)

clm decide ruft nur die DecisionEngine auf: du gibst eine Token-Zahl und ein Profil, bekommst action + trigger — ohne Loop, ohne Fixture, ohne Memory.

Profil coding Default: soft ≈ 250k, hard ≈ 350k.

# Unter soft → continue
clm decide --tokens 100000 --profile coding
# → action=continue  trigger=none

# Soft überschritten → compact
clm decide --tokens 260000 --profile coding
# → action=compact  trigger=soft_compact

# Hard überschritten → handoff
clm decide --tokens 360000 --profile coding
# → action=handoff  trigger=hard_handoff

So siehst du, dass nur die Schwellen die Aktion steuern — bevor ein Loop startet. Im echten run kommen dieselben Regeln nach jedem Agent-Step zum Zug, plus Compaction-Verify und optionale Policies.


4. Erster Loop: nur CONTINUE

Das Fixture endet bei ca. ~245k Tokens gesamt. Mit hohen Thresholds bleibt alles unter soft/hard → nur continue, Task läuft bis completed.

Parameter kurz erklärt

Flag Bedeutung hier
--goal / --goal-file Task-Ziel als String oder UTF-8-Datei (mutually exclusive); User-Seed + State/Manifest
--script JSON-Liste von SimulatedAgent-Steps
--profile Default-Threshold-Profil (coding)
--soft-compact / --hard-handoff Überschreiben der Profil-Schwellen für dieses Demo
--max-steps Sicherheitslimit (20 ≫ 4 Fixture-Steps)
--session-id Fester Name → vorhersagbare Pfade unter sessions/
--path CLM-Home (hier .clm)
--quiet Unterdrückt Live-Progress (End-Summary bleibt)
clm run --goal "getting-started continue" \
  --script tests/fixtures/sample_transcript.json \
  --profile coding \
  --soft-compact 500000 --hard-handoff 600000 \
  --max-steps 20 --session-id gs-continue --path .clm

Erwartung (CLI-Auszug): Während des Runs siehst du Live-Progress mit Phasen: phase=agent vor dem Agent-Step (inkl. max_turns-Budget), phase=done danach inkl. Decision; bei Coding-Agents zusätzlich turns=N/max, tools=…, optional notes/summary der Agent-Antwort. Bei langen Steps alle ~20 s eine status-Zeile mit elapsed= (kein Live-Turn-Zähler mitten im Subprocess). Bei --max-steps zusätzlich step=i/max und open=N. Compact/Handoff melden jeweils phase=start und phase=done. Mit --quiet entfallen die Progress-Zeilen, die Summary bleibt.

>>> clm run start session_id=gs-continue agent=simulated soft=500000 hard=600000 max_steps=20
goal=getting-started continue
step=1/20 phase=agent status=running open=19 max_turns=8
step=1/20 phase=done status=running tokens.total=12800 (+…) decision=continue trigger=none open=19 max_turns=8 tools=0
…
<<< clm run end stopped_reason=completed status=completed steps=4 …
session_id=gs-continue
stopped_reason=completed
status=completed
steps=4
tokens.total=244900
compact_count=0
decisions=4

Danach Status und Decisions prüfen:

clm status --session-id gs-continue --path .clm
grep '"action"' .clm/sessions/gs-continue/decisions.jsonl

Erwartung:

  • status zeigt vier Metric-Zeilen und vier Decisions
  • in decisions.jsonl nur "action": "continue" mit "trigger": "none"
  • Rationales sinngemäß: no handoff or compact rule matched

Illustrative Decision-Zeile (Felder gekürzt):

{
  "action": "continue",
  "trigger": "none",
  "rationale": "no handoff or compact rule matched",
  "step_index": 1,
  "total_tokens": 12800
}

Warum so? Soft/hard liegen bewusst über dem Fixture-Maximum (~245k). Die Engine hat keinen Grund zu intervenieren — ideal, um „gesunden“ Loop und Artefakt-Schreiben ohne Side-Effects zu sehen.


5. Artefakte lesen

Pro Session unter .clm/sessions/<id>/:

.clm/sessions/gs-continue/
  state.json         # aktueller Session-Stand (Source of Truth für resume/compact/handoff)
  metrics.jsonl      # ein JSON-Objekt pro Zeile und Step
  decisions.jsonl    # eine Decision (oder Verify-Event) pro Zeile
Datei Inhalt
state.json goal, status, step_index, messages, tokens, memory_keys, Listen wie changed_artifacts / blockers, …
metrics.jsonl Token-Snapshots pro Step (append-only); optional Cost-Felder ab P4
decisions.jsonl Jede CONTINUE/COMPACT/HANDOFF-Entscheidung inkl. trigger & rationale; bei Compaction zusätzlich Verify-Events

state.json — worauf achten?

Feld Bedeutung
session_id / goal Identität und Auftrag
status z. B. running, completed, phase_boundary, …
step_index Wie viele Agent-Steps bereits gelaufen sind
tokens.total_tokens Kumulierte Session-Tokens (Schwellen-Default)
tokens.context_tokens Grobe Window-Schätzung (chars//4 der Messages)
last_compact_step Letzter Compact-Step oder null
memory_keys Keys, die Compaction/Handoff ins Memory geschrieben haben
messages Aktuelles Context Window (nach Compact ggf. gekürzt)

Lesepfad

  1. clm status — schneller Überblick ohne JSON-Parsing
  2. decisions.jsonl — warum CONTINUE/COMPACT/HANDOFF
  3. metrics.jsonl — Token-Verlauf pro Step
  4. state.json — voller Stand (Messages, Artefakt-Listen)
  5. Bei Handoff: .clm/manifests/

Die JSONL-Dateien eignen sich für grep/jq. Formale Metrik-Definitionen: metrics.md.

Hinweis zu status: Die Kurzzeilen unter Metrics zeigen oft die pro-Step-Tokenfelder der Logzeile; die Decision-Zeilen und state.tokens.total_tokens tragen die kumulierte Session-Summe, die für Soft/Hard zählt. Nicht wundern, wenn die Zahlen unterschiedlich aussehen — sie messen leicht verschiedene Schnitte derselben Session.


6. Mini-Szenario: COMPACT

Niedrige soft-Threshold (1000) → schon nach Step 1 (total_tokens ≈ 12 800) greift Compaction. Hard bleibt hoch, damit die Session nicht handoffed, sondern nach dem Verdichten weiterläuft.

clm run --goal "getting-started compact" \
  --script tests/fixtures/sample_transcript.json \
  --profile coding \
  --soft-compact 1000 --hard-handoff 500000 \
  --max-steps 20 --session-id gs-compact --path .clm

Erwartung:

stopped_reason=completed
compact_count=3          # typisch: compact nach Steps 1–3; Step 4 completed
last_recall_score=1.0    # Verify ok im Offline-Pfad
grep compact .clm/sessions/gs-compact/decisions.jsonl
clm status --session-id gs-compact --path .clm

In decisions.jsonl siehst du typischerweise Paare aus:

  1. Decision action=compact, trigger=soft_compact, Rationale mit tokens.total_tokens (…) >= soft_compact (1000)
  2. Event compaction_verify mit trigger=verify_ok, recall_score=1.0

Was passiert bei COMPACT?

  1. Strukturierte Summary aus dem Session-State (Offline: ohne LLM)
  2. Snapshot ins Memory (Key u. a. unter Session/Compact-Step)
  3. Compact-Hint (Markdown): Goal, Constraints, Next action, Memory-Keys, Verified/Not verified
  4. Verified Compaction: deterministische Recall-Fragen gegen Summary+Hint (Goal, Verified, Constraints, Blockers). Default-Schwellwert recall_score_threshold ≈ 0.8
  5. Nur bei Verify-OK: Messages werden ersetzt (System-Hint + recent retain) — Context schrumpft
  6. Bei Verify-Fail: Messages bleiben; Loop erzwingt HANDOFF mit trigger=verify_fail

Im Offline-Demo mit dem Sample-Fixture ist Verify in der Regel grün (recall_score=1.0). Das Feature schützt dich später bei realen Sessions davor, kritische Fakten wegzuschneiden.

Optional Memory ansehen:

ls .clm/memory/
# je nach Lauf: MEMORY.md, topics/, logs/ und geschriebene Compact-Keys

7. Mini-Szenario: HANDOFF

Niedrige hard-Threshold (20 000): nach Step 1 (~12.8k) kann noch compact greifen (soft=5000); nach Step 2 (~60.3k) ist hard überschritten → HANDOFF und Loop-Stop.

clm run --goal "getting-started handoff" \
  --script tests/fixtures/sample_transcript.json \
  --profile coding \
  --soft-compact 5000 --hard-handoff 20000 \
  --max-steps 20 --session-id gs-handoff --path .clm

Erwartung:

stopped_reason=handoff
status=running              # Task nicht „completed“ — bewusst unterbrochen
steps=2
tokens.total=60300
handoff_manifest=.clm/manifests/<timestamp>_gs-handoff.json
ls .clm/manifests/
clm status --session-id gs-handoff --path .clm

Was ist ein Handoff-Manifest?

Das Manifest ist die auditierbare Übergabe an eine Folgesession (Mensch oder Agent): Ziel, Stand, was verifiziert ist, was als Nächstes sicher ist, welche Memory-Keys geladen werden sollen.

Zentrale Felder (Auszug):

Feld Rolle
goal Auftrag der Session
status z. B. in_progress (hier typisch)
next_safe_action Sichere nächste Aktion für die Fortsetzung
memory_keys Keys zum Seed-Retrieval
token_snapshot Token-Stand zum Handoff
decision_rationale Warum gehandoft wurde (z. B. hard threshold)
changed_artifacts / verified / not_verified / blockers Arbeitsstand
schema_version Manifest-Version (aktuell 1.1)

Vollständige Feldliste und JSON Schema: manifest-schema.md, schemas/handoff_manifest.schema.json.

Illustrativer Kern (Werte je nach Lauf):

{
  "goal": "getting-started handoff",
  "status": "in_progress",
  "schema_version": "1.1",
  "token_snapshot": 60300,
  "decision_rationale": "tokens.total_tokens (60300) >= hard_handoff (20000)",
  "next_safe_action": "Resume from manifest next_safe_action / re-read source_of_truth"
}

8. Optional: ein Schritt weiter

Sobald CONTINUE/COMPACT/HANDOFF sitzen, sind das nützliche nächste Offline-Schritte (je 1–2 Minuten). Details und weitere Flags: README.md.

Metrics exportieren (JSON/HTML unter .clm/exports/):

clm export metrics --format json --session-id gs-continue --path .clm
clm export metrics --format html --session-id gs-continue --path .clm

Phasengrenze signalisieren (nächste Decision bevorzugt Handoff, wenn Policy greift):

# nur sinnvoll auf einer noch „lebenden“ / non-terminal Session
clm signal --phase-done --session-id <id> --path .clm

Session fortsetzen (--resume liest state.json und setzt den SimulatedAgent am step_index fort — greift nicht auf bereits completed / final gehandoften Terminal-Zuständen im Sinne „fertig“; für Experimente ggf. frische Session-ID nutzen):

clm run --resume <session-id> \
  --script tests/fixtures/sample_transcript.json \
  --path .clm

Memory backupen:

clm backup memory --path .clm --label getting-started

Manuell compact/handoff auf persistiertem State (ohne vollen Loop):

clm compact --session-id gs-continue --path .clm
clm handoff --session-id gs-continue --path .clm

Was du jetzt kannst

  • CLM offline installieren und den Outer Loop mit dem SimulatedAgent steuern
  • Erklären, wann CONTINUE, COMPACT und HANDOFF greifen (soft/hard, Priorität)
  • Thresholds bewusst setzen und das Verhalten am 4-Step-Fixture vorhersagen
  • state.json, metrics.jsonl und decisions.jsonl lesen und clm status interpretieren
  • Ein Handoff-Manifest als Übergabe-Artefakt finden und grob einordnen
  • Wissen, wo Compaction verifiziert wird und was verify_fail bedeuten würde

Als Nächstes

Thema Wo
Detaillierte Demo A/B/C + Manifest-Validierung README.md (Demo scenarios)
Pluggable Coding Agents (Grok Build, Registry) coding-agents.md
Komponenten & Datenfluss, Verified Compaction architecture.md
Manifest-Felder & Schema manifest-schema.md
Metrik-Definitionen metrics.md
Resume, Export, Calibrate, Backup, Multi-Agent, Cost, HITL README.md (CLI Quickstart / P2–P4)
Tests / Quality Gate pytest -q bzw. mise run check

Troubleshooting

Symptom Check
clm: command not found Venv aktiv? source .venv/bin/activate und uv pip install -e ".[dev]". Alternativ: uv run clm …
CLM home not found Zuerst clm init --path .clm; bei anderem Home immer denselben --path setzen
Fixture nicht gefunden Vom Repo-Root starten; Pfad tests/fixtures/sample_transcript.json
Python-Fehler / Syntax python --version ≥ 3.12; mit mise: mise install und ggf. frisches mise run install
Session-ID schon vorhanden / verwirrende Artefakte Andere --session-id wählen oder .clm/sessions/<id>/ löschen und neu laufen
resume macht nichts Sinnvolles Session bereits completed / final? Frische ID oder State prüfen (step_index, status)
Unerwarteter verify_fail / Handoff statt Compact Recall unter Threshold; Compact hat Messages nicht mutiert. decisions.jsonl nach verify_fail / recall_score durchsuchen
mise pinnt Python, Shell zeigt weiter 3.14 Shell nicht aktiviert (mise activate) — für Tasks mise run … / mise exec -- … nutzen
.clm/ taucht in git status auf Oft lokal und ok; Sessions/Manifeste nicht committen, außer du willst Demo-Artefakte absichtlich versionieren

Version der Software: siehe pyproject.toml (0.4.0a1). Dieser Guide deckt den Offline-Kernpfad und die Lesbarkeit der Artefakte ab, nicht die vollständige Feature-Oberfläche (P3/P4 Ops, Live-Adapter, Policy-Plugins).