How to Build an AI Agent
How to Build an AI Agent
s12

Worktree + Aufgaben-Isolation

Zusammenarbeit

Isolate by Directory

694 LOC16 ToolsComposable worktree lifecycle + event stream over a shared task board
Each works in its own directory; tasks manage goals, worktrees manage directories, bound by ID

s01 > s02 > s03 > s04 > s05 > s06 | s07 > s08 > s09 > s10 > s11 > [ s12 ]

"Jeder arbeitet in seinem eigenen Verzeichnis, keine Interferenzen" -- Aufgaben verwalten Ziele, Worktrees verwalten Verzeichnisse, verbunden durch ID.

Problem

Bis s11 können Agenten Aufgaben autonom beanspruchen und abschließen. Aber jede Aufgabe läuft in einem gemeinsamen Verzeichnis. Zwei Agenten, die gleichzeitig verschiedene Module refaktorisieren, kollidieren: Agent A bearbeitet config.py, Agent B bearbeitet config.py, nicht bereitgestellte Änderungen vermischen sich, und keiner kann sauber zurückrollen.

Die Aufgabenwand verfolgt was zu tun ist, aber hat keine Meinung darüber wo es zu tun ist. Die Lösung: Geben Sie jeder Aufgabe ihr eigenes Git-Worktree-Verzeichnis. Aufgaben verwalten Ziele, Worktrees verwalten Ausführungskontext. Verbinden Sie sie durch Aufgaben-ID.

Lösung

Kontrollebene (.tasks/)              Ausführungsebene (.worktrees/)
+------------------+                +------------------------+
| task_1.json      |                | auth-refactor/         |
|   status: in_progress  <------>   branch: wt/auth-refactor
|   worktree: "auth-refactor"   |   task_id: 1             |
+------------------+                +------------------------+
| task_2.json      |                | ui-login/              |
|   status: pending    <------>     branch: wt/ui-login
|   worktree: "ui-login"       |   task_id: 2             |
+------------------+                +------------------------+
                                    |
                          index.json (Worktree-Registrierung)
                          events.jsonl (Lebenszyklus-Protokoll)

Zustandsautomaten:
  Aufgabe:     pending -> in_progress -> completed
  Worktree:    absent  -> active      -> removed | kept

Wie es funktioniert

  1. Aufgabe erstellen. Ziel zuerst persistieren.
TASKS.create("Implement auth refactor")
# -> .tasks/task_1.json  status=pending  worktree=""
  1. Worktree erstellen und an Aufgabe binden. Das Übergeben von task_id bringt die Aufgabe automatisch auf in_progress.
WORKTREES.create("auth-refactor", task_id=1)
# -> git worktree add -b wt/auth-refactor .worktrees/auth-refactor HEAD
# -> index.json erhält neuen Eintrag, task_1.json erhält worktree="auth-refactor"

Die Bindung schreibt Status auf beide Seiten:

def bind_worktree(self, task_id, worktree):
    task = self._load(task_id)
    task["worktree"] = worktree
    if task["status"] == "pending":
        task["status"] = "in_progress"
    self._save(task)
  1. Befehle im Worktree ausführen. cwd zeigt auf das isolierte Verzeichnis.
subprocess.run(command, shell=True, cwd=worktree_path,
               capture_output=True, text=True, timeout=300)
  1. Abschließen. Zwei Möglichkeiten:
    • worktree_keep(name) -- Verzeichnis für später aufbewahren.
    • worktree_remove(name, complete_task=True) -- Verzeichnis entfernen, gebundene Aufgabe abschließen, Event emitieren. Ein Aufruf erledigt both Aufräumen und Abschluss.
def remove(self, name, force=False, complete_task=False):
    self._run_git(["worktree", "remove", wt["path"]])
    if complete_task and wt.get("task_id") is not None:
        self.tasks.update(wt["task_id"], status="completed")
        self.tasks.unbind_worktree(wt["task_id"])
        self.events.emit("task.completed", ...)
  1. Event-Stream. Jeder Lebenszyklus-Schritt emitet zu .worktrees/events.jsonl:
{
  "event": "worktree.remove.after",
  "task": { "id": 1, "status": "completed" },
  "worktree": { "name": "auth-refactor", "status": "removed" },
  "ts": 1730000000
}

Events die emitet werden: worktree.create.before/after/failed, worktree.remove.before/after/failed, worktree.keep, task.completed.

Nach einem Absturz rekonstruiert sich der Status von .tasks/ + .worktrees/index.json auf Disk. Konversationsgedächtnis ist flüchtig; Dateistatus ist dauerhaft.

Was sich von s11 geändert hat

KomponenteVorher (s11)Nachher (s12)
KoordinationAufgabenwand (owner/status)Aufgabenwand + explizite Worktree-Bindung
AusführungsumfangGemeinsames VerzeichnisAufgaben-bezogenes isoliertes Verzeichnis
WiederherstellbarNur AufgabenstatusAufgabenstatus + Worktree-Index
AufräumenAufgabenabschlussAufgabenabschluss + explizites Keep/Remove
Lebenszyklus-SichtbarkeitImplizit in LogsExplizite Events in .worktrees/events.jsonl

Ausprobieren

python agents/s12_worktree_task_isolation.py
  1. Erstelle Aufgaben für Backend-Auth und Frontend-Login-Seite, dann liste Aufgaben auf.
  2. Erstelle Worktree "auth-refactor" für Aufgabe 1, dann binde Aufgabe 2 an neuen Worktree "ui-login".
  3. Führe "git status --short" in Worktree "auth-refactor" aus.
  4. Behalte Worktree "ui-login", dann liste Worktrees auf und inspiziere Events.
  5. Entferne Worktree "auth-refactor" mit complete_task=true, dann liste Aufgaben/Worktrees/Events auf.