This page describes runtime state transitions for task/run.
For startup preflight rules and full pattern matrix, see startup-patterns.
- 0.1 Entry Point from State Model
- 1. Startup / Preflight
- 2. Basic Lifecycle
- 3. Blocked Reasons Used for Recovery
- 4. Run Lifecycle and Judge Idempotency
- 5. Dispatcher Recovery Layer
- 6. Worker Failure Handling
- 7. Judge Non-Approval / Merge Failure Paths
- 8. Cycle Manager Self-Recovery
- 9. Host Snapshot and Context Update
- 10. Why
FailedandRetryCoexist - Related Agent Specifications
- 11. TigerResearch Lifecycle (Planner-First)
- 13. Chat Conversational Flow
When entering from state vocabulary, first fix terminology in state-model, then check transitions and recovery paths here.
| State model section | Next section here | Owning agent |
|---|---|---|
| "1. Task Status" "2. Task Block Reason" | 2. Basic Lifecycle, 3. Blocked Reasons Used for Recovery | Dispatcher / Worker / Judge |
| "2.2 Task Retry Reason (Operations)" | 6. Worker Failure Handling, 8. Cycle Manager Self-Recovery | Worker / Cycle Manager |
| "7. Patterns Prone to Stalls" | 5. Dispatcher Recovery Layer, 7. Judge Non-Approval / Merge Failure Paths | Dispatcher / Judge |
On system startup, call /system/preflight to build recommended startup configuration.
Inputs:
- Requirement content
- GitHub open issues
- GitHub open PRs
- Local task backlog (
queued/running/failed/blocked)
Rules:
startPlanner = hasRequirementContent && !hasIssueBacklog && !hasJudgeBacklog- Execution agents (
dispatcher/worker/tester/docser) start when planner work or backlog exists - Judge starts when judge backlog exists or execution agents are active
- Planner process count is max 1
Meaning of common warnings:
Issue backlog detected (...)- Backlog-first mode is active
Planner is skipped for this launch- Normal when issue/pr backlog exists
Exact formulas and all combinations are in startup-patterns.
- Task enters
queued - Dispatcher acquires lease and moves task to
running - Execution role (
worker/tester/docser) runs task and verification commands- For
tasks.kind=research, worker runs non-git research path (plan/collect/challenge/write) - For
tasks.kind=code, normal git-based implementation path is used - Before LLM execution, worker builds compressed prompt context from:
- Static instructions (
apps/worker/instructions/*.md) - Runtime snapshot (
.opentiger/context/agent-profile.json) - Failure delta (
.opentiger/context/context-delta.json)
- Static instructions (
- Context injection uses a fixed character budget to avoid prompt bloat
- For
- On success:
github/local-gitmode: usuallyblocked(awaiting_judge)if review neededdirectmode: tasks transition directly todone(no judge review)- Otherwise
done
- Judge evaluates successful run (skipped in
directmode) - Task transitions to:
doneblocked(awaiting_judge)(retry/recovery)blocked(needs_rework)(split/autofix path)
- Cycle Manager continues requeue / rebuild until convergence
Definitions are in state-model.
awaiting_judge- Successful run exists but not judged, or run restore needed
quota_wait- Worker detected LLM quota error; waiting for cooldown retry
needs_rework- Non-approve escalation, repeated failure signature, or explicit autofix path
Legacy needs_human is normalized into valid recovery paths.
Other runtime blocked reasons:
issue_linking- Planner temporarily holds task for issue-link metadata; returns to
queuedwhen resolved
- Planner temporarily holds task for issue-link metadata; returns to
- Worker creates
runs(status=running)at start - Worker updates run to
success/failed - Judge only processes unjudged successful runs
- Judge atomically claims run before review (
judgedAt,judgementVersion)
Result:
- Prevents double review of same run
- Suppresses duplicate judge loops
Each poll loop:
- Clean up expired leases
- Clean up dangling leases
- Reclaim dead-agent leases
- Recover orphaned
runningtasks with no active run
Task filter conditions:
- Unresolved dependencies blocked
targetAreaconflict blocked- Recent non-quota failure subject to cooldown block
- Latest quota failure excluded from dispatcher cooldown block
On task error:
- Update run to
failed - Update task:
- If matches quota signature:
blocked(quota_wait) - Otherwise:
failed
- If matches quota signature:
- Optionally update context delta (
.opentiger/context/context-delta.json) by failure signature - Release lease
- Return agent to
idle
Queue duplicate prevention:
- Per-task runtime lock
- Post-start guard on lock conflict (avoids wrong immediate requeue)
- Non-approval may create AutoFix task and move parent to
blocked(needs_rework) - On approval, merge retries are handled by
pr_merge_queue(not same-run re-judgement) - Queue lifecycle:
pending->processing(claim)processing->merged(taskdone) orpending(retry with backoff)processing->failed(attempt budget exhausted)
- Conflict recovery (
[AutoFix-Conflict]/[Recreate-From-Main]) is triggered only after merge queue exhaustion - Stale queue claims are recovered by Judge and Cycle Manager cleanup paths
Main periodic actions:
- Cancel timeout runs
- Lease cleanup
- Reset offline agents
- Cooldown requeue of failed tasks (with failure classification; unsupported/missing verification command goes to command adjustment, not block)
- Reason-specific cooldown recovery for blocked tasks
- Backlog ordering gate
local task backlog > 0: continue task executionlocal task backlog == 0: call/system/preflightto import/sync issue backlogissue backlog == 0: trigger Planner replan
For startup vs replan responsibility split, see startup-patterns.
Blocked recovery behavior:
awaiting_judge- If pending judge run exists, keep
blocked(awaiting_judge) - If no pending run, try restoring latest judgable successful run
- If no run can be restored:
- Judge-review task: requeue to
queued(awaiting_judge_missing_run_retry) - Other task: timeout requeue to
queued(awaiting_judge_timeout_retry)
- Judge-review task: requeue to
- If pending judge run exists, keep
quota_wait- Requeue after cooldown
needs_rework- Judge-review task:
- Pending/restorable judge run exists ->
blocked(awaiting_judge) - Missing judge run -> requeue to
queued(pr_review_needs_rework_missing_run_retry)
- Pending/restorable judge run exists ->
setup_or_bootstrap_issue: in-place requeue from blocked with setup retry limit- Normal task: create
[Rework] ...task, move parent to failed lineage - Policy-only violation: may in-place requeue after
allowedPathsadjustment. If no safe path, suppress rework split (cancel after retry limit) - Do not create additional rework if valid rework child already exists
- Cancel when rework depth exceeds
AUTO_REWORK_MAX_DEPTH
- Judge-review task:
System process self-recovery:
- Self-heal starts managed processes only while runtime hatch is armed
- Judge backlog alone does not arm runtime hatch
Policy lifecycle and self-growth details:
- API host context endpoints:
GET /system/host/neofetchGET /system/host/context
- Main snapshot source is
neofetch; falls back touname -srmowhen needed - Snapshot cached in
.opentiger/context/agent-profile.json, updated by TTL/fingerprint
Runs table may show immediate failed while task card shows retry countdown.
Example:
- run status:
failed(actual result of that attempt) - task retry:
quota 79s(next recovery attempt already scheduled)
This indicates active recovery, not a halt.
- agent/planner
- agent/dispatcher
- agent/worker
- agent/tester
- agent/docser
- agent/judge
- agent/cycle-manager
To trace implementation, use the "Implementation reference (source of truth)" section at the end of each page to locate the corresponding apps/*/src.
POST /plugins/tiger-research/jobscreates a research job and requests planner start withresearchJobId- Planner decomposes query into claims and enqueues claim-level
collecttasks - Dispatcher runs those tasks in parallel (
tasks.kind=research) - Worker persists claims/evidence/report artifacts in TigerResearch plugin tables
- Cycle Manager orchestrates stage transitions:
planning->collecting->challenging->composing->judging/reworking
- Judge (if
RESEARCH_REQUIRE_JUDGE=true) applies research verdict:- pass: task/job converge to
done - fail: task blocked as
needs_rework
- pass: task/job converge to
- Cycle Manager creates targeted rework tasks until quality gate convergence or blocked terminal condition
Fallback behavior:
- If planner cannot be started on job creation, API enqueues a fallback
plantask. - While
plannerPendingUntilis active, cycle manager waits before fallback plan task injection.
All plugin runtime behavior is driven by PluginManifestV1 loaded by packages/plugin-sdk.
- Startup loader phase
- Read available plugin manifests
- Validate
pluginApiVersion - Resolve
requiresorder - Build enabled plugin registry from
ENABLED_PLUGINS
- API phase
- Mount plugin routes under
/plugins/<plugin-id>/* - Expose plugin inventory/status through
GET /plugins
- Mount plugin routes under
- Planner/Dispatcher/Worker/Judge/Cycle phase
- Resolve hooks from shared registry
- Execute plugin-specific behavior without hardcoded plugin id checks
- Dashboard phase
- Discover route modules via
import.meta.glob - Apply enabled-filter to nav/routes at startup
- Discover route modules via
- DB phase
- Apply core migrations
- Apply plugin migrations in dependency order
Failure handling:
- Incompatible plugin manifest ->
incompatiblestatus, plugin skipped, core continues - Plugin load/runtime initialization error ->
errorstatus with explicit reason
The chat interface provides a conversational path from requirement to execution.
Phase progression: greeting → requirement_gathering → plan_proposal → execution → monitoring
- User sends message describing what they want to build
- LLM generates a plan autonomously (minimal clarification questions)
- When plan is complete, LLM appends
---PLAN_READY---marker - Backend detects marker, strips it from saved content, inserts
mode_selectionsystem message - Conversation phase transitions to
plan_proposal
- UI renders mode selection card (Direct / Local Git / GitHub)
- User selects execution mode via
POST /chat/conversations/:id/start-execution - Backend updates global config, sets conversation to
executionphase - Frontend triggers preflight → process startup (planner, dispatcher, workers, judge, cycle-manager)
LLM responses are streamed via Server-Sent Events:
POST /messagesstarts LLM execution and returns immediately- Chunks are buffered in an in-memory session (
chat-state.ts) GET /streamreplays buffered chunks, then listens for new events- Terminal events:
done(success) orerror(failure) - Session cleanup after 60s post-completion
apps/api/src/routes/chat.ts— endpointsapps/api/src/routes/chat-orchestrator.ts— phase resolution, system promptsapps/api/src/routes/chat-state.ts— SSE session managementpackages/llm/src/chat/chat-executor.ts— LLM process executionapps/dashboard/src/pages/Chat.tsx— frontend orchestrationapps/dashboard/src/lib/chat-api.ts— API client and SSE subscriber