1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
# Package: task
`internal/task` — Task definition, parsing, validation, and state machine.
---
## 1. Overview
A **Task** is the central unit of work in Claudomator. It describes what an agent should do (`agent.instructions`), how it should be run (timeout, retry, priority), and how it relates to other tasks (`depends_on`, `parent_task_id`). Tasks are defined in YAML files, parsed into `Task` structs, persisted in SQLite, and driven through a state machine from `PENDING` to a terminal state.
---
## 2. Task Struct
```go
type Task struct {
ID string // UUID; auto-generated if omitted in YAML
ParentTaskID string // ID of parent task (subtask linkage); empty for root tasks
Name string // Human-readable label; required
Description string // Optional longer description
Agent AgentConfig // How to invoke the agent
Timeout Duration // Maximum wall-clock run time (e.g. "30m"); 0 = no limit
Retry RetryConfig // Retry policy
Priority Priority // "high" | "normal" | "low"; default "normal"
Tags []string // Arbitrary labels for filtering
DependsOn []string // Task IDs that must reach COMPLETED before this queues
State State // Current lifecycle state; not read from YAML (yaml:"-")
RejectionComment string // Set by RejectTask; not read from YAML (yaml:"-")
QuestionJSON string // Pending question from a READY agent; not read from YAML (yaml:"-")
CreatedAt time.Time // Set on parse; not read from YAML (yaml:"-")
UpdatedAt time.Time // Updated on every state change; not read from YAML (yaml:"-")
}
```
Fields tagged `yaml:"-"` are runtime-only and are never parsed from task YAML files.
---
## 3. AgentConfig Struct
```go
type AgentConfig struct {
Type string // Agent implementation: "claude", "gemini", etc.
Model string // Model identifier passed to the agent binary
ContextFiles []string // Files injected into agent context at start
Instructions string // Prompt / task description sent to the agent; required
ProjectDir string // Working directory for the agent process
MaxBudgetUSD float64 // Spending cap in USD; 0 = unlimited; must be >= 0
PermissionMode string // One of: default | acceptEdits | bypassPermissions | plan | dontAsk | delegate
AllowedTools []string // Whitelist of tool names the agent may use
DisallowedTools []string // Blacklist of tool names the agent may not use
SystemPromptAppend string // Text appended to the agent's system prompt
AdditionalArgs []string // Extra CLI arguments forwarded to the agent binary
SkipPlanning bool // When true, bypass the planning phase
}
```
---
## 4. RetryConfig Struct
```go
type RetryConfig struct {
MaxAttempts int // Total attempts including the first; default 1 (no retry)
Backoff string // "linear" or "exponential"; default "exponential"
}
```
---
## 5. YAML Task File Format — Single Task
```yaml
# Unique identifier. Optional: auto-generated UUID if omitted.
id: "fix-login-bug"
# Human-readable label. Required.
name: "Fix login redirect bug"
# Optional description shown in the UI.
description: "Users are redirected to /home instead of /dashboard after login."
# Agent configuration.
agent:
# Agent type: "claude", "gemini", etc. Can be omitted for auto-classification.
type: "claude"
# Model to use. Empty = agent default.
model: "claude-opus-4-6"
# Files loaded into the agent's context before execution.
context_files:
- "src/auth/login.go"
- "docs/design/auth.md"
# Prompt sent to the agent. Required.
instructions: |
Fix the post-login redirect in src/auth/login.go so that users are
sent to /dashboard instead of /home. Add a regression test.
# Working directory for the agent process. Empty = server working directory.
project_dir: "/workspace/myapp"
# USD spending cap. 0 = no limit.
max_budget_usd: 1.00
# Permission mode. Valid values: default | acceptEdits | bypassPermissions | plan | dontAsk | delegate
permission_mode: "acceptEdits"
# Tool whitelist. Empty = all tools allowed.
allowed_tools:
- "Edit"
- "Read"
- "Bash"
# Tool blacklist.
disallowed_tools:
- "WebFetch"
# Appended to the agent's system prompt.
system_prompt_append: "Always write tests before implementation."
# Extra arguments forwarded verbatim to the agent binary.
additional_args:
- "--verbose"
# Skip the planning phase.
skip_planning: false
# Maximum run time. Accepts Go duration strings: "30m", "1h30m", "45s".
# 0 or omitted = no limit.
timeout: "30m"
# Retry policy.
retry:
# Total attempts (including first). Must be >= 1.
max_attempts: 3
# "linear" or "exponential".
backoff: "exponential"
# Scheduling priority: "high", "normal" (default), or "low".
priority: "normal"
# Arbitrary string labels for filtering.
tags:
- "bug"
- "auth"
# Task IDs that must be COMPLETED before this task is queued.
depends_on:
- "setup-test-db"
```
---
## 6. Batch File Format
A batch file wraps multiple tasks under a `tasks` key. Each entry is a full task definition (same fields as above). All tasks are parsed and initialized together.
```yaml
tasks:
- name: "Step 1 — scaffold"
agent:
instructions: "Create the initial project structure."
priority: "high"
- name: "Step 2 — implement"
agent:
instructions: "Implement the feature described in docs/feature.md."
depends_on:
- "step-1-id"
- name: "Step 3 — test"
agent:
instructions: "Write and run integration tests."
depends_on:
- "step-2-id"
retry:
max_attempts: 2
backoff: "linear"
```
`ParseFile` tries the batch format first; if no `tasks` key is present it falls back to single-task parsing.
---
## 7. State Constants
| Constant | Value | Meaning |
|-------------------|------------------|-------------------------------------------------------------------------|
| `StatePending` | `PENDING` | Newly created; awaiting classification or human approval. |
| `StateQueued` | `QUEUED` | Accepted and waiting for an available agent slot. |
| `StateRunning` | `RUNNING` | Agent process is actively executing. |
| `StateReady` | `READY` | Agent has paused and is awaiting human input (question / approval). |
| `StateCompleted` | `COMPLETED` | Agent finished successfully. Terminal — no further transitions allowed. |
| `StateFailed` | `FAILED` | Agent exited with a non-zero code or internal error. |
| `StateTimedOut` | `TIMED_OUT` | Execution exceeded the configured `timeout`. |
| `StateCancelled` | `CANCELLED` | Explicitly cancelled by the user or scheduler. |
| `StateBudgetExceeded` | `BUDGET_EXCEEDED` | Agent hit the `max_budget_usd` cap before finishing. |
| `StateBlocked` | `BLOCKED` | Waiting on a dependency task that has not yet completed. |
---
## 8. State Machine — Valid Transitions
| From | To | Condition / trigger |
|--------------------|--------------------|--------------------------------------------------------------|
| `PENDING` | `QUEUED` | Task approved and eligible for scheduling. |
| `PENDING` | `CANCELLED` | Cancelled before being queued. |
| `QUEUED` | `RUNNING` | Agent slot becomes available; execution starts. |
| `QUEUED` | `CANCELLED` | Cancelled while waiting in the queue. |
| `RUNNING` | `READY` | Agent pauses and emits a question for human input. |
| `RUNNING` | `COMPLETED` | Agent exits successfully. |
| `RUNNING` | `FAILED` | Agent exits with an error. |
| `RUNNING` | `TIMED_OUT` | Wall-clock time exceeds `timeout`. |
| `RUNNING` | `CANCELLED` | Cancelled mid-execution. |
| `RUNNING` | `BUDGET_EXCEEDED` | Cumulative cost exceeds `max_budget_usd`. |
| `RUNNING` | `BLOCKED` | Runtime dependency check fails. |
| `READY` | `COMPLETED` | Human answer accepted; task finishes. |
| `READY` | `PENDING` | Answer rejected; task returns to pending for re-approval. |
| `FAILED` | `QUEUED` | Retry requested (re-enqueue). |
| `TIMED_OUT` | `QUEUED` | Retry or resume requested. |
| `CANCELLED` | `QUEUED` | Restart requested. |
| `BUDGET_EXCEEDED` | `QUEUED` | Retry with higher or no budget. |
| `BLOCKED` | `QUEUED` | Dependency became satisfied; task re-queued. |
| `BLOCKED` | `READY` | Dependency resolved but human review required. |
| `COMPLETED` | *(none)* | Terminal state. |
---
## 9. Key Functions
### `ParseFile(path string) ([]Task, error)`
Reads a YAML file at `path` and returns one or more tasks. Tries batch format (`tasks:` key) first; falls back to single-task format. Auto-assigns UUIDs, default priority, default retry config, and sets `State = PENDING` on all returned tasks.
### `Parse(data []byte) ([]Task, error)`
Same as `ParseFile` but operates on raw bytes instead of a file path.
### `ValidTransition(from, to State) bool`
Returns `true` if the transition from `from` to `to` is permitted by the state machine. Used by `storage.DB.UpdateTaskState` to enforce transitions atomically inside a transaction.
### `Validate(t *Task) error`
Validates a task's fields. Returns `*ValidationError` (implementing `error`) with all failures collected, or `nil` if valid.
---
## 10. Validation Rules
The `Validate` function enforces the following rules:
| Rule | Details |
|------|---------|
| `name` required | Must be non-empty. |
| `agent.instructions` required | Must be non-empty. |
| `agent.max_budget_usd` non-negative | Must be `>= 0`. |
| `timeout` non-negative | Must be `>= 0` (zero means no limit). |
| `retry.max_attempts >= 1` | Must be at least 1. |
| `retry.backoff` valid values | Must be empty, `"linear"`, or `"exponential"`. |
| `priority` valid values | Must be empty, `"high"`, `"normal"`, or `"low"`. |
| `agent.permission_mode` valid values | Must be empty or one of: `default`, `acceptEdits`, `bypassPermissions`, `plan`, `dontAsk`, `delegate`. |
Multiple failures are collected and returned together in a single `ValidationError`.
|