45 Agent-Watcher
frank edited this page 2026-07-21 13:21:34 +02:00
This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Agent Watcher

forge agent watch pollt Forgejo-Issues und übergibt Treffer an lokale Coding-Agent-CLIs (cursor-agent, codex, pi, opencode, claude).

Agent-Dashboard (TUI)

In einem interaktiven Terminal startet forge agent watch standardmäßig das Agent-Dashboard. Es zeigt Repositories, Queue, laufende und blockierte Issues, Limits und offene Agent-PRs. Mit Enter oder 19 öffnet man die Output-Ansicht eines Runs; n / p / Tab wechseln zwischen parallelen Runs; d oder Esc kehren zum Dashboard zurück.

c öffnet die Agent-Konfiguration (wie forge agent config) direkt im laufenden Dashboard; nach dem Speichern gelten die Werte sofort für den Watcher (Persistenz in die Workspace- bzw. Projekt-agent.yaml). a startet einen kurzen Dialog zum Hinzufügen eines Repositories per HTTPS-URL (z.B. https://repository.hildebrandt.io/frank/forgecli.git): Eintrag in die Config, Bare-Clone und Aufnahme in den Poll ohne Neustart. Im URL-Feld funktioniert normales Terminal-Paste (Ctrl/Cmd+V bzw. Bracketed Paste).

Am unteren Rand zeigt ein Activity-Log-Drawer Orchestrierungs-Events chronologisch (Agent start/stop/fail/done, Worktree anlegen/entfernen, Issue claim/label, …). Jede Zeile kann ein Task-Kind-Präfix tragen (siehe unten). Standardmäßig ist der Drawer aufgeklappt und nimmt etwa ein Drittel der Terminalhöhe ein; l klappt ihn zu/auf, f filtert nach Kategorie (Agent / Worktree / Issue), [/] scrollt in der Historie. Das Web-Dashboard (--ui) zeigt dieselben Events in einem einklappbaren Panel.

Task Kinds (Aufgabenarten)

Laufende und geloggte Jobs tragen ein stabiles Task Kind (task_kind in JSON) plus menschenlesbares Label in TUI, Web-UI, Activity-Log und Plain-Logs (--no-tui):

Kind-ID Label Bedeutung
coding Agent Coding Neues Issue / Implementierung im Coding-Agent
verify Verifying Implementation Nach Coding: Vollständigkeit gegen Issue prüfen (max. verify_attempts)
fix_build Fixing Build CI fehlgeschlagen → Repair am bestehenden PR/Worktree
resolve_conflicts Resolving Conflicts Merge-Konflikte am PR beheben
mention Mention Follow-up PR-Kommentar mit @mention eines überwachten Logins als Follow-up

Weitere Kinds lassen sich intern ergänzen; UI und Log-Formatierung nutzen TaskKindLabel. Die Detail-Activity (coding agent is working, babysitting PR #…, …) bleibt ergänzend sichtbar.

Für jeden laufenden Job zeigt das Dashboard die aktuelle Pipeline-Phase an, etwa Agent-Ausführung, WIP-PR-Eröffnung, Commit/Push, CI-Babysitting, Reparatur oder Abschluss. Wartet der Job, werden der konkrete Grund und der Zeitpunkt der nächsten Prüfung angezeigt. Der Repository-Poll läuft standardmäßig alle zehn Sekunden; während eine synchrone Pipeline aktiv ist, weist das Dashboard ausdrücklich darauf hin, dass der nächste Repository-Poll nach deren Abschluss folgt. Das CI-Babysitting prüft weiterhin mit --ci-interval (standardmäßig fünf Sekunden).

--no-tui schaltet auf Plain-Logs um. --ui startet stattdessen ein lokales Web-Dashboard (gegenseitig ausschließend mit der TUI).

ACP-Jobende

Ein ACP-Lauf endet regulär mit der Antwort auf session/prompt. Schließt ein Agent stattdessen die Verbindung oder lässt sie nach seiner letzten Antwort offen, wertet forge den Lauf nur dann als erfolgreich, wenn eine Agent-Antwort vorliegt, alle Tool-Aufrufe einen terminalen Status erreicht haben, kein Plan-Eintrag mehr in_progress/pending/active ist und ausstehende Updates verarbeitet wurden. Client-seitige FS-/Permission-RPCs (fs/read_text_file, fs/write_text_file, session/request_permission) zählen als Aktivität und verhindern einen vorzeitigen Abschluss. Bei offener Verbindung ohne Prompt-Antwort greift dieselbe Prüfung erst nach zwei Minuten ohne weitere Aktivität als Hang-Watchdog (nicht nach wenigen Sekunden Denkpause). Reine Tool-, Plan- oder Thought-Aktivität genügt nicht als erfolgreicher Abschluss. Der erkannte Abschlussgrund erscheint im Run-Log beziehungsweise im Agent-Dashboard.

Codex ACP

Für codex startet forge den Adapter codex-acp bzw. npx -y @agentclientprotocol/codex-acp. Authentifizierung:

  • Mit gesetztem CODEX_API_KEY oder OPENAI_API_KEY wird die Methode api-key genutzt.
  • Sonst chat-gpt (bestehender Codex-/ChatGPT-Login), oder Auth wird übersprungen, wenn session/new ohnehin funktioniert.
  • Schlägt der ACP-Start fehl (initialize / session/new / Prozessstart), fällt forge auf codex exec zurück (acp fallback: …). Fehler mitten im Prompt starten keinen zweiten Raw-Lauf.

Headless setzt forge NO_BROWSER=1 und INITIAL_AGENT_MODE=agent, sofern diese Variablen nicht schon gesetzt sind. Adapter-stderr erscheint mit Präfix acp: im Run-Log.

Konfigurationsdatei

Einstellungen können in folgenden Dateien liegen:

  1. ./agent.yaml im Workspace-Modus (Start außerhalb eines Git-Repos, höchste Datei-Priorität)
  2. ./.forge/agent.yaml (Projekt innerhalb eines Repos)
  3. ~/.config/forge/agent.yaml

Mit --config /pfad/zur/agent.yaml lässt sich ein anderer Pfad wählen (unabhängig vom Workspace-Modus).

Precedence: CLI-Flags > Umgebung > agent.yaml > Defaults.

Workspace-Modus (außerhalb eines Repos)

Wird forge agent watch in einem Verzeichnis gestartet, das kein Git-Repository ist, gilt dieses Verzeichnis als Agent-Workspace:

  • agent.yaml liegt direkt im Workspace-Root (nicht unter .forge/)
  • Bare-Repos werden standardmäßig unter dem Workspace angelegt (owner/repo.git), nicht unter ~/.config/forge/repos/
  • repo_cache_dir in der Config oder --config überschreiben das wie gewohnt

Beispiel:

mkdir -p ~/agent-ws && cd ~/agent-ws
forge agent config    # legt ~/agent-ws/agent.yaml an
forge agent watch     # nutzt dieselbe Datei; Bare-Caches unter ~/agent-ws/…

Innerhalb eines Git-Repos bleibt das bisherige Verhalten (./.forge/agent.yaml, globaler Default-Cache) erhalten.

Config-Mode (TUI)

forge agent config öffnet im aktuellen Verzeichnis eine interaktive TUI zum Anlegen und Bearbeiten der lokalen agent.yaml — ohne manuelles YAML-Editieren (Projekt: ./.forge/agent.yaml, Workspace: ./agent.yaml).

forge agent config --print liest dieselbe Config-Suchreihenfolge wie watch/run, füllt eingebaute Defaults auf (Labels, Intervalle, agent_mapping, Codex-Harness-Tasks, Prompt-Templates, …) und schreibt die effektive Config als YAML nach stdout (kein TTY nötig). Mit --config /pfad lässt sich eine konkrete Datei wählen.

  • Lädt vorhandene Config beim Start
  • Repositories hinzufügen, bearbeiten, entfernen (optional Vorschlag aus git remote origin); Textfelder akzeptieren Paste
  • Limits (parallel.max, parallel.per_repo, max_open_prs, per-Repo-Overrides)
  • Alle relevanten Agent-Optionen: agent, model, git_mode, Trigger, Labels, CI/Babysit, interval, agent_user, agent_mapping, Harness-Tasks (agents.*), Prompt-Templates (prompts.*), impersonate, pre_prompt, repo_cache_dir, …
  • Speichern mit Bestätigung (überschreibt die Projekt-Datei); Zielpfad wird angezeigt
  • Danach starten forge agent watch / forge agent run mit den gespeicherten Werten ohne wiederholte Flags

Tasten (Auszug): ↑↓ navigieren, Enter bearbeiten, ←→ / Leertaste bei Auswahlfeldern, a/e/d in der Repo-Liste, q beenden.

Beispiel:

interval: 10s
agent: cursor-agent
model: ""
git_mode: pr          # commit | pr
trigger:
  label: agent        # genau einer: user | label | project

parallel:
  max: 3
  per_repo: 1
max_open_prs: 2

# Watch every repository the authenticated user can access (merged with repos: overrides).
all_repos: false

repos:
  - owner: frank
    name: forgecli
    # Bare mode (default): omit path — forge clones bare to ~/.config/forge/repos/owner/repo.git
  - url: https://repository.hildebrandt.io/frank/forgecli.git
  - owner: frank
    name: legacy-app
    path: ~/src/legacy-app   # optional legacy checkout
    max_parallel: 1
    max_open_prs: 2

# Optional override for bare-repo cache root (default: ~/.config/forge/repos)
repo_cache_dir: ~/.config/forge/repos

# How often watch fetches origin and refreshes the default branch (default: 1m)
repo_sync_interval: 1m

working_label: agent:working
ready_label: agent:ready
done_label: agent:done
babysit_attempts: 3
verify_attempts: 3

# Optional per-harness task profiles (model / reasoning / pre_prompt).
# Codex defaults when unset: code→gpt-5.6-sol; fix_build/resolve_conflicts/mention/verify→gpt-5.6-terra
# with escalate to gpt-5.6-sol after 2 failed fixes for fix_build and resolve_conflicts.
agents:
  codex:
    code:
      model: gpt-5.6-sol
      reasoning: high
      labels:
        - label: agent:deep
          reasoning: xhigh
    fix_build:
      model: gpt-5.6-terra
      reasoning: medium
      escalate_after: 2
      escalate:
        model: gpt-5.6-sol
        reasoning: high
    verify:
      model: gpt-5.6-terra

Harness-Tasks (agents)

Unter agents.<harness> lassen sich pro Coding-Agent und pro Aufgabenart Modell, Reasoning und Pre-Prompt setzen:

YAML-Key Task Kind Verwendung
code coding Issue-Implementierung
verify verify Post-Coding-Vollständigkeitscheck
fix_build fix_build CI-Repair (Babysit / Watch)
resolve_conflicts resolve_conflicts Merge-Konflikt-Repair
mention mention PR-@mention Follow-up

Felder je Task: model, reasoning, pre_prompt, optional escalate_after + escalate.{model,reasoning,pre_prompt}.

  • Escalation: wenn fixAttempt > escalate_after, gelten die escalate.*-Werte (leere Escalate-Felder erben vom Task).
  • code.labels: Liste von Modifiern; erste passende Issue-Label (case-insensitive) überschreibt Model/Reasoning und hängt pre_prompt an.
  • Pre-Prompt-Compose: globales pre_prompt + Task-pre_prompt (+ Label-pre_prompt) mit \n\n.
  • CLI --model überschreibt nur das Modell für alle Tasks; Reasoning/PrePrompt bleiben aus dem Harness-Profil.
  • Codex-Defaults (wenn Felder leer): codegpt-5.6-sol; fix_build / resolve_conflicts / mention / verifygpt-5.6-terra; bei fix_build und resolve_conflicts Escalation nach 2 Fixes → gpt-5.6-sol.
  • Reasoning wird für Codex als -c model_reasoning_effort=… (raw CLI) bzw. best-effort ACP-Session-Config gesetzt.
  • Bearbeitbar in forge agent config unter Harness tasks (agents.*).

Prompt-Templates (prompts)

Die festen Prompt-Bodies pro Aufgabenart sind als Go text/template in agent.yaml überschreibbar. Leer = eingebauter Default. forge agent config --print zeigt die effektiven Templates inkl. Platzhalter.

prompts:
  code: |
    {{if .PrePrompt}}{{.PrePrompt}}

    {{end}}## Forgejo issue to implement
    ...
  verify: |
    ## Verify implementation completeness
    ...
  fix_build: |
    ## Fix failing CI for this pull request
    ...
  resolve_conflicts: |
    ## Resolve merge conflicts for this pull request
    ...
  mention: |
    ## Respond to a pull request mention
    ...
YAML-Key Task Wichtige Felder im Template
code Issue-Implementierung .PrePrompt, .Number, .Title, .HTMLURL, .Labels, .GitMode, .IsPR, .Body, .Todos, .WorkingLabel, .ProgressCommentStyle, .IncrementalGit
verify Post-Coding-Check .PrePrompt, .Number, .Title, .HTMLURL, .Labels, .GitMode, .IsPR, .Body, .Todos, .WorkingLabel, .ProgressCommentStyle, .IncrementalGit
fix_build CI-Repair .Number, .Title, .PRNumber, .Failure, .Todos, .ProgressCommentStyle, .IncrementalGit
resolve_conflicts Merge-Konflikt-Repair .Number, .Title, .PRNumber, .BaseBranch, .Detail, .Todos, .ProgressCommentStyle, .IncrementalGit
mention PR-@mention Follow-up .Number, .Title, .PRNumber, .MentionedLogin, .CommentAuthor, .CommentID, .CommentBody, .Todos, .ProgressCommentStyle, .IncrementalGit
  • pre_prompt (global / Harness) wird zusätzlich vor den gerenderten Body gehängt (beim Coding-Task auch als .PrePrompt im Template verfügbar).
  • Ungültige Templates erzeugen einen Fehler-Prompt statt eines Agent-Laufs mit leerem Text.
  • Bearbeitbar in forge agent config unter Prompt templates (prompts.*); für lange Texte ist YAML bzw. --print oft praktischer als die TUI-Zeile.

Mention-Mapping (agent_mapping)

Im PR-Modus (git_mode: pr) überwacht forge agent watch offene Pull Requests auf unbeantwortete @mentions. Standardmäßig gilt ein agent_user (Default: authentifizierter Config-Username) plus der stabile Alias @agent.

Mit agent_mapping lassen sich mehrere Forgejo-Logins gleichzeitig überwachen und jeweils einem Coding-Agent zuordnen:

agent_user: frank          # eigener Login; wird zusätzlich überwacht, falls nicht schon ein Mapping-Key

agent_mapping:
  agent: default           # @agent → globaler Agent aus agent: / --agent
  codex: codex
  cursor: cursor-agent
  claude: claude
  pi: pi
  • default bedeutet: denselben Agent nutzen wie die globale agent-Einstellung.
  • Alle Keys im Mapping werden auf @mentions geprüft; agent_user wird ergänzt, wenn er nicht bereits als Key vorkommt.
  • Bei User-Trigger (trigger.user / --user) matcht der Watcher zusätzlich Issues, die einem Mapping-Login zugewiesen sind (z.B. Assignee codex bei trigger.user: agent).
  • Mentions ohne Mapping-Eintrag werden ignoriert (wie bisher bei fremden Usern).
  • Bei @codex … startet der Watcher den gemappten Runner (codex) in derselben Worktree-Session, wenn möglich.
  • Bearbeitete Mentions werden mit 👀 markiert und danach nicht erneut eingeplant — unabhängig davon, welcher Login die Reaction gesetzt hat (Impersonation vs. Token-User).
  • Bearbeitbar in agent.yaml und per forge agent config (TUI-Menü Mention mapping).

User-Impersonierung (impersonate)

Damit Agent-Aktionen (Kommentare, Reactions, Labels, PRs) und forge-eigene Commits als der angesprochene bzw. zugewiesene Agent-User erscheinen, gibt es Admin-Impersonierung über die Forgejo-Sudo-API:

impersonate: true
agent_user: agent          # Fallback, wenn kein Mapping-Assignee/Mention greift
agent_mapping:
  cursor: cursor-agent
  codex: codex

Oder per Flag: forge agent watch --impersonate …

Verhalten:

  1. Der authentifizierte Token muss Site-Admin sein (OAuth-Apps können fremde User nicht impersonieren).
  2. Beim Start wird Admin + Fallback-agent_user per Sudo validiert.
  3. Pro Job gilt: @cursor-Mention oder Assignee cursorSudo: cursor; analog für codex, claude, … Ohne Mapping-Treffer → Fallback agent_user.
  4. Der Coding-Agent kommt aus agent_mapping für denselben Login (Assignee/Mention).
  5. Existierende Logins aus agent_user + agent_mapping erhalten auf allen watched Repos automatisch Collaborator-Recht write (fehlende Accounts werden übersprungen, nicht angelegt).
  6. GIT_AUTHOR_* / GIT_COMMITTER_* werden aus dem Job-Ziel-User gesetzt.

Out of scope: Auto-Create von Forgejo-Accounts, Rechterücknahme beim Entfernen aus dem Mapping.

Limits

Einstellung Flag Bedeutung
parallel.max --parallel Max. gleichzeitige Pipelines global
parallel.per_repo --parallel-per-repo Max. gleichzeitige Pipelines pro Repository
max_open_prs --max-open-prs Max. offene Agent-PRs, bevor neue Issue-Runs warten
repos[].max_parallel Per-Repo-Override für Parallelität
repos[].max_open_prs Per-Repo-Override für offene PRs

max_open_prs ist ausschließlich ein Gate für neue Issue-Pipelines, die einen weiteren PR erzeugen könnten. Bereits offene PRs werden auch bei erreichtem oder überschrittenem Limit weiter gebabysittet; CI-Fehler, Mentions und Merge-Konflikte bleiben reparaturberechtigt und werden vor neuen Issues eingeplant. Parallelitätslimits gelten weiterhin.

Issues ohne freien Slot bleiben in der internen Queue (Dashboard: queued) und erhalten kein agent:*-Label. Laufende Pipelines und noch nicht sichtbare WIP-PRs reservieren ihre Slots beim Dispatch; ein erneuter Limit-Check vor dem Claim verhindert vorzeitiges agent:ready bei überbuchten Slots.

Beim Babysitting ordnet forge einen Actions-Run über den Branch oder den exakten gepushten Commit-SHA zu. Das ist für Forgejo-PR-Workflows erforderlich, weil deren Runs häufig prettyref: "#<pr>" statt des Quell-Branches und den Commit nur als commit_sha liefern.

Erscheint innerhalb von zwei Minuten (bzw. ci_timeout, falls kürzer) kein Actions-Run, oder der Run hat keine Build-Jobs, überspringt forge das Babysitting und schließt den PR-Lauf normal ab (agent:ready) — ohne den Coding-Agenten erneut zu starten.

--commit-Modus: aktueller Branch

Im Git-Modus --commit (bzw. git_mode: commit) gilt:

  1. Arbeitsverzeichnis ist der bestehende Checkout (repos[].path oder aktuelles Working Tree). Es werden keine Agent-Worktrees und keine Agent-Branches angelegt.
  2. Branch bleibt unverändert: forge wechselt den Checkout nicht (Health-Sync nur fetch, kein checkout/pull der Default-Branch). Der Coding-Agent darf den Branch weder wechseln noch neu anlegen; Verstöße werden erkannt und der Checkout zurückgesetzt.
  3. Parallelität ist fest 1: parallel.max, parallel.per_repo, --parallel und Repo-Overrides werden auf 1 geklemmt. Es läuft immer nur ein Job.
  4. Keine Pull Requests: Es werden keine PRs benötigt oder erzeugt. forge öffnet, aktualisiert oder babysittet keine PRs; der Coding-Agent soll auch keine anlegen. max_open_prs wird ignoriert.
  5. Publish: Dirty-Änderungen werden commitet und mit normalem git push (ohne Force) auf dem aktuellen Branch veröffentlicht.
  6. Abschluss: Während des Laufs fasst forge ACP-Chat-Abschnitte zusammen und postet sie als lesbare Issue-Kommentare (kein PR). Nach erfolgreichem Publish folgt der Agent usage-Block am Issue; Labels wechseln direkt zu agent:done (kein agent:ready-Zwischenzustand wie im PR-Modus). Das Issue wird geschlossen (auch ohne --close / close: true).
  7. Bare-Cache ist in diesem Modus nicht erlaubt — ohne Working Tree fehlt der „aktuelle Branch“. Für bare-only-Setups --pr nutzen oder repos[].path auf einen Checkout setzen.

Beispiel:

git_mode: commit
# parallel wird auf 1 geklemmt, auch wenn hier höher steht
parallel:
  max: 1
repos:
  - owner: frank
    name: forgecli
    path: ~/src/forgecli
forge agent watch --label agent --agent cursor-agent --commit

--pr-Modus: WIP-PR und Fortschritt

Im Git-Modus --pr (bzw. git_mode: pr) gilt:

  1. Claim/Start bleibt am Issue (Kommentar, Working-Label, optional Projekt-Spalte).
  2. Sofort nach Worktree-Anlage force-pusht forge den Branch und öffnet einen Pull Request mit Titel WIP: #<issue> <titel> und einer Kurzbeschreibung der Aufgabe.
  3. Während des Haupt-Agent-Laufs fasst forge zusammenhängende ACP-Chat-Abschnitte zwischen Tool-Calls zusammen und postet sie als lesbare PR-Kommentare (keine Roh-Tool-Dumps). Die Default-Prompts fordern den Coding-Agenten auf, Intent/Fortschritt nur im Stil kurzer PR-Arbeitskommentare zu formulieren (technisch, ohne Chat-Fülltext).
  4. Nach erfolgreichem Agent-Lauf committe forge verbleibende Dirty-Änderungen selbst, force-pusht den Agent-Branch (git push --force), lehnt einen leeren PR (keine Commits vor dem Default-Branch) ab, entfernt sonst das WIP:-Präfix, aktualisiert Titel und Description (inkl. PR_TITLE: / PR_BODY: aus der Agent-Ausgabe, Closes #<issue>) und babysittet CI.
  5. CI-/Konflikt-Reparaturen (Watch-Babysit, RunCIFix, RunConflictFix, Mention-Follow-ups) kommentieren nur am PR — Titel und Description werden dabei nicht erneut geschrieben. Follow-ups stellen für die Dauer der Arbeit das WIP:-Präfix wieder her. Vor dem Konflikt-Agenten synct forge die Default-Branch im Repo-Cache (git fetch + Fast-Forward von lokalem main/master auf origin/<base>), damit Merge/Rebase gegen den aktuellen Remote-Stand laufen.
  6. Merge-Konflikt-Detection vs. Repair: Forgejo setzt mergeable=false auch bei WIP, während der Konfliktprüfung (Checking) oder bei Fehlern — ohne echten Merge-Konflikt. Watch und Babysit behandeln mergeable=false nur als Kandidat und bestätigen Konflikte lokal mit git merge-tree gegen origin/<base>. Explizite mergeable_state-Werte conflicts/dirty (GitHub-Kompat) zählen ebenfalls als Signal, werden aber ebenfalls per Git verifiziert. Repair-Fortschritt und „resolved“ hängen am Git-Check, nicht am Forgejo-mergeable-Flag (nach beginPRFollowUp bleibt der Titel wieder WIP und damit API-seitig oft unmergeable).

Fortschritt nach dem Claim liegt am PR; der Issue-Start-Kommentar verweist weiterhin auf die Aufgabe.

Agent usage am Abschluss

Wenn forge einen Lauf abschließt — im --pr-Modus nach grünem CI (agent:ready), im --commit-Modus nach erfolgreichem Publish (agent:done + Issue schließen) — postet forge einen Agent usage-Block als Kommentar am PR bzw. am Issue. Enthalten sind — soweit vom Harness geliefert:

Feld Quelle
In/Out tokens (+ Cache) ACP PromptResponse.usage, sessionUpdate: usage_update
Cost ACP Cost oder CLI-Log-Heuristiken (cost_usd, cost:)
Limits Context used/size aus ACP; Provider-Quota via Usage-Limit-Checker (Codex/Claude)
Runtime Gesamtdauer vom ersten Agent-Start bis zum Abschluss

Fehlende Werte werden weggelassen; der Abschluss bricht nicht ab. Follow-up-Läufe (CI-Fix, Mentions) fließen in die Aggregation ein, solange Metriken kumuliert oder pro Lauf committet werden können.

Beispiel:

📊 **Agent usage** (`cursor-agent` / ACP)

| | |
| --- | --- |
| In tokens | 120 000 (cached read 80 000) |
| Out tokens | 8 500 |
| Cost | $1.23 USD |
| Limits | context 142 000 / 200 000 · quota ok |
| Runtime | 12m 34s |

Inkrementelle Commits während der Arbeit

Der Agent-Prompt fordert regelmäßige, thematisch kleine Commits mit sofortigem Push nach abgeschlossenen Teilschritten (conventional commit messages). So bleibt der bereits geöffnete WIP-PR früh mit sichtbarem Verlauf aktualisiert und CI kann früher Feedback geben.

Nach dem Agent-Lauf gilt:

  1. Uncommittet → forge committe die Reständerungen selbst (git add -A + Commit). Kein Agent-Follow-up nur zum Committen — der hatte zuvor leere PRs begünstigt (Reset statt Commit).
  2. Force-Push → forge force-pusht den Agent-Branch (git push --force origin HEAD:refs/heads/<branch>), prüft danach, dass nichts mehr ungepusht ist.
  3. Keine publizierte Arbeit → fehlen Commits vor dem Default-Branch (--pr) bzw. hat sich HEAD nicht bewegt (--commit), versucht forge zuerst Orphan-Tree-Recovery, kommentiert klar am Issue/PR und startet einen Follow-up-Agent-Lauf („Issue jetzt implementieren und committen“). Scheitert auch der, bricht der Lauf mit einer verständlichen Fehlermeldung ab (kein leerer „fertig“-PR); Issue erneut mit agent:ready / forge agent run anstoßen.
  4. Verify → nach erfolgreichem Publish startet forge bis zu verify_attempts (Default 3) Verify-Läufe (prompts.verify / agents.*.verify). Der Agent prüft die Branch-Arbeit gegen das Issue, zieht fehlendes nach und commitet. Enthält die Ausgabe Alles Implementiert (case-insensitive), endet die Schleife früh; fehlt der Marker nach allen Versuchen, läuft die Pipeline best-effort weiter (kein Fail). Mentions, CI- und Konflikt-Repairs überspringen Verify.

Dasselbe gilt für bestehende Worktrees (Reuse nach Restart/Update, WIP-PR-Wiederaufnahme, CI-/Mention-/Konflikt-Follow-ups): vor dem Weiterarbeiten werden Reständerungen forge-seitig publiziert — bei dirty Worktree zuerst Commit, dann Force-Push. Die Worktree-Maintenance flushed offene PR-Worktrees nach Restart ebenso (Commit + Force-Push). Leere offene PRs versuchen zusätzlich, verlorene Agent-Arbeit aus dangling Git-Trees wiederherzustellen (nur wenn der Diff nicht vorwiegend neueres Base-Work löscht); Branches mit eigenen Commits werden beim Flush immer force-gepusht.

Pull Requests öffnet und finalisiert weiterhin nur der Watcher (git_mode: pr). Derselbe Commit-/Push-Abschluss gilt für CI-Fixes, Mentions und Konflikt-Reparaturen.

Optional kann pre_prompt das Verhalten verstärken, z.B.:

pre_prompt: |
  Commit and push after every logical step. Keep commits small and conventional.
  Do not open a pull request yourself.

Im --commit-Modus entfällt der PR-Bezug vollständig (nur Commit/Push auf dem aktuellen Branch).

Issues mit offenen Forgejo-Dependencies (blocked-by) werden als blocked angezeigt und nicht gestartet, bis die Blocker geschlossen sind.

Bare Mode (Repos per URL)

Ohne repos[].path braucht der Agent-Orchestrierer keinen manuellen Checkout mehr:

  1. Fehlende Repos werden als bare Clone unter ~/.config/forge/repos/owner/repo.git angelegt (Cache-Root konfigurierbar via repo_cache_dir; im Workspace-Modus standardmäßig das Workspace-Verzeichnis).
  2. Vor jedem neuen Issue-Worktree läuft git fetch --prune origin; bei Bare-Caches wird der lokale Default-Branch-Ref auf origin/<default> nachgezogen. Neue Agent-Branches starten immer von origin/<default> (auch bei Legacy-Checkouts), damit frische main/master-Änderungen Konflikte reduzieren. Nach gemergten Agent-PRs wird der Default-Branch ebenfalls aktualisiert.
  3. Agent-Worktrees liegen unter .forge-worktrees/issue-<n>/ bzw. pr-<n>/ innerhalb des Bare-Caches; Push aus dem Worktree funktioniert wie gewohnt.

Repos können per url: (HTTPS/SSH), owner/name (+ optional host), CLI --repos owner/repo oder --all-repos angegeben werden. Mit --all-repos (bzw. all_repos: true) lädt forge die Liste zugänglicher Repositories über die Forgejo-API (/user/repos) und merged sie mit expliziten repos:-Einträgen; vorhandene Einträge überschreiben Pfad und Limits für dasselbe owner/name. Ohne --all-repos bleibt das Verhalten unverändert (nur konfigurierte repos: bzw. -R/--repos). Bei vielen Repositories empfiehlt sich das Setzen von parallel.max, parallel.per_repo und max_open_prs. Legacy-Checkouts mit repos[].path oder cwd-Erkennung bleiben parallel nutzbar.

Nach dem Merge eines Agent-PRs holt forge bei Bare-Repos per fetch --prune; bei Legacy-Checkouts weiterhin fetch + pull --ff-only auf dem Default-Branch. Anschließend wird der zugehörige Worktree entfernt und das Issue erhält agent:done (ersetzt agent:ready).

Agent-Status-Labels (agent:*)

Der Agent pflegt genau ein agent:*-Label pro Issue:

Phase Label
Claim / aktive Pipeline agent:working
Arbeit abgeschlossen (Coding/Babysit fertig, PR offen) agent:ready
PR gemerged und Worktree gelöscht agent:done

Beim Setzen eines neuen agent:*-Labels entfernt forge alle anderen Labels derselben Familie. Fehlende Repo-Labels (agent:working, agent:ready, agent:done) werden bei Bedarf automatisch angelegt.

Konfiguration: working_label, ready_label, done_label in agent.yaml oder --working-label, --ready-label, --done-label (Defaults siehe forge agent watch --help). Der Issue-Trigger (--label / trigger.label) ist davon getrennt und nutzt typischerweise kein agent:-Präfix.

Bei Pipeline-Fehlschlag wird agent:working entfernt; es wird kein agent:ready oder agent:done gesetzt.

Health-Loop und Job-Store (agent.db)

Während forge agent watch läuft ein Health-Loop parallel zu aktiven Pipelines (Intervall = --interval). Er hält die Instanz im Hintergrund stabil:

Check Aktion
Ghost-Jobs Stale running-Einträge ohne aktive Pipeline → failed, agent:working entfernen
Labels Genau ein erwartetes agent:* pro bekanntem Job wiederherstellen
@login stop @agent/@codex/@cursor/… plus stop/abort/cancel/halt bricht den Job ab
Issue-Änderungen Close / Trigger verloren → Stop; Body/Title-Fingerprint für laufende Jobs
--all-repos Neue zugängliche Repos periodisch hinzufügen (ohne bestehende zu droppen)
Repo-Sync Periodisch git fetch aller Remote-Branches; Default-Branch (meist main) lokal nachziehen — Intervall repo_sync_interval / --repo-sync-interval (Standard: 1m)
API/DB Forgejo-Probe und SQLite-Ping; Poll-Fehler pro Repo isolieren, Watcher läuft weiter

Der Repo-Sync hält Bare-Caches und Legacy-Checkouts nah am Server: alle origin/*-Refs werden aktualisiert, der Default-Branch zusätzlich als lokaler Tip. Unabhängig davon refreshed forge den Default-Branch unmittelbar vor jedem neuen Issue-Worktree; Startpunkt ist origin/<default>. Bei Legacy-Checkouts mit laufendem Job macht der periodische Sync nur Fetch (kein Checkout/Pull); neue Worktrees brauchen das nicht, weil sie vom Remote-Tip starten.

Persistenz liegt in SQLite ohne CGO (modernc.org/sqlite):

  • Pfad: ~/Library/Application Support/forge/agent.db (bzw. os.UserConfigDir()/forge/agent.db)
  • Tabellen: jobs, job_events, issue_snapshots, pr_snapshots
  • Einmaliger Import aus Legacy agent-state.json → Umbenennung nach agent-state.json.bak

Stop-Beispiel auf Issue oder PR: @agent stop oder @codex abort.

Projekt-Spalten (--project-column)

Wenn --project gesetzt ist, kann --project-column (oder project_column in agent.yaml) das Issue beim Claim in eine Board-Spalte verschieben. Der primäre Lock bleibt das Working-Label (agent:working); die Spalte ist ein zusätzlicher Board-Status.

forge erkennt zur Laufzeit, welche Project-REST-Variante die Forgejo-Instanz anbietet, und nutzt dann deterministisch genau diese Pfade:

Forgejo Gitea (Referenz) Variante Endpunkte
< 7.0 < 1.22 legacy-cards GET /projects/{id}/columns, Karten unter /projects/columns/{id}/cards
7.0 10.x 1.22 1.25 legacy-cards Repository-Boards in der UI; REST meist Legacy-Karten-API
11.0+ 1.23+ (wenn REST vorhanden) repo-issues GET /repos/{owner}/{repo}/projects/{id}/columns, POST /repos/.../projects/columns/{id}/issues/{index}
beliebig beliebig unsupported Projects-Unit deaktiviert oder kein Column-REST (404/501/405 auf allen Probes)

Verhalten:

  • API vorhanden und Spalte gefunden → Move muss gelingen, sonst bricht der Claim mit Fehler ab.
  • API nicht unterstützt → expliziter Skip mit Grund im Log (project column move skipped: …); der Agent-Lauf geht weiter.
  • Spaltenname nicht gefunden → Fehler (auch wenn die API grundsätzlich verfügbar ist).

Die Matrix steht auch im Code (ForgejoProjectColumnSupport in internal/agent/project_column.go) und wird bei jeder Instanz per Probe verifiziert, nicht nur anhand der Versionsnummer.

Wichtige Flags

Siehe forge agent watch --help für die vollständige Liste. Auszug (auch in agent.yaml möglich):

  • --agent — Coding-Agent-CLI
  • --label / --user / --project — Issue-Trigger (genau einer)
  • --project-column — Spalte im Projekt-Board beim Claim (z. B. „In Arbeit“)
  • --commit / --pr — Git-Modus (--commit: aktueller Branch, max. 1 Job, kein PR; --pr: Worktree + WIP-PR sofort, Finalisierung nach Agent-Lauf)
  • --repos owner/repo,... — weitere Watch-Targets (bare-cloned ohne lokales path; im --commit-Modus braucht jedes Target einen Working-Tree/path)
  • --all-repos — alle für den Login zugänglichen Repositories überwachen (merged mit repos:)
  • --parallel, --parallel-per-repo, --max-open-prs — Dispatch-Limits (im --commit-Modus Parallelität=1, max_open_prs irrelevant)
  • --interval — Repository-Prüfintervall (Standard: 10s)
  • --repo-sync-interval — Fetch/Sync der Default-Branch für watched Repos (Standard: 1m)
  • --ci-interval — CI-Prüfintervall beim PR-Babysitting (Standard: 5s)
  • --working-label, --ready-label, --done-labelagent:* Lifecycle-Labels (siehe Wiki)
  • --no-tui — Plain-Logs statt Dashboard
  • --config — Pfad zur Agent-Konfiguration

forge agent config — interaktive TUI für die lokale agent.yaml (siehe Abschnitt Config-Mode)