diff --git a/automaton/dashboard/ui/__pycache__/app.cpython-314.pyc b/automaton/dashboard/ui/__pycache__/app.cpython-314.pyc index 2aa5b26..810391e 100644 Binary files a/automaton/dashboard/ui/__pycache__/app.cpython-314.pyc and b/automaton/dashboard/ui/__pycache__/app.cpython-314.pyc differ diff --git a/automaton/dashboard/ui/app.py b/automaton/dashboard/ui/app.py index c823f6e..da28e5e 100644 --- a/automaton/dashboard/ui/app.py +++ b/automaton/dashboard/ui/app.py @@ -106,24 +106,8 @@ class DashboardHandler(SimpleHTTPRequestHandler): @staticmethod def _find_tasks_dir(project_root: Path) -> Path | None: - from ..core.scope import detect_scope - _, scope = detect_scope() - # Framework mode: tasks live inside .automaton/ - # Project mode: tasks live at project root, .automaton/tasks/ may be a symlink - if scope == "framework": - candidates = [ - project_root / ".automaton" / "tasks", - project_root / "tasks", - ] - else: - candidates = [ - project_root / "tasks", - project_root / ".automaton" / "tasks", - ] - for p in candidates: - if p.exists() and p.is_dir(): - return p - return candidates[0] + tasks_dir = project_root / ".automaton" / "tasks" + return tasks_dir if tasks_dir.exists() else tasks_dir def _serve_tasks(self): project_root = find_automaton_root() @@ -220,14 +204,7 @@ class DashboardHandler(SimpleHTTPRequestHandler): project_root = find_automaton_root() if not project_root or not self._validate_task_name(task_name): return None - candidates = [ - project_root / ".automaton" / "tasks" / task_name / self.REVIEW_FILE, - project_root / "tasks" / task_name / self.REVIEW_FILE, - ] - for p in candidates: - if p.exists(): - return p - return candidates[0] + return project_root / ".automaton" / "tasks" / task_name / self.REVIEW_FILE def _get_review_status(self, task_name: str) -> dict: review_path = self._get_review_path(task_name) diff --git a/prompts/orchestrate.md b/prompts/orchestrate.md index 657aca4..cd9c7ec 100644 --- a/prompts/orchestrate.md +++ b/prompts/orchestrate.md @@ -19,7 +19,7 @@ Specifically: 7. {project}/.automaton/extensions/contracts/*.md — Additive extensions loaded after global contracts 8. ~/.automaton/scripts/*.sh — Always from global framework 9. {project}/.automaton/extensions/scripts/*.sh — Additive extensions loaded before global scripts (pre-processing) -10. {project}/tasks/ — Project tasks (project mode) or ~/.automaton/tasks/ (framework mode) +10. {project}/.automaton/tasks/ — Task folders (both framework and project mode) ## VRAM Detection @@ -193,7 +193,7 @@ while task is not in terminal state: #### Continue from existing tasks If the user says "orchestrate" or "continue" with no new task description, the Orchestrator should: -1. Scan all tasks in the tasks/ directory, including sub-task folders under `tasks/{parent-task}/subtasks/` +1. Scan all tasks in `{project}/.automaton/tasks/`, including sub-task folders under `{project}/.automaton/tasks/{parent-task}/subtasks/` 2. Find the most advanced task (the one closest to completion) — **prioritize sub-tasks over parent tasks** (because the parent depends on the sub-tasks) 3. When choosing among sub-tasks in the same wave, prioritize those in later phases (e.g., Bug Find over Research) because they are closer to completion 4. Drive that task through the remaining phases @@ -201,10 +201,7 @@ If the user says "orchestrate" or "continue" with no new task description, the O #### New tasks from user input If {task-description} contains a description for a NEW task, the Orchestrator MUST: 1. Generate a kebab-case task name from the description (e.g., "add user auth" → `add-user-auth`) -2. Create the task folder. Task location depends on scope: - - **Framework mode** (inside ~/.automaton/): `~/.automaton/tasks/{task-name}/` - - **Project mode** (in a user project): `{project}/tasks/{task-name}/` - The dashboard reads from both locations automatically. +2. Create the task folder at `{project}/.automaton/tasks/{task-name}/` (empty — no artifact files) 3. **Immediately drive it to completion** using the auto-execution loop Note: `IMPLEMENTATION.md` is the artifact produced by the implementation phase, not the Orchestrator. Do not pre-create it. **Do not create an empty `IMPLEMENTATION.md` for new tasks** — this is inconsistent with the Orchestrator's own rule and can confuse the Research phase. @@ -240,9 +237,7 @@ In manual mode, the Orchestrator only **reports** the current state and the next ## State Determination -Examine the tasks/ directory and determine the state of each task folder. The tasks directory is: -- **Framework mode**: `~/.automaton/tasks/` -- **Project mode**: `{project}/tasks/` Check from the most advanced state backward. **Important**: Always check that artifacts are non-empty before considering them as indicators of task state. +Examine the `{project}/.automaton/tasks/` directory and determine the state of each task folder. Check from the most advanced state backward. **Important**: Always check that artifacts are non-empty before considering them as indicators of task state. 1. Has `VERDICT.md` with `PASS` (non-empty) → **Complete** 2. Has `VERDICT.md` with `NEEDS_REVIEW` or `FAIL` (non-empty) → **Human Intervention** @@ -325,23 +320,16 @@ When a parent task has a `DECOMPOSITION.md` file, the Orchestrator must create s ### Sub-Task Folder Structure -When decomposing, the Orchestrator creates sub-tasks under the parent task's `subtasks/` folder: +When decomposing, the Orchestrator creates sub-tasks under the parent task's `subtasks/` folder inside `{project}/.automaton/tasks/`: ``` -tasks/parent-task/ → Parent task (Research → Decomposition → complete) +{project}/.automaton/tasks/parent-task/ → Parent task (Research → Decomposition → complete) SPEC.md DECOMPOSITION.md subtasks/ - subtask-a/ → Sub-task (full lifecycle independently) - SPEC.md - DESIGN.md - IMPLEMENTATION.md - BUG_REPORT.md - ADVERSARIAL_BUG_REPORT.md - DOC_REVIEW.md - VERDICT.md + subtask-a/ → Sub-task (full lifecycle independently) + ... subtask-b/ - SPEC.md ... ``` @@ -356,11 +344,11 @@ When a parent task reaches the **Decomposition** phase (has `SPEC.md` and `DECOM 5. **Verify VRAM constraints**: - For each sub-task, check if its estimated peak context (from DECOMPOSITION.md) is within the max peak context. - If a sub-task exceeds the VRAM limit, create a warning and suggest splitting it further. -6. **Check for existing sub-task folders**: For each sub-task, check if the folder `tasks/{parent-task-name}/subtasks/{sub-task-name}/` already exists. If it does, skip the creation and report that the sub-task has already been created. This prevents duplicate sub-tasks when the Orchestrator is invoked multiple times. +6. **Check for existing sub-task folders**: For each sub-task, check if the folder `{project}/.automaton/tasks/{parent-task-name}/subtasks/{sub-task-name}/` already exists. If it does, skip the creation and report that the sub-task has already been created. This prevents duplicate sub-tasks when the Orchestrator is invoked multiple times. 7. **Check for DECOMPOSITION.md updates**: Compare the DECOMPOSITION.md with the existing sub-task folders. If the DECOMPOSITION.md has been updated (new sub-tasks added or existing sub-tasks removed), update the sub-task folders accordingly: - For new sub-tasks, create the folders. - For removed sub-tasks, report the orphaned sub-tasks and delete the folders. -8. **Create sub-task folders** under `tasks/{parent-task-name}/subtasks/{sub-task-name}/`: +8. **Create sub-task folders** under `{project}/.automaton/tasks/{parent-task-name}/subtasks/{sub-task-name}/`: - For each sub-task, create an empty folder (no files yet — the sub-task starts at the Research phase). - The sub-task name should be a kebab-case version of the sub-task description from DECOMPOSITION.md. 9. **Create a VRAM_CONFIG.md** file for each sub-task with the VRAM configuration (see VRAM Config Propagation section). diff --git a/scripts/migrate-project.sh b/scripts/migrate-project.sh index 7554bb7..5982eb7 100755 --- a/scripts/migrate-project.sh +++ b/scripts/migrate-project.sh @@ -107,16 +107,18 @@ while IFS= read -r -d '' project_file; do fi done < <(find "$PROJECT_AUTOMATON" -maxdepth 1 -type f -name "*.md" -o -name "*.sh" -print0 2>/dev/null || true) -# Task directory — old model stored tasks in .automaton/tasks/, new model uses tasks/ -OLD_TASKS="$PROJECT_AUTOMATON/tasks" -NEW_TASKS="$PROJECT_DIR/tasks" -if [ -d "$OLD_TASKS" ] && [ ! -e "$NEW_TASKS" ]; then - echo " MOVING .automaton/tasks/ → tasks/ (tasks should be at project root)" - mv "$OLD_TASKS" "$NEW_TASKS" - MOVED+=(".automaton/tasks/ -> tasks/") -elif [ -d "$OLD_TASKS" ] && [ -d "$NEW_TASKS" ]; then - echo " NOTICE Both .automaton/tasks/ and tasks/ exist — keeping both" - KEPT+=(".automaton/tasks/ and tasks/") +# Task directory — tasks always live in .automaton/tasks/ for all modes +ROOT_TASKS="$PROJECT_DIR/tasks" +AUTOMATON_TASKS="$PROJECT_AUTOMATON/tasks" +if [ -d "$ROOT_TASKS" ] && [ ! -e "$AUTOMATON_TASKS" ]; then + echo " MOVING tasks/ → .automaton/tasks/ (tasks belong in .automaton/)" + mv "$ROOT_TASKS" "$AUTOMATON_TASKS" + MOVED+=("tasks/ -> .automaton/tasks/") +elif [ -d "$ROOT_TASKS" ] && [ -d "$AUTOMATON_TASKS" ]; then + echo " MERGING tasks/ contents into .automaton/tasks/" + cp -r "$ROOT_TASKS"/* "$AUTOMATON_TASKS/" 2>/dev/null || true + rm -rf "$ROOT_TASKS" + MOVED+=("tasks/ merged -> .automaton/tasks/") fi # Report