State Enforcement (v2.0):
- .state file as single source of truth for task phase
- Approval gates for research, decomposition, design, test_design
- status.py --transition refuses illegal phase transitions
- status.py --validate-folder detects out-of-order artifacts
- status.py --audit checks all tasks for violations
- status.py --create-task is the only valid way to create tasks
- Pre-v2.0 tasks without .state are UNTRACKED -- all commands refuse them
- New --upgrade command bootstraps .state files for existing tasks
Project Scoping:
- --project flag added to all status.py commands across 16+ files
- _find_project_dir errors instead of silently falling back to ~/.automaton/
- --scope-check marks framework files OUT_OF_SCOPE when working on a project
- Dashboard handlers use stored project_root instead of re-detecting from CWD
- Prompts reference ~/.automaton/scripts/vram_detect.py (not {project}/.automaton/)
Harness Integration:
- status.py --can-edit now supports project-level checks (no --task required)
- --can-edit --file checks file scope without --task
- --json output for machine-readable harness integration
- opencode plugin (plugins/automaton-guard/plugin.ts) intercepts edit/write
- Git pre-commit hook (scripts/git-hooks/pre-commit) blocks commits without task
- Formal integration contract (contracts/harness-integration.md)
Other:
- upgrade.sh delegates to status.py --upgrade instead of manual heuristics
- Phase prompts reference --project {project} for multi-project scoping
- 200 tests passing (14 new)
7.4 KiB
Workflow State Machine
This file defines the linear progression of a task in automaton. The Orchestrator uses this to determine the next phase.
Single Source of Truth: .state File
The .state file in each task folder is the canonical indicator of a task's current phase. It takes precedence over artifact-based heuristic.
- Location:
tasks/{task-name}/.state - Content: A single phase name (e.g.,
research,research:awaiting_approval,implement,complete) - Atomic writes: Written to
.state.tmpfirst, then renamed to.state - If
.stateis missing: Fall back to artifact-based heuristic and write.statewith the inferred phase
.state.approvals Log
Each task has a .state.approvals file recording all user approvals:
- Location:
tasks/{task-name}/.state.approvals - Format: One line per approval:
{phase}:approved|{ISO-8601-timestamp}|{approver} - Append-only: Approvals are never deleted
- Metadata: Not a phase deliverable, excluded from artifact checks
.state.lock (Multi-Agent Mode Only)
When Mode: multi-agent is set in .agent.md, a .state.lock file tracks which agent has claimed the task:
- Location:
tasks/{task-name}/.state.lock - Format:
agent: {id},phase: {current},claimed: {timestamp},expires: {timestamp} - Atomic writes: Same
.tmppattern as.state - Default timeout: 30 minutes (configurable in
.agent.md) - Metadata: Not a phase deliverable, excluded from artifact checks
Task Lifecycle
| Current State | Signal | Next Phase | Action |
|---|---|---|---|
| New Task | status.py --create-task {name} --project {project} creates folder with .state = new |
Research | Generate SPEC.md |
| Research | Has .state = research |
research:awaiting_approval | Present SPEC.md draft for user sign-off |
| research:awaiting_approval | Has .state = research:awaiting_approval |
research:approved | User says "APPROVED", call status.py --approve |
| research:approved | Has .state = research:approved |
Decomposition (optional) or Design (optional) or Implement | Transition via status.py --transition |
| Decomposition | Has .state = decomposition |
decomposition:awaiting_approval | Present DECOMPOSITION.md draft for user sign-off |
| decomposition:awaiting_approval | Has .state = decomposition:awaiting_approval |
decomposition:approved | User says "APPROVED", call status.py --approve |
| decomposition:approved | Has .state = decomposition:approved |
Sub-task Research | Orchestrator creates sub-task folders |
| Design | Has .state = design |
design:awaiting_approval | Present DESIGN.md draft for user sign-off |
| design:awaiting_approval | Has .state = design:awaiting_approval |
design:approved | User says "APPROVED", call status.py --approve |
| design:approved | Has .state = design:approved |
Test Design (optional) or Implement | Transition via status.py --transition |
| Test Design | Has .state = test_design |
test_design:awaiting_approval | Present TEST_PLAN.md draft for user sign-off |
| test_design:awaiting_approval | Has .state = test_design:awaiting_approval |
test_design:approved | User says "APPROVED", call status.py --approve |
| test_design:approved | Has .state = test_design:approved |
Implement | Transition via status.py --transition |
| Implementation | Has .state = implement |
Bug Find | Generate BUG_REPORT.md |
| Bug Find | Has .state = bug_find |
Adversarial Bug Find | Generate ADVERSARIAL_BUG_REPORT.md |
| Adversarial Bug Find | Has .state = adversarial_bug_find |
Doc Review | Generate DOC_REVIEW.md |
| Doc Review | Has .state = doc_review |
Referee | Generate VERDICT.md |
| Referee | Has .state = referee |
Complete / Human Intervention | Finalize or request user intervention |
Phases Without Approval Gates
The following phases do not have :awaiting_approval sub-states because they do not require interactive user sign-off:
implement,bug_find,adversarial_bug_find,doc_review,referee- These transition directly to the next phase upon producing their artifact and calling
status.py --transition
Task Creation (via status.py)
New tasks MUST be created via status.py --create-task {name} --project {project}. This creates the folder, .state = new, and an empty .state.approvals file.
Manual task folder creation (mkdir tasks/my-task) is flagged as a violation by status.py --audit and status.py --validate-folder.
Tasks without .state files are UNTRACKED. All commands (--transition, --can-edit, --task, --approve) refuse to operate on them. Run status.py --upgrade --project {project} to bootstrap .state files for pre-v2.0 tasks.
Task creation from bugs
When the Orchestrator detects a VERDICT.md with FAIL or NEEDS_REVIEW, it uses status.py --create-task --project {project} to create fix/review/tiebreak tasks. The Orchestrator also copies relevant artifacts (SPEC.md, BUG_REPORT.md, etc.) and sets .state to the appropriate phase (e.g., bug_find for fix tasks).
Enforcement via status.py
Phase-Gated Transitions
All transitions go through status.py --transition {phase} --project {project}:
- Only legal transitions are allowed (defined in LEGAL_TRANSITIONS)
:awaiting_approvalphases can only transition to:approvedviastatus.py --approve --project {project}- Required artifacts must exist and be non-empty before transitioning
- Forbidden artifacts (from future phases) block transitions
Folder Validation
status.py --validate-folder --task {name} --project {project} checks for:
- Out-of-order artifacts (artifacts from future phases)
- Missing
.statefile (manually created task) - Phase-artifact inconsistency
Audit
status.py --audit --project {project} checks all tasks for:
- Category 1: Out-of-order artifacts
- Category 2: State-artifact inconsistency
- Category 3: Unauthorized git modifications (if git repo)
- Category 4: Manually created task folders (no
.state)
Approval Gates
status.py --approve --task {name} --project {project} transitions from :awaiting_approval to :approved:
- Records approval in
.state.approvalswith timestamp and approver - Refuses if not in an
:awaiting_approvalsub-state - Refuses for phases that don't require approval
Autopilot Rules
- Linear Progression: Never skip a phase. Each transition must go through
status.py --transition --project {project}. - Approval Gates: Research, Decomposition, Design, and Test Design phases require explicit user approval before proceeding. The autopilot MUST pause at
:awaiting_approvalsub-states. - Artifact Check: A phase is only considered "complete" if its corresponding artifact exists, is non-empty, AND the
.statefile reflects the completed phase. - Folder Validation: Before each phase transition, run
status.py --validate-folder --project {project}. Do not proceed past violations. - Human Intervention: If the Referee marks a task as
FAIL,NEEDS_REVIEW, or identifies "Tie-Breaks", the Autopilot pauses and waits for user input. - Task Creation: Always use
status.py --create-task --project {project}to create new tasks. Never create task folders manually. - Forbidden Actions: Respect the ALLOWED/FORBIDDEN sections in each phase prompt. Even in autopilot, the Orchestrator must not perform forbidden actions.