Files
Lap Tran bc7daf8590 Restore archived tasks, fix dashboard scroll-reset, bind ornith, add Playwright smoke test
- **Restore 82 completed tasks** from tasks/complete/ back to tasks/ top
  level (all <7 days old per the cleanup policy; premature bulk archive
  was fixed).
- **Dashboard: fix scroll-reset on auto-refresh** — renderBoard rebuilds
  the board via innerHTML every 2s, destroying each column-body's
  scrollTop. Now snapshots column-body scrollTop + board.scrollLeft +
  view.scrollTop before rebuild and restores after (matched by
  PHASE_GROUPS index).
- **Dashboard UI additions** (pre-existing unstaged work): approval
  section cards, transition buttons, inline artifact editor (textarea for
  writing missing SPEC/VERDICT/etc from the detail modal).
- **Bind ornith as Implement model** — config.md: Model explicit to
  omlx/Ornith-1.0-35B-4bit-mlx, context window 32768. Interactive
  autopilot already used ornith via opencode default; now explicit.
- **Fix cleanup stub** — automaton-cleanup.sh had a stale --project arg
  pointing at a pytest temp dir (test isolation leak). Rewired to point
  at ~/.automaton.
- **Fix plist-isolation test** — test asserted host plist doesn't exist,
  but a real install creates it. Now snapshots mtime before run, asserts
  unchanged after (only a write during the test counts as bleed).
- **New Playwright smoke test** (tests/test_dashboard_ui.py) — 2 tests:
  board renders tasks, column scroll survives auto-refresh tick.
  Verified the test fails without the scroll fix (scrollTop resets to 0).
  Skipped via importorskip when playwright is absent (main CI stays
  green).
- **Clarify SI loop scope in README** — new-project onboarding section
  documents the framework-scoped self-improvement loop and options
  (leave/pause/create project loop).
- **CHANGELOG** documents all changes including the known model-divergence
  gap (mde tasks marked complete but per-role model binding was never
  implemented).
2026-06-26 10:05:18 -04:00

23 KiB

SPEC: Status Script

Goal

Create a status.py script that any agent can call to determine the current phase, allowed actions, and forbidden actions for a task — reducing agent decision-making to a single bash command.

Background

Currently, agents must read .agent.md, .rules.md, workflow.md, check artifact existence, and derive their allowed actions from 493 lines of orchestrator prompt. This complexity causes agents to skip phases. A single command that returns the current state and boundaries eliminates ambiguity and reduces the cognitive load on the agent.

Requirements

1. Command interface

python ~/.automaton/scripts/status.py --task {task-name} [--project {project-path}]

2. Output format

The script outputs structured plain text (not JSON — agents parse plain text more reliably):

Task: add-user-auth
Phase: research (from .state)
State file: ~/.automaton/tasks/add-user-auth/.state
Allowed actions:
  - Read project files
  - Ask clarifying questions  
  - Write SPEC.md
Forbidden actions:
  - Edit code
  - Create IMPLEMENTATION.md
  - Create DESIGN.md
  - Skip to implementation
Next artifact needed: SPEC.md
Next phase: design or implement
Command to proceed: "orchestrate" or "design {task-name}"

3. State determination logic

The script must determine state using this priority:

  1. Read .state file — if it exists, it is authoritative
  2. Fall back to artifact heuristic — if .state doesn't exist, determine state from artifact files (current logic from workflow.md) and write .state with the inferred phase
  3. Report "unknown" — if neither .state nor enough artifacts exist to determine state

4. Atomic .state writes

When the script writes .state (during fallback or transition), it must:

  • Write to .state.tmp first
  • Rename .state.tmp to .state (atomic on most filesystems)
  • Not corrupt an existing .state if the write fails

5. Transition command

python ~/.automaton/scripts/status.py --task {task-name} --transition {phase}

This transitions the task to a new phase:

  • Validates the transition is legal according to the state machine
  • Writes .state with the new phase name
  • Validates the required artifact for the current phase exists before transitioning
  • Refuses illegal transitions (e.g., from research directly to bug_find)
  • Refuses transitions past :awaiting_approval sub-states (approval must be granted first)

Legal transitions:

  • new → research
  • research → research:awaiting_approval (when SPEC.md draft is produced)
  • research:awaiting_approval → research:approved (ONLY via --approve, not --transition)
  • research:approved → decomposition | design | implement
  • decomposition → decomposition:awaiting_approval (when DECOMPOSITION.md draft is produced)
  • decomposition:awaiting_approval → decomposition:approved (ONLY via --approve)
  • decomposition:approved → (sub-task research, parent awaits)
  • design → design:awaiting_approval (when DESIGN.md draft is produced)
  • design:awaiting_approval → design:approved (ONLY via --approve)
  • design:approved → test_design | implement
  • test_design → test_design:awaiting_approval (when TEST_PLAN.md draft is produced)
  • test_design:awaiting_approval → test_design:approved (ONLY via --approve)
  • test_design:approved → implement
  • implement → bug_find
  • bug_find → adversarial_bug_find
  • adversarial_bug_find → doc_review
  • doc_review → referee
  • referee → complete | human_intervention

Approval gate enforcement: --transition MUST REFUSE to transition from :awaiting_approval to any phase other than :approved. This ensures sign-off cannot be bypassed.

5a. Approve command

python ~/.automaton/scripts/status.py --task {task-name} --approve

Approves the current phase artifact, transitioning from :awaiting_approval to :approved.

  • This is the ONLY way to move past an approval gate
  • Must be called explicitly — the agent cannot self-approve
  • Writes .state with the :approved sub-state atomically
  • Records approval in .state.approvals log (see section 5b)

If the current phase does not have an :awaiting_approval sub-state:

  • For phases with approval (research, decomposition, design, test_design): if not in :awaiting_approval, refuse with: "ERROR: Current phase is '{phase}' (not awaiting approval). Current sub-state must be '{phase}:awaiting_approval' before approval can be granted."
  • For phases without approval (implement, bug_find, etc.): "This phase does not require approval."

5b. Approval log

Each task has an .state.approvals file that records all approvals:

Location: tasks/{task-name}/.state.approvals Format (one line per approval):

research:approved|2026-06-14T14:30:00Z|user
design:approved|2026-06-14T15:00:00Z|user

Each line contains: {phase}:approved|{ISO-8601-timestamp}|{approver}

  • {approver} is "user" for manual approval or the agent-id for multi-agent approval
  • This file is append-only — approvals are never deleted
  • It is metadata, not an artifact, and is excluded from --validate-folder checks

5c. Create-task command

python ~/.automaton/scripts/status.py --create-task {task-name} [--project {project-path}]

This is the ONLY valid way to create a task folder. It:

  1. Validates that the task name is kebab-case (lowercase, hyphens, no spaces)
  2. Validates that the task doesn't already exist
  3. Creates the task folder at {project}/.automaton/tasks/{task-name}/
  4. Writes .state with content new\n (not research — the task starts as new and transitions to research via --transition research)
  5. Creates .state.approvals as an empty file
  6. Outputs: "Created task '{task-name}' in state 'new'. Use --transition research to begin."

This replaces manual mkdir task creation.

--validate-folder and --audit checks: A task folder without .state was created manually and is flagged as a violation:

Task: fix-broken-thing
Phase: unknown (no .state file found)
Folder validation: FAIL — task was created manually (no .state file). Use 'python ~/.automaton/scripts/status.py --create-task' to create tasks properly.

6. Validation on transition

When transitioning, the script must verify:

  • The required artifact for the CURRENT phase exists and is non-empty
    • research → SPEC.md must exist and be non-empty
    • decomposition → DECOMPOSITION.md must exist and be non-empty
    • design → DESIGN.md must exist and be non-empty
    • test_design → TEST_PLAN.md must exist and be non-empty
    • implement → IMPLEMENTATION.md must exist and be non-empty
    • bug_find → BUG_REPORT.md must exist and be non-empty
    • adversarial_bug_find → ADVERSARIAL_BUG_REPORT.md must exist and be non-empty
    • doc_review → DOC_REVIEW.md must exist and be non-empty
    • referee → VERDICT.md must exist and be non-empty
  • If validation fails, output an error and refuse the transition

7. List command

python ~/.automaton/scripts/status.py --list [--project {project-path}]

Lists all tasks in the project with their current phase:

Task                     Phase               Next Step
add-user-auth            research             design or implement
fix-login-bug            implement            bug_find
add-payment-api          complete             —

8. Project path resolution

  • --project defaults to current working directory
  • Task folders are looked up in {project}/.automaton/tasks/
  • If running from ~/.automaton/, use ~/.automaton/tasks/
  • Sub-tasks are listed under their parent task with indentation

9. Sub-task support

python ~/.automaton/scripts/status.py --task parent-task/subtask-a --project {project-path}

For sub-tasks:

  • Look up the task at {project}/.automaton/tasks/{parent-task}/subtasks/{subtask}/
  • Read .state from the sub-task folder
  • Report parent context in output

10. Validate-folder command

python ~/.automaton/scripts/status.py --validate-folder --task {task-name} [--project {project-path}]

Checks that the task folder does not contain artifacts from phases that haven't been reached yet. This detects phase-skipping violations — if an agent jumps ahead and creates IMPLEMENTATION.md during research, --validate-folder catches it.

Phase-to-forbidden-artifacts mapping (artifacts from future phases):

Phase Forbidden artifacts (must NOT exist)
new SPEC.md, DESIGN.md, DECOMPOSITION.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
research DESIGN.md, DECOMPOSITION.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
decomposition DESIGN.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
design DECOMPOSITION.md, TEST_PLAN.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
test_design DECOMPOSITION.md, IMPLEMENTATION.md, BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
implement BUG_REPORT.md, ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
bug_find ADVERSARIAL_BUG_REPORT.md, DOC_REVIEW.md, VERDICT.md
adversarial_bug_find DOC_REVIEW.md, VERDICT.md
doc_review VERDICT.md
referee (none — all artifacts allowed)
complete (none — all artifacts allowed)
human_intervention (none — all artifacts allowed)

Note: Non-artifact files (.state, VRAM_CONFIG.md, PARENT_SPEC.md, REVIEW.md) are never flagged as forbidden — they are metadata, not phase deliverables.

Output on success:

Task: add-user-auth
Phase: research (from .state)
Folder validation: PASS — no out-of-order artifacts found

Output on violation:

Task: add-user-auth
Phase: research (from .state)
Folder validation: FAIL — found out-of-order artifacts:
  - IMPLEMENTATION.md (belongs to implement phase, not yet reached)
  - BUG_REPORT.md (belongs to bug_find phase, not yet reached)
These artifacts indicate phase-skipping. The task is in research phase but has artifacts from future phases.
Remove the out-of-order artifacts or revert to the correct phase.

11. Audit command

python ~/.automaton/scripts/status.py --audit [--project {project-path}]

Runs a comprehensive audit across ALL tasks in the project. This is a deeper check than --validate-folder — it checks for three categories of violations:

Category 1: Out-of-order artifacts (same as --validate-folder, applied to all tasks)

  • Checks each task folder for artifacts from future phases
  • Reports each violation with the task name, current phase, and offending artifacts

Category 2: State-artifact inconsistency

  • Checks that .state matches the artifacts actually present
  • If .state says "implement" but only SPEC.md exists (no IMPLEMENTATION.md), the state may be wrong
  • If .state says "research" but IMPLEMENTATION.md exists, the state was likely not updated after a skip
  • Reports each inconsistency with a suggested correction

Category 3: Unauthorized modifications (requires git)

  • If the project is a git repo, checks whether source code files were modified during a non-implement phase
  • Compares file modification timestamps (from git log) against .state transition times (from .state file mtime)
  • If code was edited when .state says "research" or "design", flags it as a violation
  • If no git repo is found, skip this check and note it in the output

Output format:

Audit Report for /path/to/project

=== Category 1: Out-of-order Artifacts ===
[PASS] add-user-auth: no violations
[FAIL] fix-login-bug (phase: research): found IMPLEMENTATION.md (implement phase artifact)
[PASS] add-payment-api: no violations

=== Category 2: State-Artifact Inconsistency ===
[PASS] add-user-auth: .state ("research") matches artifacts (SPEC.md exists)
[WARN] fix-login-bug: .state says "research" but IMPLEMENTATION.md exists — suggested correction: implement
[PASS] add-payment-api: .state ("complete") matches all artifacts

=== Category 3: Unauthorized Modifications ===
Skipped: not a git repository
— OR —
[PASS] add-user-auth: no code modifications outside implement phase
[FAIL] fix-login-bug: src/auth.py was modified during research phase (state: research, file mtime: 2026-06-14)

=== Summary ===
3 tasks audited
2 violations found
  - fix-login-bug: out-of-order artifact (IMPLEMENTATION.md)
  - fix-login-bug: state-artifact mismatch (.state says research, IMPLEMENTATION.md exists)
  - fix-login-bug: unauthorized modification (src/auth.py during research phase)

Exit codes:

  • 0: No violations found
  • 1: Violations found (useful for CI integration)
  • 2: Error (task not found, corrupted .state, etc.)

12. Error handling

  • Task not found: output "ERROR: Task '{task-name}' not found in {project}/.automaton/tasks/"
  • .state file corrupted (contains unknown phase): output "ERROR: Unknown phase '{phase}' in .state file"
  • Illegal transition: output "ERROR: Cannot transition from '{current}' to '{target}'. Legal transitions from '{current}' are: {list}"
  • Missing artifact on transition: output "ERROR: Cannot transition from '{current}' to '{target}'. Required artifact '{artifact}' is missing or empty in task folder."
  • Out-of-order artifact on transition: output "ERROR: Cannot transition from '{current}' to '{target}'. Found forbidden artifact '{artifact}' in task folder. This indicates phase-skipping. Remove the artifact or revert to the correct phase."

13. Transition validation with folder check

When --transition is called, it must ALSO run the --validate-folder check before allowing the transition:

  • If the task folder contains forbidden artifacts for the current phase, the transition is REFUSED
  • This prevents transitioning past a phase-skipping violation
  • The error message identifies the forbidden artifacts and suggests corrective action
  • This is in ADDITION to the existing artifact validation (required artifact must exist)

Example:

$ python ~/.automaton/scripts/status.py --task fix-login-bug --transition implement
ERROR: Cannot transition to implement phase. Found out-of-order artifacts:
  - BUG_REPORT.md (belongs to bug_find phase)
Remove out-of-order artifacts before transitioning.

Acceptance Criteria

  • status.py exists in ~/.automaton/scripts/
  • --task flag shows current phase (including approval sub-states), allowed actions, forbidden actions, next artifact, next phase
  • --task shows approval status for phases with :awaiting_approval or :approved sub-states
  • --transition flag validates and writes .state transitions (including approval sub-states)
  • --transition refuses transition from :awaiting_approval to anything other than :approved
  • --transition refuses transition past :awaiting_approval without approval
  • --approve command transitions :awaiting_approval to :approved
  • --approve refuses if current phase is not :awaiting_approval
  • --approve records approval in .state.approvals log
  • --approve refuses for phases that don't require approval
  • --create-task creates task folder with .state = new and empty .state.approvals
  • --create-task validates kebab-case task names
  • --create-task refuses if task already exists
  • --transition refuses transition if forbidden artifacts exist in task folder
  • --transition refuses transition if required artifact is missing or empty
  • --list flag shows all tasks with their current phase and approval status
  • --validate-folder flag checks for out-of-order artifacts per phase
  • --validate-folder flags task folders without .state as manually created
  • --validate-folder uses the phase-to-forbidden-artifacts mapping
  • --validate-folder excludes non-artifact files (.state, .state.approvals, VRAM_CONFIG.md, PARENT_SPEC.md, REVIEW.md)
  • --audit flag runs all categories of checks across all tasks
  • --audit Category 1: out-of-order artifacts per phase
  • --audit Category 2: state-artifact inconsistency (including approval sub-states)
  • --audit Category 3: unauthorized git modifications (with graceful skip if no git repo)
  • --audit Category 4: manually created task folders (no .state file)
  • --audit outputs structured report with exit codes (0=clean, 1=violations, 2=error)
  • Fallback to artifact heuristic when .state doesn't exist
  • Atomic writes for .state file
  • Approval log (.state.approvals) is created and maintained
  • Transition validation (only legal transitions allowed, including approval sub-states)
  • Clear error messages for invalid states, illegal transitions, missing artifacts, out-of-order artifacts, approval violations
  • Sub-task support (reading .state from sub-task folder)
  • Project path resolution (defaults to CWD, handles ~/.automaton/)
  • Tests in tests/test_status.py

14. Tool integration hooks (OPTIONAL — not required for v1)

These commands are designed for agent tool integrations (opencode skills, Cursor rules, Aider hooks, etc.) that want to enforce workflow rules at the tool-action level. They are not required for the framework to function — all enforcement in v1 is prompt-based plus status.py checks. Tool integration is a future configurable layer that an agent tool can opt into.

--can-edit — Pre-edit hook

python ~/.automaton/scripts/status.py --can-edit --task {task-name} [--project {project-path}]

Returns whether code edits are allowed for the task's current phase:

  • Exit code 0 + "ALLOWED" if the current phase allows code edits (implement, doc_review)
  • Exit code 1 + "DENIED: Task '{task-name}' is in {phase} phase. Code edits require implement or doc_review phase." if not

Agent tools can call this before allowing a file edit. If the tool supports pre-action hooks, it can block edits that don't pass this check. This is opt-in — without tool integration, this check is advisory (the FORBIDDEN section in phase prompts).

--can-create-task — Pre-task-creation hook

python ~/.automaton/scripts/status.py --can-create-task [--project {project-path}]

Returns whether a new task can be created. Always returns ALLOWED — this hook exists for tool integrations that want to gate task creation through the tool layer rather than relying on prompts.

--scope-check — Scope confinement hook

python ~/.automaton/scripts/status.py --scope-check --task {task-name} --file {file-path} [--project {project-path}]

Returns whether the given file path is within the project's scope:

  • Exit code 0 + "IN_SCOPE" if {file-path} is within {project}/ or ~/.automaton/
  • Exit code 1 + "OUT_OF_SCOPE: File '{file-path}' is outside project '{project}'." if not

Agent tools can call this before allowing file reads/writes to enforce scope confinement. This is opt-in — without tool integration, scope confinement is advisory (the .rules.md rule).

--same-session — Session discipline hook

python ~/.automaton/scripts/status.py --same-session --task {task-name} [--project {project-path}]

Returns whether the task was created in the current session (heuristically determined by comparing task creation time with a session marker):

  • If tasks/{task-name}/.state was created within the last N minutes (configurable, default 30), returns "SAME_SESSION" with exit code 1
  • Otherwise returns "DIFFERENT_SESSION" with exit code 0

This is a best-effort heuristic — it cannot reliably determine sessions across agent restarts. It's opt-in and should not be the sole enforcement for session discipline.

Configuration

Tool integration hooks are always available in status.py but are not called by any framework prompts in v1. To activate tool-level enforcement, the agent tool configuration (e.g., opencode skills, Cursor rules) should:

  1. Call --can-edit before allowing file edits and block if DENIED
  2. Call --scope-check before allowing file access outside the project
  3. Call --can-create-task is a no-op in v1 (always ALLOWED) but reserved for future use

No configuration file is needed — the hooks are available on demand. The framework does not require them.

Acceptance Criteria

  • status.py exists in ~/.automaton/scripts/
  • --task flag shows current phase (including approval sub-states), allowed actions, forbidden actions, next artifact, next phase
  • --task shows approval status for phases with :awaiting_approval or :approved sub-states
  • --transition flag validates and writes .state transitions (including approval sub-states)
  • --transition refuses transition from :awaiting_approval to anything other than :approved
  • --transition refuses transition past :awaiting_approval without approval
  • --approve command transitions :awaiting_approval to :approved
  • --approve refuses if current phase is not :awaiting_approval
  • --approve records approval in .state.approvals log
  • --approve refuses for phases that don't require approval
  • --create-task creates task folder with .state = new and empty .state.approvals
  • --create-task validates kebab-case task names
  • --create-task refuses if task already exists
  • --transition refuses transition if forbidden artifacts exist in task folder
  • --transition refuses transition if required artifact is missing or empty
  • --list flag shows all tasks with their current phase and approval status
  • --validate-folder flag checks for out-of-order artifacts per phase
  • --validate-folder flags task folders without .state as manually created
  • --validate-folder uses the phase-to-forbidden-artifacts mapping
  • --validate-folder excludes non-artifact files (.state, .state.approvals, VRAM_CONFIG.md, PARENT_SPEC.md, REVIEW.md)
  • --audit flag runs all categories of checks across all tasks
  • --audit Category 1: out-of-order artifacts per phase
  • --audit Category 2: state-artifact inconsistency (including approval sub-states)
  • --audit Category 3: unauthorized git modifications (with graceful skip if no git repo)
  • --audit Category 4: manually created task folders (no .state file)
  • --audit outputs structured report with exit codes (0=clean, 1=violations, 2=error)
  • --can-edit returns ALLOWED/DENIED based on current phase (optional, for tool integration)
  • --can-create-task returns ALLOWED (optional, reserved for future tool integration)
  • --scope-check returns IN_SCOPE/OUT_OF_SCOPE (optional, for tool integration)
  • --same-session returns SAME_SESSION/DIFFERENT_SESSION heuristic (optional, for tool integration)
  • Fallback to artifact heuristic when .state doesn't exist
  • Atomic writes for .state file
  • Approval log (.state.approvals) is created and maintained
  • Transition validation (only legal transitions allowed, including approval sub-states)
  • Clear error messages for invalid states, illegal transitions, missing artifacts, out-of-order artifacts, approval violations
  • Sub-task support (reading .state from sub-task folder)
  • Project path resolution (defaults to CWD, handles ~/.automaton/)
  • Tests in tests/test_status.py

Non-Goals

  • This spec does not cover prompt restructuring (separate task)
  • This spec does not cover autopilot integration (separate task)
  • This spec does not cover dashboard integration (future work)
  • Tool integration hooks are implemented in v1 but are optional and not called by any framework prompt