From 52dcf8e3097512cce26ee0c75452c7c25b25c678 Mon Sep 17 00:00:00 2001 From: laptran Date: Sat, 13 Jun 2026 12:26:27 -0400 Subject: [PATCH] Implement all 5 tasks: additive extension model, framework self-enforcement, changelog, project migration, dashboard review --- .onboarding.md | 7 +- .rules.md | 19 +++- CHANGELOG.md | 18 ++++ README.md | 22 +++-- automaton/dashboard/html/dashboard.js | 47 +++++++++- automaton/dashboard/html/index.html | 10 +++ automaton/dashboard/html/styles.css | 13 +++ automaton/dashboard/ui/app.py | 96 +++++++++++++++++++- prompts/onboarding.md | 89 +++++------------- prompts/orchestrate.md | 13 +-- references/session-starter.md | 5 +- scripts/migrate-project.sh | 125 ++++++++++++++++++++++++++ scripts/update.sh | 22 +---- system-prompt.md | 5 +- tasks/dashboard-toggle/REVIEW.md | 4 + 15 files changed, 380 insertions(+), 115 deletions(-) create mode 100644 CHANGELOG.md create mode 100755 scripts/migrate-project.sh create mode 100644 tasks/dashboard-toggle/REVIEW.md diff --git a/.onboarding.md b/.onboarding.md index b2e64e9..c56ce4a 100644 --- a/.onboarding.md +++ b/.onboarding.md @@ -9,9 +9,10 @@ The agent's first task in any project is to perform an "Initial Exploration" to ### Step 1: Discovery The agent must: 1. Explore the project root using `ls` and `find`. -2. Read `.automaton/.agent.md` -3. Read `.automaton/.rules.md` -4. Read the global `~/.automaton/.agent.md` +2. Read ~/.automaton/.agent.md (global router) +3. Read ~/.automaton/.rules.md (global framework rules) +4. Read the project's `.automaton/.agent.md` +5. Read the project's `.automaton/.rules.md` ### Step 2: Reporting The agent must report back with: diff --git a/.rules.md b/.rules.md index e9ba2a2..e72a682 100644 --- a/.rules.md +++ b/.rules.md @@ -1,5 +1,20 @@ # .rules.md -- Add one rule per observed failure mode with a concrete example. +## Task-Driven Development +- All changes must go through a task in tasks/{name}/ with SPEC.md → phases → VERDICT.md +- Never edit files directly without a corresponding task +- Never create task directories manually (mkdir tasks/) — use the Orchestrator instead + +## VRAM-Aware Task Sizing +- Before creating or scoping a task, check ~/.automaton/config.md for VRAM limits +- Verify the task fits within max peak context (default: 12k tokens) +- If no config exists, default to 8k with 25% headroom + +## Changelog +- When a task reaches Resolution (VERDICT.md written), append an entry to CHANGELOG.md +- Use the format: `- description (#task-name)` under the appropriate [unreleased] section + +## Self-Improvement +- Add one rule per observed failure mode with a concrete example - Consolidate contradictions monthly. Remove stale rules. -- No rule without a real example of the problem it prevents. \ No newline at end of file +- No rule without a real example of the problem it prevents diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7ca4940 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog + +## [unreleased] + +### Added +- Blocked phase column between Verification and Resolution on dashboard (#additive-extension-model) +- Framework self-enforcement rules in .rules.md and system-prompt.md (#framework-self-enforcement) +- Additive extension model: projects extend via extensions/ dir, never copy framework files (#additive-extension-model) +- CHANGELOG.md for release notes tracking (#changelog) +- Framework audit: comprehensive self-consistency check with RESEARCH.md (#framework-audit) + +### Changed +- prompts/orchestrate.md: always reads prompts/contracts/scripts from global, project extensions are additive (#additive-extension-model) +- prompts/onboarding.md: removed diff/merge upgrade, replaced with migration check (#additive-extension-model) +- README.md: updated upgrade docs for new additive model (#additive-extension-model) +- scripts/update.sh: simplified to plain git pull (#additive-extension-model) +- .rules.md: converted from template to concrete rules with Task-Driven Development, VRAM-aware sizing, Changelog, and Self-Improvement sections (#framework-self-enforcement) +- system-prompt.md: added instruction to read global .rules.md (#framework-self-enforcement) diff --git a/README.md b/README.md index 400b88e..679123a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,9 @@ This will: - Check for uncommitted changes and warn you - Pull the latest updates -**Upgrading existing projects:** When the framework is updated, existing projects may need their framework files upgraded (new phases added, new prompts, etc.). To upgrade an existing project, tell the agent: "Upgrade automaton for this project." The agent will check for missing files and update them. +**Upgrading existing projects:** The framework reads prompts, contracts, and scripts from `~/.automaton/` at runtime. Projects only override `.agent.md` and `.rules.md`. This means updating the global framework (`git pull`) automatically applies to all projects. No per-project upgrade is needed. + +If a project was set up under the old model (with copies of framework files), it needs migration first. Tell the agent: "Upgrade automaton for this project" to run the migration. --- @@ -185,21 +187,23 @@ The framework uses a **layered approach** to file management, with a clear prece ### What files belong in each layer? -- **Project's `.automaton/`**: .agent.md (project-specific settings like Autopilot mode, rules override), .rules.md (project-specific constraints) +- **Project's `.automaton/`**: .agent.md (project-specific settings like Autopilot mode, rules override), .rules.md (project-specific constraints), extensions/ (optional additive overrides) - **Global `~/.automaton/`**: All prompt files, contracts, scripts, config.md, workflow.md ### Upgrading -When you upgrade the global framework (e.g., after pushing bug fixes), existing projects may need their framework files upgraded. Tell the agent: +The framework reads all base files from `~/.automaton/` at runtime. To update the framework: +```bash +cd ~/.automaton && git pull +``` + +This automatically applies changes to all projects — no per-project upgrade needed. + +If a project has stale framework file copies (from the old model), tell the agent: > "Upgrade automaton for this project." -The agent will: -1. Compare the project's `.automaton/` files with the global `~/.automaton/` files -2. **Customized files** — If the project has customized a file (differs from global), **keep the project's version** -3. **Outdated files** — If the project's file is identical to the old global version, **update from global** -4. **New files** — If the global framework has new files, **add them to the project** -5. Report what was upgraded, added, and skipped +The agent will run `migrate-project.sh` to clean up stale files and move customizations to `extensions/`. ## Contact & Support [Insert Contact Info] diff --git a/automaton/dashboard/html/dashboard.js b/automaton/dashboard/html/dashboard.js index 22ac2ba..5cc114a 100644 --- a/automaton/dashboard/html/dashboard.js +++ b/automaton/dashboard/html/dashboard.js @@ -1,7 +1,7 @@ const state = { scope: 'none', currentView: 'board', theme: 'default', selectedTask: null, tasks: [], refreshCount: 0, autoRefresh: true, showWaves: true, - filterPhase: 'all', filterWave: 'all', searchQuery: '', filterVisible: false, + filterPhase: 'all', filterReview: 'all', filterWave: 'all', searchQuery: '', filterVisible: false, refreshInterval: null, projectName: null, }; @@ -77,6 +77,8 @@ function renderHeader() { wipTasks.textContent = filtered.filter(t => wipStates.includes(t.state)).length; doneTasks.textContent = filtered.filter(t => t.state === 'done').length; blockedTasks.textContent = filtered.filter(t => t.state === 'blocked').length; + const pendingReview = document.getElementById('pending-review'); + if (pendingReview) pendingReview.textContent = filtered.filter(t => !t.review || t.review.status === 'pending').length; // Project name display const projectName = state.projectName; if (projectName) { @@ -140,6 +142,10 @@ function renderTaskCard(task) { const statusClass = task.state === 'done' ? 'done' : task.state === 'blocked' ? 'blocked' : 'in_progress'; const statusIcon = task.state === 'done' ? '✅' : task.state === 'blocked' ? '❌' : '🔄'; const subLabel = getSubLabel(task.state); + const reviewStatus = task.review ? task.review.status : 'pending'; + const reviewBadge = reviewStatus === 'approved' ? '✅' + : reviewStatus === 'changes_requested' ? '❌' + : '🟡'; const progressHtml = task.sub_tasks.length > 0 ? `${task.sub_tasks.filter(st => st.has_verdict && st.verdict_status === 'PASS').length}/${task.sub_tasks.length}` : ''; @@ -151,7 +157,7 @@ function renderTaskCard(task) { }).join('')}` : ''; return `
-
${task.display_name}${statusIcon}
+
${task.display_name}${reviewBadge}${statusIcon}
${subLabel}
${progressHtml ? `` : ''} ${subtasksHtml} @@ -175,9 +181,20 @@ function renderDetail(task) { return `${icon}${col.label}`; }).join(''); const phaseGroupHtml = phaseGroup ? `${PHASE_GROUPS.find(g => g.id === phaseGroup).label}` : ''; + const reviewStatus = task.review ? task.review.status : 'pending'; + const reviewStatusText = reviewStatus === 'approved' ? '✅ Approved' : reviewStatus === 'changes_requested' ? '❌ Changes Requested' : '🟡 Pending Review'; + const reviewComment = task.review && task.review.comment ? `

${escapeHtml(task.review.comment)}

` : ''; content.innerHTML = `

Status

${statusText}${phaseGroupHtml}

Artifacts

${artifactsHtml}
+

Review

+ ${reviewStatusText} + ${reviewComment} +
+ + +
+
${task.sub_tasks.length > 0 ? `

Sub-tasks (${task.sub_tasks.filter(st => st.has_verdict).length}/${task.sub_tasks.length})

    ${task.sub_tasks.map(st => { const stStatus = st.has_verdict && st.verdict_status === 'PASS' ? 'pass' : st.has_verdict && st.verdict_status === 'FAIL' ? 'fail' : 'incomplete'; @@ -299,9 +316,34 @@ function renderTimeline() { panel.innerHTML = `

    Phase Legend:

    ${legend}
    ${itemsHtml}`; } +async function submitReview(taskName, status) { + const comment = prompt(status === 'changes_requested' ? 'Describe what changes are needed:' : 'Optional approval comment:'); + if (comment === null) return; + try { + const res = await fetch(`/api/task/${taskName}/review`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ status, comment }), + }); + const data = await res.json(); + if (data.success) { + await refreshData(); + const task = state.tasks.find(t => t.name === taskName); + if (task && task.name === (state.selectedTask && state.selectedTask.name)) { + renderDetail(task); + } + } + } catch (err) { + console.error('Review submission failed:', err); + } +} + function getFilteredTasks() { let filtered = [...state.tasks]; if (state.filterPhase !== 'all') filtered = filtered.filter(t => t.state === state.filterPhase); + if (state.filterReview === 'pending') filtered = filtered.filter(t => !t.review || t.review.status === 'pending'); + else if (state.filterReview === 'approved') filtered = filtered.filter(t => t.review && t.review.status === 'approved'); + else if (state.filterReview === 'changes_requested') filtered = filtered.filter(t => t.review && t.review.status === 'changes_requested'); if (state.filterWave === 'has-waves') filtered = filtered.filter(t => t.sub_tasks.length > 0); else if (state.filterWave === 'no-waves') filtered = filtered.filter(t => t.sub_tasks.length === 0); if (state.searchQuery) { @@ -374,6 +416,7 @@ function setupUI() { document.getElementById('btn-close-help').addEventListener('click', () => { document.getElementById('help-modal').classList.remove('open'); }); document.getElementById('btn-close-detail').addEventListener('click', closeDetail); document.getElementById('filter-phase').addEventListener('change', (e) => { state.filterPhase = e.target.value; renderCurrentView(); }); + document.getElementById('filter-review').addEventListener('change', (e) => { state.filterReview = e.target.value; renderCurrentView(); }); document.getElementById('filter-wave').addEventListener('change', (e) => { state.filterWave = e.target.value; renderCurrentView(); }); document.getElementById('search-input').addEventListener('input', (e) => { state.searchQuery = e.target.value; renderCurrentView(); }); } diff --git a/automaton/dashboard/html/index.html b/automaton/dashboard/html/index.html index c656a74..f1ba43d 100644 --- a/automaton/dashboard/html/index.html +++ b/automaton/dashboard/html/index.html @@ -26,6 +26,7 @@ WIP: 0 Done: 0 Blocked: 0 + Pending: 0
@@ -48,6 +49,15 @@
+
+ + +