Consolidate task location: always .automaton/tasks/

Both framework and project tasks now live in .automaton/tasks/.
Every project has a .automaton/ directory, so no need for special
scope-based path logic. Removed the dual-convention gap.

Changes:
- Dashboard _find_tasks_dir() and _get_review_path() always use
  {root}/.automaton/tasks/ — no scope branching
- migrate-project.sh: moves tasks/ -> .automaton/tasks/ during upgrade
- Orchestrator prompt: all task path references updated to
  {project}/.automaton/tasks/
This commit is contained in:
2026-06-13 21:37:13 -04:00
parent 741364654c
commit 7c8c606d73
4 changed files with 25 additions and 58 deletions
+3 -26
View File
@@ -106,24 +106,8 @@ class DashboardHandler(SimpleHTTPRequestHandler):
@staticmethod @staticmethod
def _find_tasks_dir(project_root: Path) -> Path | None: def _find_tasks_dir(project_root: Path) -> Path | None:
from ..core.scope import detect_scope tasks_dir = project_root / ".automaton" / "tasks"
_, scope = detect_scope() return tasks_dir if tasks_dir.exists() else tasks_dir
# 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]
def _serve_tasks(self): def _serve_tasks(self):
project_root = find_automaton_root() project_root = find_automaton_root()
@@ -220,14 +204,7 @@ class DashboardHandler(SimpleHTTPRequestHandler):
project_root = find_automaton_root() project_root = find_automaton_root()
if not project_root or not self._validate_task_name(task_name): if not project_root or not self._validate_task_name(task_name):
return None return None
candidates = [ return project_root / ".automaton" / "tasks" / task_name / self.REVIEW_FILE
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]
def _get_review_status(self, task_name: str) -> dict: def _get_review_status(self, task_name: str) -> dict:
review_path = self._get_review_path(task_name) review_path = self._get_review_path(task_name)
+9 -21
View File
@@ -19,7 +19,7 @@ Specifically:
7. {project}/.automaton/extensions/contracts/*.md — Additive extensions loaded after global contracts 7. {project}/.automaton/extensions/contracts/*.md — Additive extensions loaded after global contracts
8. ~/.automaton/scripts/*.sh — Always from global framework 8. ~/.automaton/scripts/*.sh — Always from global framework
9. {project}/.automaton/extensions/scripts/*.sh — Additive extensions loaded before global scripts (pre-processing) 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 ## VRAM Detection
@@ -193,7 +193,7 @@ while task is not in terminal state:
#### Continue from existing tasks #### Continue from existing tasks
If the user says "orchestrate" or "continue" with no new task description, the Orchestrator should: 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) 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 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 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 #### New tasks from user input
If {task-description} contains a description for a NEW task, the Orchestrator MUST: 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`) 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: 2. Create the task folder at `{project}/.automaton/tasks/{task-name}/` (empty — no artifact files)
- **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.
3. **Immediately drive it to completion** using the auto-execution loop 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. 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 ## State Determination
Examine the tasks/ directory and determine the state of each task folder. The tasks directory is: 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.
- **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.
1. Has `VERDICT.md` with `PASS` (non-empty) → **Complete** 1. Has `VERDICT.md` with `PASS` (non-empty) → **Complete**
2. Has `VERDICT.md` with `NEEDS_REVIEW` or `FAIL` (non-empty) → **Human Intervention** 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 ### 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 SPEC.md
DECOMPOSITION.md DECOMPOSITION.md
subtasks/ subtasks/
subtask-a/ → Sub-task (full lifecycle independently) 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-b/ 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**: 5. **Verify VRAM constraints**:
- For each sub-task, check if its estimated peak context (from DECOMPOSITION.md) is within the max peak context. - 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. - 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: 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 new sub-tasks, create the folders.
- For removed sub-tasks, report the orphaned sub-tasks and delete 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). - 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. - 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). 9. **Create a VRAM_CONFIG.md** file for each sub-task with the VRAM configuration (see VRAM Config Propagation section).
+12 -10
View File
@@ -107,16 +107,18 @@ while IFS= read -r -d '' project_file; do
fi fi
done < <(find "$PROJECT_AUTOMATON" -maxdepth 1 -type f -name "*.md" -o -name "*.sh" -print0 2>/dev/null || true) 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/ # Task directory — tasks always live in .automaton/tasks/ for all modes
OLD_TASKS="$PROJECT_AUTOMATON/tasks" ROOT_TASKS="$PROJECT_DIR/tasks"
NEW_TASKS="$PROJECT_DIR/tasks" AUTOMATON_TASKS="$PROJECT_AUTOMATON/tasks"
if [ -d "$OLD_TASKS" ] && [ ! -e "$NEW_TASKS" ]; then if [ -d "$ROOT_TASKS" ] && [ ! -e "$AUTOMATON_TASKS" ]; then
echo " MOVING .automaton/tasks/ → tasks/ (tasks should be at project root)" echo " MOVING tasks/ → .automaton/tasks/ (tasks belong in .automaton/)"
mv "$OLD_TASKS" "$NEW_TASKS" mv "$ROOT_TASKS" "$AUTOMATON_TASKS"
MOVED+=(".automaton/tasks/ -> tasks/") MOVED+=("tasks/ -> .automaton/tasks/")
elif [ -d "$OLD_TASKS" ] && [ -d "$NEW_TASKS" ]; then elif [ -d "$ROOT_TASKS" ] && [ -d "$AUTOMATON_TASKS" ]; then
echo " NOTICE Both .automaton/tasks/ and tasks/ exist — keeping both" echo " MERGING tasks/ contents into .automaton/tasks/"
KEPT+=(".automaton/tasks/ and tasks/") cp -r "$ROOT_TASKS"/* "$AUTOMATON_TASKS/" 2>/dev/null || true
rm -rf "$ROOT_TASKS"
MOVED+=("tasks/ merged -> .automaton/tasks/")
fi fi
# Report # Report