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.
21 KiB
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).
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):
- Externe Phasengrenze (z. B. nach
clm signal --phase-done) und Policy „lieber handoff“ → HANDOFF - Tokens ≥ hard → HANDOFF (
trigger=hard_handoff) - Tokens ≥ soft (und genug Steps seit letztem Compact) → COMPACT (
trigger=soft_compact) - 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) uvempfohlen (schnell, Lockfileuv.lockim Repo)- Alternativ:
python -m venv .venv+pip install -e ".[dev]"
- Alternativ:
- Git-Checkout dieses Repos
- Optional: mise — pinnt Tool-Versionen laut
mise.toml(Python/uv). Kein Ersatz füruvbeim 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 übermise 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:
statuszeigt vier Metric-Zeilen und vier Decisions- in
decisions.jsonlnur"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
clm status— schneller Überblick ohne JSON-Parsingdecisions.jsonl— warum CONTINUE/COMPACT/HANDOFFmetrics.jsonl— Token-Verlauf pro Stepstate.json— voller Stand (Messages, Artefakt-Listen)- 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:
- Decision
action=compact,trigger=soft_compact, Rationale mittokens.total_tokens (…) >= soft_compact (1000) - Event
compaction_verifymittrigger=verify_ok,recall_score=1.0
Was passiert bei COMPACT?
- Strukturierte Summary aus dem Session-State (Offline: ohne LLM)
- Snapshot ins Memory (Key u. a. unter Session/Compact-Step)
- Compact-Hint (Markdown): Goal, Constraints, Next action, Memory-Keys, Verified/Not verified
- Verified Compaction: deterministische Recall-Fragen gegen Summary+Hint (Goal, Verified, Constraints, Blockers). Default-Schwellwert
recall_score_threshold ≈ 0.8 - Nur bei Verify-OK: Messages werden ersetzt (System-Hint + recent retain) — Context schrumpft
- 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.jsonlunddecisions.jsonllesen undclm statusinterpretieren- Ein Handoff-Manifest als Übergabe-Artefakt finden und grob einordnen
- Wissen, wo Compaction verifiziert wird und was
verify_failbedeuten 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).
