From 95e14e634001ac28c9ac31d315120bf80e763646 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Mon, 1 Jun 2026 09:42:21 -0400 Subject: [PATCH] Show the recap on Review and the carry-forward on Planning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Review screen renders the reviewer's one-line recap (quiet pending line, then the recap); the Planning screen renders last session's carry-forward as a 'Last time: …' one-liner, mirroring the knowledge indicator. Updates the README Status section for M7. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 10 ++++++++++ internal/web/static/app.css | 1 + internal/web/static/app.js | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/README.md b/README.md index 9b5688f..ef66101 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,16 @@ go test ./... ## Status +M7 (reflection): when a session ends, a fourth AI role — the reviewer — +reflects on it, read against your recent sessions, and produces two short +lines: a recap shown on the Review screen, and a carry-forward takeaway that +grounds the coach the next time you plan. It runs once asynchronously on +entering Review, never blocks the End button, and degrades gracefully — with +no backend (or a slow/failed call) Review and Planning behave exactly as +before. The carry-forward is snapshot-persisted (latest-wins) and composes +into the coach's grounding; the reflection lines are short and cross the wire +by design, while the knowledge profile still does not. + M6 (knowledge port): the planning coach now sharpens intents against who you actually are. A single profile file (`~/.antidrift/knowledge.md`, overridable via `ANTIDRIFT_KNOWLEDGE_FILE`) holds your standing context — priorities, diff --git a/internal/web/static/app.css b/internal/web/static/app.css index d46e41f..8be65b2 100644 --- a/internal/web/static/app.css +++ b/internal/web/static/app.css @@ -119,6 +119,7 @@ input:focus { outline: 0; border-color: var(--accent); } /* Planning: standing-profile grounding indicator */ .knowline { opacity: 0.85; } +.reflectline { opacity: 0.85; } .link { background: none; border: none; padding: 0; font: inherit; font-size: 12px; color: var(--accent); cursor: pointer; text-decoration: underline; diff --git a/internal/web/static/app.js b/internal/web/static/app.js index 42376f3..8117ab2 100644 --- a/internal/web/static/app.js +++ b/internal/web/static/app.js @@ -179,6 +179,27 @@ function updatePlanningKnowledge(k) { }; } +// reflectionBlock renders the reviewer's recap on the Review screen. idle/nil or +// an empty recap renders nothing; pending shows a quiet line; ready shows the +// one-line recap. +function reflectionBlock(refl) { + if (!refl) return ''; + if (refl.status === 'pending') return `
reflecting…
`; + if (refl.status === 'ready' && refl.recap) { + return `
${refl.recap}
`; + } + return ''; +} + +// updatePlanningReflection renders last session's carry-forward takeaway as a +// quiet one-liner on the planning screen. Nothing renders without one. +function updatePlanningReflection(refl) { + const el = document.getElementById('reflectBand'); + if (!el) return; + if (!refl || !refl.carry_forward) { el.innerHTML = ''; return; } + el.innerHTML = `Last time: ${refl.carry_forward}`; +} + function render(state) { setStateAttr(state); const rs = state.runtime_state; @@ -186,6 +207,7 @@ function render(state) { updatePlanningCoach(state.coach); updatePlanningTasks(state.tasks); updatePlanningKnowledge(state.knowledge); + updatePlanningReflection(state.reflection); return; } if (rs === 'active' && renderedState === 'active') { @@ -213,6 +235,7 @@ function render(state) {
+
@@ -239,6 +262,7 @@ function render(state) { updatePlanningCoach(state.coach); updatePlanningTasks(state.tasks); updatePlanningKnowledge(state.knowledge); + updatePlanningReflection(state.reflection); } else if (rs === 'active') { const c = state.commitment || {}; @@ -265,6 +289,7 @@ function render(state) {

${c.next_action || ''}

done when: ${c.success_condition || ''}

+ ${reflectionBlock(state.reflection)} ${reviewSummary(state.evidence)}
`; document.getElementById('end').onclick = () => post('/end');