Der Agentenkurs · Der Harness

Harness in der Praxis

Lektion 3/311 Min. LesezeitProfi

Lernziele

  • Du härtest einen Coding-Agenten in fünf Schritten von außen nach innen.
  • Du sortierst Aktionen in die Berechtigungslisten allow, ask und deny.
  • Du prüfst jedes Bauteil deines Harness mit dem Satz „Das gibt es, weil das Modell X nicht kann“.

Die Theorie steht, jetzt härtest du einen echten AgentEin System, in dem ein Sprachmodell seinen nächsten Schritt selbst wählt: Es ruft Werkzeuge auf, wertet das Ergebnis aus und macht weiter, bis das Ziel erreicht ist.Im Glossar. Das durchgehende Beispiel ist ein Coding-Agent für eine Web-Anwendung mit Postgres-Datenbank, der über Claude Code läuft. Jeder Schritt lässt sich auf jeden HarnessAlles, was festlegt, was der Agent erreichen darf: Tools, Berechtigungen, Sandbox, Zeitlimits und die Prüfung, bevor eine Aktion wirkt. Englisch für Geschirr oder Gestell.Im Glossar übertragen, auch auf den eigenen Loop mit siebzig Zeilen aus dem Handbuch Agent-Harnesses. Arbeite die Ringe der Reihe nach ab.

Diese Lektion härtet einen Agenten, den du schon betreibst. Wie du die Maschinerie selbst von Grund auf baust, also den Loop und seine Schutzmechanismen, zeigt das Handbuch.

Schritt eins: Wände bauen

Leg vor dem ersten Prompt fest, was der Agent nicht erreicht. Gib ihm einen Worktree · engl. git worktreeEin zusätzliches Arbeitsverzeichnis desselben Git-Repositorys auf einem eigenen Branch. Ein Agent arbeitet darin, ohne deinen Checkout oder main zu berühren.Im Glossar statt deines Checkouts:

git worktree add ../agent-workspace -b agent/task-one

Dazu kommt ein Datenbanknutzer, der nur lesen darf:

CREATE USER agent_ro WITH PASSWORD 'rotate-me';
GRANT CONNECT ON DATABASE app TO agent_ro;
GRANT USAGE ON SCHEMA public TO agent_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO agent_ro;
-- auch Tabellen, die später entstehen
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO agent_ro;

Wir haben die Rolle in PostgreSQL 16 getestet. agent_ro liest alle Tabellen, DELETE und DROP TABLE scheitern mit „permission denied“. Die letzte Zeile haben wir ergänzt: Ohne sie bleibt jede Tabelle unlesbar, die nach dem GRANT angelegt wird. Sie gilt für Tabellen, die der Nutzer anlegt, der die Zeile ausführt, in der Regel also der Eigentümer der Migrationen.

Muss der Agent Pakete installieren oder APIs aufrufen, läuft er in einem Container mit Netzwerk-Allowlist: deine Paket-Registry und die API des Modells, sonst nichts. Der Test für diesen Schritt geht so: Stell dir die schlimmste mögliche Session vor und prüf, ob der Schaden auf einen gelöschten Worktree begrenzt bleibt.

Schritt zwei: Leitplanken schreiben

Leg eine AGENTS.mdEine Textdatei im Wurzelverzeichnis eines Repositorys mit kurzen Regeln für Coding-Agenten: Aufbau, Testbefehl, Verbote. Der Agent liest sie zu Beginn jeder Session.Im Glossar ins Wurzelverzeichnis des Repositorys. Sie muss kurz genug sein, dass der Agent sie in jeder Session liest:

- App code in src/, tests in tests/, run everything from the repo root.
- `make check` must pass before you call any task done.
- Never hand-edit files in migrations/ — generate them with `make migration`.
- Your database user is read-only. Ask before proposing any schema change.

Jede Zeile nennt eine Regel, nach der der Agent handeln kann. Philosophie und Vorgeschichte haben darin keinen Platz.

Schritt drei: Sensoren verdrahten

Fass die mechanischen Prüfungen in einem Befehl zusammen:

check:
	ruff check .
	mypy src
	pytest -q

Dann lässt du den Harness diesen Befehl nach jeder Änderung ausführen, ohne dass das Modell · engl. model, LLMDas Sprachmodell (LLM, Large Language Model). Es liest Text, schreibt Text und entscheidet in einem Agenten, was als Nächstes passiert.Im Glossar daran denken muss. Das erledigt ein PostToolUse-HookEin Befehl, den der Harness bei einem festen Ereignis automatisch ausführt, etwa vor oder nach jedem Tool-Aufruf. Ein Hook vor dem Aufruf kann ihn blockieren und dem Modell den Grund melden.Im Glossar, der nach jedem Edit und Write läuft:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "make check 1>&2" }
        ]
      }
    ]
  }
}

Das 1>&2 am Ende ist wichtig. Gibt ein PostToolUse-Hook reinen Text aus, sieht das Modell nur die Ausgabe auf stderr, und auch die nur, wenn der Hook mit Code 2 endet. make endet bei einem Fehler mit Code 2, die Bedingung ist also erfüllt. pytest und ruff schreiben ihre Befunde aber auf stdout. In unserem Test mit Claude Code 2.1.322 sah das Modell ohne Umleitung nur make: *** [check] Error 1 und keinen Hinweis, welcher Test gescheitert war. Mit 1>&2 kam die vollständige Meldung an.

So landen Fehler sofort im Verlauf, solange der Fehler erst eine Änderung alt ist.

Schritt vier: Berechtigungen kürzen

Gib dem Agenten zuerst nur die Rechte, die er braucht, und frag danach nur noch beim Unumkehrbaren nach:

{
  "permissions": {
    "allow": ["Read", "Grep", "Glob", "Bash(make check)", "Bash(git diff:*)", "Bash(git status)"],
    "ask": ["Bash(git commit:*)", "Bash(git push:*)"],
    "deny": ["WebFetch", "Bash(rm:*)"]
  }
}

Claude Code prüft die Regeln in einer festen Reihenfolge: erst deny, dann ask, dann allow. Die erste passende Liste entscheidet. Ein :* am Ende steht für jede Fortsetzung des Befehls. Eine Deny-Regel wie Bash(rm:*) greift laut Dokumentation nicht, wenn das Programm über seinen Pfad oder innerhalb von sh -c aufgerufen wird. Die harte Grenze bleibt deshalb Ring eins.

Menschen bestätigen fast jede Abfrage, die sie sehen. Nur eine kurze ask-Liste wird deshalb gelesen. Bestätigst du etwas jeden Tag, ohne nachzudenken, gehört es nach allow. Noch besser machst du die Aktion unmöglich und streichst die Abfrage.

allow, ask oder deny?

Sortiere jede Aktion des Coding-Agenten in die Liste, in die sie bei diesem Projekt gehört.

Noch offen (7)

  • Dateien im Repository lesen und durchsuchen
  • make check ausführen
  • git diff ansehen
  • git commit
  • git push
  • Webseiten abrufen
  • rm mit beliebigen Pfaden

allow: läuft ohne Frage (0)

    ask: nur mit Freigabe (0)

      deny: nie (0)

        Schritt fünf: einen Hook setzen

        Nimm die Regel aus der AGENTS.md, deren Verletzung am meisten schmerzt, und setz sie durch:

        {
          "hooks": {
            "PreToolUse": [
              {
                "matcher": "Edit|Write",
                "hooks": [
                  {
                    "type": "command",
                    "command": "jq -r '.tool_input.file_path' | grep -q 'migrations/' && { echo 'Blocked: generate migrations with make migration' >&2; exit 2; } || exit 0"
                  }
                ]
              }
            ]
          }
        }

        Der Hook liest den Dateipfad des geplanten Aufrufs. Liegt die Datei unter migrations/, blockiert er die Änderung mit Code 2 und nennt den richtigen Weg. Wir haben den Befehl mit einem Pfad unter migrations/ (blockiert) und einem unter src/ (durchgelassen) geprüft. Ein gut gewählter Hook bringt mehr als zehn, die ständig auslösen.

        Die Quartalsprüfung

        Jedes Bauteil im Harness ist eine Wette darauf, dass das Modell etwas nicht kann, und diese Wetten laufen ab. Anthropic strich ein ganzes Bauteil, die Kontext-Resets gegen vorzeitiges Abschließen, nachdem ein neues Modell es überflüssig gemacht hatte.

        Trag dir deshalb einen festen Termin pro Quartal ein. Schreib für jeden Hook, jede Zeile der Leitplanken und jede verweigerte Berechtigung den Satz auf: „Das gibt es, weil das Modell X nicht kann.“ Dann testest du X mit dem aktuellen Modell. Was sich nicht mehr lohnt, löschst du. Ein Harness, der nur wächst, gleicht ein Modell aus, das es nicht mehr gibt.

        Tipps

        • Neue Regeln erst nach dem zweiten Fehler. Schreib eine Regel erst in die AGENTS.md, wenn der Agent dasselbe zweimal falsch macht. Regeln auf Verdacht veralten.
        • Logge blockierte Hooks. Ein Hook, der nie auslöst, ist bei der nächsten Quartalsprüfung ein Kandidat zum Löschen.
        • Tool-Beschreibungen sind Leitplanken. Lies die Hinweise zu Tools und MCP · engl. Model Context ProtocolEin offenes Protokoll, über das ein Agent Tools aus externen Servern einbindet, etwa für GitHub, Slack oder eine Datenbank. Jeder Server bringt eigene Tool-Definitionen mit.Im Glossar im Handbuch Agent-Harnesses, bevor du ein Tool hinzufügst.

        Probier es selbst aus

        Drei Experimente zeigen dir, was dein Harness wirklich leistet. Arbeite sie mit deinem eigenen Agenten ab.

        Selbst nachweisen

        0 von 3 erledigt

        Sensoren verdienen ein eigenes Modul. Weiter geht es mit Evals. Wer die Maschinerie tiefer verstehen will, findet im Handbuch Agent-Harnesses die Landschaft der Harnesses und einen funktionierenden Harness in rund 190 Zeilen.

        Merksätze

        • Du härtest in fünf Schritten: Wände, Leitplanken, Sensoren, Berechtigungen, ein einzelner Hook.
        • Worktree und Datenbank-Rolle mit reinen Leserechten begrenzen den Schaden der schlimmsten Session auf einen gelöschten Worktree.
        • Ein PostToolUse-Hook führt die Prüfungen nach jeder Änderung aus, und mit 1>&2 sieht das Modell auch, was gescheitert ist.
        • Die ask-Liste bleibt kurz und enthält nur Unumkehrbares, alles andere ist erlaubt oder unmöglich.
        • Jedes Quartal prüfst du jedes Bauteil gegen das aktuelle Modell und löschst, was sich nicht mehr lohnt.

        Prüf dich selbst

        Denkfrage

        Dein PostToolUse-Hook führt pytest direkt aus, und das Modell reagiert nie auf fehlschlagende Tests. Woran liegt das?

        Denkfrage

        Du bestätigst jeden Tag zwanzigmal `git commit` im Worktree des Agenten, ohne hinzusehen. Was änderst du?

        Prüf dich selbst

        1. 1Was ist der Test für Schritt eins, die Wände?
        2. 2Eine Aktion steht in allow und passt zugleich auf eine Regel in ask. Was passiert in Claude Code?
        3. 3Warum endet der Sensor-Hook in dieser Lektion auf `1>&2`?
        4. 4Wann schreibst du eine neue Regel in die AGENTS.md?

        Quellen

        1. Configure permissions · Anthropic, Stand: Nov. 2026

          allow, ask, deny, Reihenfolge der Prüfung, Syntax mit :* und Grenzen von Bash-Regeln.

        2. Hooks reference · Anthropic, Stand: Nov. 2026

          PreToolUse und PostToolUse, Exit-Code 2, stderr als Rückmeldung an Claude.

        3. PostgreSQL: ALTER DEFAULT PRIVILEGES · PostgreSQL Global Development Group, Stand: Nov. 2026

          Rechte für Tabellen, die später angelegt werden.

        Dein Fortschritt bleibt nur in diesem Browser gespeichert.