# 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`.