summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-02-05 10:37:09 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-02-05 10:37:09 -1000
commit223c94f52ebaa878f6951ebf7d08754e413bdca7 (patch)
treefc02a201fb83ec49fd5978d2ec9bf79f83e5d57c
parent4ac78382343e14c00ba21ee11ee4642255509eef (diff)
Document multi-agent workflow, ADRs, and Agent API
- Add Development Workflow section to DESIGN.md documenting three-role system (Architect, Implementor, Reviewer) with handoff documents - Update CLAUDE.md with Key Documents section pointing to DESIGN.md, role definitions, and ADRs - Add ADR-first documentation policy across all role definitions - Update REVIEWER_ROLE.md with comprehensive test quality checklist - Document Agent API and completed tasks log in DESIGN.md - Update database schema table with 5 missing tables - Update endpoint reference with 10 missing routes - Create ADRs 002-005 capturing key architectural decisions: - 002: Timeline aggregation architecture - 003: HTMX write operations pattern - 004: Concurrent data fetching with graceful degradation - 005: Agent API notification-based authentication - Add migrations/README.md documenting schema history and 007 gap Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
-rw-r--r--ARCHITECT_ROLE.md8
-rw-r--r--CLAUDE.md35
-rw-r--r--DESIGN.md177
-rw-r--r--IMPLEMENTOR_ROLE.md3
-rw-r--r--REVIEWER_ROLE.md26
-rw-r--r--docs/adr/002-timeline-aggregation.md76
-rw-r--r--docs/adr/003-htmx-write-operations.md85
-rw-r--r--docs/adr/004-concurrent-data-fetching.md104
-rw-r--r--docs/adr/005-agent-api-authentication.md95
-rw-r--r--migrations/README.md36
10 files changed, 618 insertions, 27 deletions
diff --git a/ARCHITECT_ROLE.md b/ARCHITECT_ROLE.md
index 233f157..409102d 100644
--- a/ARCHITECT_ROLE.md
+++ b/ARCHITECT_ROLE.md
@@ -12,9 +12,15 @@
**Gemini Architect Persona:**
* You are the **Lead Architect**.
* **Constraint:** You **DO NOT** write or edit Project Source Code (e.g., `.go`, `.html`, `.js`).
-* **Responsibility:** You **DO** write and update documentation and instruction files (e.g., `SESSION_STATE.md`, `instructions.md`, `issues/*.md`). Your job is to prepare surgical plans for the implementation agent (Claude Code) to execute and guide the Reviewer.
+* **Responsibility:** You **DO** write and update documentation and instruction files (e.g., `SESSION_STATE.md`, `instructions.md`, `issues/*.md`, `docs/adr/*.md`). Your job is to prepare surgical plans for the implementation agent (Claude Code) to execute and guide the Reviewer.
* **Constraint:** If the user rejects a proposed change, do NOT try again - IMMEDIATELY stop and ask for clarification from the user.
+**ADR-First Documentation:**
+* **Always create an ADR** for architectural decisions. Do NOT create one-off design documents.
+* ADRs capture context, decision, tradeoffs, and alternatives - they remain useful long after implementation.
+* Use `instructions.md` for ephemeral implementation details only.
+* See `DESIGN.md` → "Architecture Decision Records" for the template and current ADRs.
+
**Workflow Instructions:**
1. **Analyze:**
diff --git a/CLAUDE.md b/CLAUDE.md
index dbef146..c4834a5 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,9 +1,29 @@
# Claude Code Project Guidelines
## Project Overview
-A unified web dashboard aggregating Trello (PRIMARY), Todoist, Obsidian, and PlanToEat.
+A unified web dashboard aggregating Trello (PRIMARY), Todoist, Obsidian, and PlanToEat.
**Stack:** Go backend + HTMX + Tailwind CSS + SQLite.
+## Key Documents (Read These First)
+
+| Document | Purpose | When to Read |
+|----------|---------|--------------|
+| `DESIGN.md` | Authoritative design doc: architecture, patterns, visual design, dev guide | Before any significant work |
+| `SESSION_STATE.md` | Current task state, next steps | Start of every session |
+| `docs/adr/*.md` | Architecture Decision Records | Before implementing features in that area |
+
+### Multi-Agent Workflow
+
+This project uses a three-role development workflow. **Read your role definition before starting work:**
+
+| Role | Definition File | Responsibilities |
+|------|-----------------|------------------|
+| Architect | `ARCHITECT_ROLE.md` | Plans, documents, creates ADRs. Does NOT edit code. |
+| Implementor | `IMPLEMENTOR_ROLE.md` | Executes plans, writes code, runs tests. |
+| Reviewer | `REVIEWER_ROLE.md` | Reviews code quality and tests. Does NOT edit code. |
+
+**Handoff docs:** `instructions.md` (Architect → Implementor), `review_feedback.md` (Reviewer → Implementor)
+
## Efficiency & Token Management
- **Context Minimization:** Do not read entire files if `grep`, `sed`, or `ls` can answer a question.
- **Surgical Edits:** Perform small, targeted file edits. Avoid rewriting entire files for single changes.
@@ -22,19 +42,26 @@ A unified web dashboard aggregating Trello (PRIMARY), Todoist, Obsidian, and Pla
- **Build:** `go build -o dashboard cmd/dashboard/main.go`
## State Management
-- **SESSION_STATE.md:** The source of truth for resuming work. It must include:
+- **SESSION_STATE.md:** The source of truth for resuming work. Must include:
- Current Task Goal
- Completed Items
- - Architecture Decisions
- **Next 3 Specific Steps**
+- **Status tags:** `[TODO]` → `[IN_PROGRESS]` → `[REVIEW_READY]` → `[APPROVED]` (or `[NEEDS_FIX]`)
## Technical Context
- **Trello is PRIMARY:** Key + Token required in query params.
-- **Architecture:** chi router -> Handlers (`internal/handlers/`) -> Store (`internal/store/sqlite.go`).
+- **Architecture:** chi router → Handlers (`internal/handlers/`) → Store (`internal/store/sqlite.go`).
- **Errors:** Partial data/cache fallback preferred over hard failure.
+- **Full details:** See `DESIGN.md` → Architecture section.
## Coding Style
- Use concise, idiomatic Go.
- Avoid verbose explanations or comments for self-evident logic.
- Prioritize terminal-based verification over manual code review.
+- **Patterns:** See `DESIGN.md` → Development Guide for handler/template patterns.
+
+## Documentation
+- **ADR-first:** Capture architectural decisions in `docs/adr/*.md`, not one-off design docs.
+- **Update DESIGN.md** for new features, endpoints, or schema changes.
+- **Do NOT create** standalone design documents—use ADRs instead.
diff --git a/DESIGN.md b/DESIGN.md
index e0cf867..e568217 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -20,6 +20,68 @@ The dashboard serves as a **personal consolidation hub** designed to:
---
+## Development Workflow
+
+This project uses a **multi-agent development workflow** with three specialized roles that collaborate through shared documents.
+
+### Roles
+
+| Role | Agent | Responsibilities |
+|------|-------|------------------|
+| **Architect** | Gemini | Plans features, creates issues, writes surgical instructions. Does NOT edit source code. |
+| **Implementor** | Claude Code | Executes plans, writes code, runs tests. Updates state after completing work. |
+| **Reviewer** | QA Agent | Reviews code quality, runs tests, provides feedback. Does NOT edit source code. |
+
+### Role Definitions
+
+Each role has a detailed persona document:
+
+- `ARCHITECT_ROLE.md` - Planning, documentation, issue tracking
+- `IMPLEMENTOR_ROLE.md` - Code execution, TDD, verification
+- `REVIEWER_ROLE.md` - Quality gates, clean code review
+
+### Handoff Documents
+
+| Document | Purpose | Writer | Reader |
+|----------|---------|--------|--------|
+| `instructions.md` | Surgical implementation plan (ephemeral) | Architect | Implementor |
+| `review_feedback.md` | Code review results (ephemeral) | Reviewer | Implementor |
+| `SESSION_STATE.md` | Current state + next steps | All | All |
+| `issues/*.md` | Bug reports + feature specs | Architect | All |
+| `docs/adr/*.md` | Architectural decisions (permanent) | Architect | All |
+
+**Note:** `instructions.md` and `review_feedback.md` are ephemeral - they contain current task details. Architectural decisions belong in ADRs, not in ephemeral docs.
+
+### Status Tags
+
+Tasks flow through these states:
+
+```
+[TODO] → [IN_PROGRESS] → [REVIEW_READY] → [APPROVED]
+ ↑ ↓
+ └── [NEEDS_FIX] ←┘
+```
+
+### Workflow Example
+
+1. **Architect** identifies bug, creates `issues/bug_042_description.md`
+2. **Architect** writes fix plan to `instructions.md`, updates `SESSION_STATE.md` to `[TODO]`
+3. **Implementor** reads instructions, writes failing test (TDD), implements fix
+4. **Implementor** runs `go test ./...`, updates state to `[REVIEW_READY]`
+5. **Reviewer** reads code, runs tests, writes `review_feedback.md`
+6. **Reviewer** marks `[APPROVED]` or `[NEEDS_FIX]` with specific feedback
+7. If `[NEEDS_FIX]`, **Implementor** addresses feedback, returns to step 4
+
+### Principles
+
+- **Surgical edits** - Prefer targeted changes over full-file rewrites
+- **TDD** - Write failing test before implementation
+- **State tracking** - Always update `SESSION_STATE.md` after completing work
+- **Tool verification** - Use `go test`, `go build`, `grep` to verify state before planning
+- **ADR-first** - Document architectural decisions in ADRs, not one-off design docs
+
+---
+
## Architecture
### Directory Structure
@@ -330,6 +392,61 @@ Standalone live feeds page with:
Auto-refresh webcam images every 60 seconds.
+### Agent Context API (`/agent/*`)
+
+External agent authentication and data access system. Allows CLI tools, automation scripts, and AI assistants to access dashboard context securely.
+
+**Authentication Flow:**
+1. Agent sends `POST /agent/auth/request` with name + agent_id (UUID)
+2. Dashboard checks trust level:
+ - **TRUSTED**: Auto-approve if agent_id was previously approved
+ - **UNKNOWN**: Send WebSocket notification to connected browsers
+ - **BLOCKED**: Reject immediately
+3. User approves/denies via modal in browser (pushed via WebSocket)
+4. Agent polls `GET /agent/auth/poll?token=REQUEST_TOKEN` for result
+5. On approval, agent receives session_token (1-hour TTL)
+6. Agent uses session_token in Authorization header for context access
+
+**Endpoints:**
+
+| Method | Path | Auth | Purpose |
+|--------|------|------|---------|
+| POST | `/agent/auth/request` | None | Request access (returns request_token) |
+| GET | `/agent/auth/poll` | None | Poll for approval status |
+| POST | `/agent/auth/approve` | Browser session | User approves agent request |
+| POST | `/agent/auth/deny` | Browser session | User denies agent request |
+| GET | `/agent/context` | Agent session | Full timeline context (7 days back, 14 forward) |
+| GET | `/agent/web/request` | None | HTML auth flow for browser-only agents |
+| GET | `/agent/web/status` | None | HTML status page |
+| GET | `/agent/web/context` | None | HTML context view |
+
+**WebSocket Notifications (`/ws/notifications`):**
+- Pushes agent auth requests to connected browsers in real-time
+- JSON protocol with auto-reconnect on disconnect
+- Frontend handler in `web/static/js/app.js`
+
+**Security:**
+- Rate limit: 10 requests/minute per IP on auth endpoints
+- Session TTL: 1 hour, one active session per agent_id
+- Impersonation detection: Rejects if name/agent_id mismatch previous binding
+
+**Implementation:** `internal/handlers/agent.go`, `internal/handlers/websocket.go`
+
+### Completed Tasks Log
+
+Tracks task completion history for audit trail and agent context.
+
+**Purpose:**
+- Provides completion history in agent context API
+- Enables future analytics/reporting
+- Audit trail of completed work
+
+**Storage:** `completed_tasks` table (source, source_id, title, due_date, completed_at)
+
+**Feature Toggle:** `completed_log` (enabled by default)
+
+**Populated by:** `HandleCompleteAtom()` on task/card completion
+
---
## Database Schema
@@ -351,6 +468,11 @@ Auto-refresh webcam images every 60 seconds.
| `shopping_item_checks` | External item state | source, item_id, checked |
| `cache_metadata` | Cache timestamps | key, last_fetch, ttl_minutes |
| `sync_tokens` | Incremental sync | service, token |
+| `agents` | Registered agents | name, agent_id, trust_level, last_seen |
+| `agent_sessions` | Agent auth sessions | agent_id, request_token, session_token, status, expires_at |
+| `completed_tasks` | Completion log | source, source_id, title, due_date, completed_at |
+| `feature_toggles` | Feature flags | name, description, enabled |
+| `source_config` | Source filtering | source, item_type, item_id, item_name, enabled |
---
@@ -705,22 +827,33 @@ func TestFeature_Behavior(t *testing.T) {
- Add tests for new functionality
- Update tests for changed behavior
-### Design Documents and ADRs
+### Architecture Decision Records (ADRs)
-**When to update DESIGN.md:**
-- Adding new features or views
-- Changing data flow patterns
-- Modifying API integrations
-- Updating database schema
+**ADRs are the primary way to document architectural decisions.** They capture the context, decision, and tradeoffs for significant choices. Unlike one-off design documents that become stale, ADRs remain as a permanent record of why things are the way they are.
-**When to create an ADR (Architecture Decision Record):**
+**Always create an ADR when:**
- Choosing between multiple implementation approaches
-- Adding new external dependencies
-- Changing authentication/security model
-- Significant refactoring decisions
+- Adding new external dependencies or integrations
+- Changing authentication, security, or data flow patterns
+- Making significant refactoring decisions
+- Introducing new patterns or abstractions
+
+**Do NOT create one-off design docs.** Instead:
+- For feature planning → create an ADR with the architectural approach
+- For implementation details → put them in `instructions.md` (ephemeral)
+- For bug analysis → create an issue in `issues/` (ephemeral)
**ADR location:** `docs/adr/NNN-title.md`
+**Current ADRs:**
+| ADR | Decision |
+|-----|----------|
+| 001 | Session-based authentication with SQLite storage |
+| 002 | Polymorphic TimelineItem model for unified aggregation |
+| 003 | HTMX partials for all write operations |
+| 004 | Concurrent fetching with semaphore + cache fallback |
+| 005 | Agent API notification-based authentication |
+
**ADR template:**
```markdown
# ADR NNN: Title
@@ -749,11 +882,11 @@ What did we decide and why?
**Numbering:** Use sequential 3-digit numbers (001, 002, etc.)
-**Example ADRs to consider:**
-- API client retry strategy
-- Caching invalidation approach
-- New data source integration
-- UI framework changes
+**When to update DESIGN.md:**
+- Adding new features or views (update Features section)
+- New database tables (update Schema section)
+- New API endpoints (update Quick Reference)
+- Changes to the development workflow
---
@@ -783,12 +916,22 @@ npx tailwindcss -i web/static/css/input.css -o web/static/css/output.css --watch
| GET | `/tabs/timeline` | Timeline partial |
| GET | `/tabs/tasks` | Tasks partial |
| GET | `/tabs/shopping` | Shopping partial |
-| GET | `/conditions` | Live feeds page |
+| GET | `/conditions` | Live feeds page (public) |
| POST | `/complete-atom` | Complete task/card |
| POST | `/uncomplete-atom` | Reopen task/card |
| POST | `/unified-add` | Quick add task |
| POST | `/shopping/add` | Add shopping item |
-| GET | `/shopping/mode/{store}` | Shopping mode |
+| GET | `/shopping/mode/{store}` | Shopping mode view |
+| POST | `/shopping/mode/{store}/toggle` | Toggle shopping item |
+| POST | `/shopping/mode/{store}/complete` | Complete shopping item |
+| GET | `/settings` | Settings page |
+| POST | `/settings/features` | Create feature toggle |
+| POST | `/settings/features/toggle` | Toggle feature on/off |
+| GET | `/ws/notifications` | WebSocket for agent notifications |
+| POST | `/agent/auth/request` | Agent requests access |
+| GET | `/agent/auth/poll` | Agent polls for approval |
+| POST | `/agent/auth/approve` | User approves agent |
+| GET | `/agent/context` | Agent gets timeline context |
### Handler Signature
diff --git a/IMPLEMENTOR_ROLE.md b/IMPLEMENTOR_ROLE.md
index 62bfd7e..31c3f53 100644
--- a/IMPLEMENTOR_ROLE.md
+++ b/IMPLEMENTOR_ROLE.md
@@ -23,7 +23,8 @@
2. **Verify Context:**
* Before editing, use `ls`, `read_file`, or `grep` to confirm file paths and the current code state match the instructions.
- * If the instructions seem outdated or conflict with the current codebase, stop and ask for clarification.
+ * **Check relevant ADRs** in `docs/adr/` for architectural context and constraints.
+ * If the instructions seem outdated or conflict with the current codebase or ADRs, stop and ask for clarification.
3. **Test-Driven Execution (TDD):**
* **Pre-Check:** Run existing tests (`go test ./...`) or the specific reproduction test case provided to confirm the baseline (fail state for bugs, pass state for refactors).
diff --git a/REVIEWER_ROLE.md b/REVIEWER_ROLE.md
index 7c43dca..9bcf101 100644
--- a/REVIEWER_ROLE.md
+++ b/REVIEWER_ROLE.md
@@ -16,8 +16,9 @@
* **Focus:**
* **Correctness:** Does the code do what it is supposed to do?
* **Clean Code:** Is the code readable? Are functions small and focused? Are names descriptive?
- * **TDD:** Are there tests? Do they pass? Do they cover edge cases? Was the test written *before* the code (inferable from structure/commit history)?
+ * **Test Quality:** Are tests effective, clear, and complete? (See Test Review Checklist below)
* **Simplicity:** Is this the simplest thing that could possibly work? (YAGNI).
+ * **Documentation:** For significant changes, verify an ADR exists in `docs/adr/`. Flag missing ADRs for architectural decisions.
**Workflow Instructions:**
@@ -28,9 +29,25 @@
2. **Verify (Dynamic Analysis):**
* **Run Tests:** Execute `go test ./...` or specific package tests to ensure the build is green.
- * **Coverage:** Check if new code is covered by tests.
+ * **Coverage:** Check if new code is covered by tests. Use `go test -cover ./...` for coverage report.
-3. **Critique (Static Analysis):**
+3. **Review Tests (Test Quality Analysis):**
+ * **Effective:** Do tests actually verify the behavior they claim to test?
+ * Check assertions match test names - a test named `TestCreateTask_InvalidInput` should assert error handling, not success.
+ * Verify tests would fail if the code was broken - watch for tests that always pass.
+ * Ensure tests exercise the code path in question, not just adjacent code.
+ * **Clear:** Can you understand what the test verifies at a glance?
+ * Test names should describe the scenario and expected outcome: `TestHandler_MissingField_Returns400`
+ * Arrange-Act-Assert structure should be obvious.
+ * No magic numbers - use named constants or clear literals.
+ * Minimal setup - only what's needed for this specific test.
+ * **Complete:** Do tests cover the important cases?
+ * Happy path (normal operation)
+ * Error cases (invalid input, missing data, API failures)
+ * Edge cases (empty lists, nil values, boundary conditions)
+ * For bug fixes: regression test that would have caught the bug.
+
+4. **Critique (Static Analysis):**
* **Read Code:** Analyze the changes. Look for:
* **Complexity:** Nested loops, deep conditionals, long functions.
* **Naming:** Vague variable names, misleading function names.
@@ -38,7 +55,7 @@
* **Architecture:** Leaky abstractions (e.g., SQL in handlers).
* **Security:** Basic checks (input validation, error handling).
-4. **Report & State Update:**
+5. **Report & State Update:**
* **Write Feedback:** Create or update `review_feedback.md`.
* **Decision:**
* **PASS:** If code meets standards, update `SESSION_STATE.md` item to `[APPROVED]`.
@@ -47,6 +64,7 @@
* `# Review Cycle [Date/Time]`
* `## Status: [NEEDS_FIX / APPROVED]`
* `## Critical Issues (Blocking)`: Must be fixed before approval.
+ * `## Test Quality Issues`: Missing tests, unclear tests, ineffective assertions.
* `## Clean Code Suggestions (Non-Blocking)`: Improvements for readability.
* `## Praise`: What was done well.
diff --git a/docs/adr/002-timeline-aggregation.md b/docs/adr/002-timeline-aggregation.md
new file mode 100644
index 0000000..2700776
--- /dev/null
+++ b/docs/adr/002-timeline-aggregation.md
@@ -0,0 +1,76 @@
+# ADR 002: Timeline Aggregation Architecture
+
+## Status
+Accepted
+
+## Context
+The dashboard aggregates data from multiple sources (Todoist, Trello, PlanToEat, Google Calendar, Google Tasks). Users need a unified chronological view of upcoming items across all sources without opening multiple apps.
+
+Key challenges:
+- Different data sources have different models (Task, Card, Meal, Event)
+- Some sources have time-of-day, others only have dates
+- Meals have no explicit time but should appear at logical meal times
+- Need to support grouping by day section (Today, Tomorrow, Later)
+
+## Decision
+Implement a **polymorphic TimelineItem model** that normalizes all data sources into a single sortable structure.
+
+### Technical Details:
+
+**Unified Model (`internal/models/timeline.go`):**
+```go
+type TimelineItem struct {
+ ID string
+ Type TimelineItemType // task, meal, card, event, gtask
+ Title string
+ Description string
+ Time time.Time
+ AllDay bool
+ URL string
+ DaySection string // overdue, today, tomorrow, later
+ // ... additional fields
+}
+```
+
+**Meal Time Defaults:**
+- Breakfast → 08:00
+- Lunch → 12:00
+- Dinner → 19:00
+- Other → 12:00
+
+**Implementation:**
+- `internal/handlers/timeline_logic.go` - `BuildTimeline()` aggregation function
+- `internal/handlers/timeline.go` - HTTP handler
+- `internal/models/timeline.go` - Data models
+- Store methods: `GetTasksByDateRange()`, `GetMealsByDateRange()`, `GetCardsByDateRange()`
+
+**Grouping Strategy:**
+Items are grouped into collapsible day sections:
+- **Overdue** - Past due items (expanded)
+- **Today** - Due today (expanded)
+- **Tomorrow** - Due tomorrow (expanded)
+- **Later** - 2+ days out (collapsed by default)
+
+## Consequences
+
+**Pros:**
+- Single unified view reduces context switching
+- Consistent sorting regardless of data source
+- Extensible - new sources just need a converter to TimelineItem
+- Collapsible sections reduce cognitive load
+
+**Cons:**
+- Meal times are assumed, not actual (user might eat breakfast at 10am)
+- All-day items appear at midnight, requiring special handling
+- Multiple API calls per request (mitigated by caching)
+
+## Alternatives Considered
+
+**Option A: Source-specific views only**
+- Rejected: Defeats the purpose of a unified dashboard
+
+**Option B: Store normalized items in database**
+- Rejected: Adds complexity, staleness issues, harder to keep in sync
+
+**Option C: Client-side aggregation (JavaScript)**
+- Rejected: More complex, slower on mobile, harder to test
diff --git a/docs/adr/003-htmx-write-operations.md b/docs/adr/003-htmx-write-operations.md
new file mode 100644
index 0000000..2471a90
--- /dev/null
+++ b/docs/adr/003-htmx-write-operations.md
@@ -0,0 +1,85 @@
+# ADR 003: HTMX-Based Write Operations
+
+## Status
+Accepted
+
+## Context
+Phase 1-2 of the dashboard were read-only views. Phase 3 required transforming it into an active command center where users can:
+- Complete tasks/cards
+- Create new tasks
+- Add shopping items
+- Toggle item states
+
+Traditional approaches would require either:
+- Full page reloads (poor UX)
+- Complex JavaScript SPA framework (React, Vue)
+- Custom AJAX handlers
+
+## Decision
+Use **HTMX attributes** for all write operations, returning HTML partials that swap into the DOM.
+
+### Technical Details:
+
+**Pattern: Form submission with partial swap**
+```html
+<form hx-post="/complete-atom"
+ hx-vals='{"id": "{{.ID}}", "source": "{{.Source}}"}'
+ hx-target="closest .task-card"
+ hx-swap="outerHTML">
+ <button type="submit">✓</button>
+</form>
+```
+
+**Handler returns HTML partial:**
+```go
+func (h *Handler) HandleCompleteAtom(w http.ResponseWriter, r *http.Request) {
+ // ... complete the task via API
+ // Return completed state HTML or empty response
+ HTMLResponse(w, h.renderer, "completed-atom", data)
+}
+```
+
+**Quick Add Pattern:**
+```html
+<input hx-post="/unified-add"
+ hx-trigger="keyup[key=='Enter']"
+ hx-target="#task-list"
+ hx-swap="afterbegin"
+ name="content">
+```
+
+**Optimistic UI:**
+- Use CSS transitions for immediate visual feedback
+- On error, swap in error banner partial
+- HTMX `hx-on` events for state management
+
+**Unified Quick Add:**
+- Single input parses text for routing hints
+- `#groceries` tag → routes to shopping
+- `#work` tag → routes to Trello
+- Default → routes to Todoist
+
+## Consequences
+
+**Pros:**
+- No JavaScript framework needed
+- Server renders all HTML (single source of truth)
+- Progressive enhancement (works without JS, enhanced with)
+- Trivial to test (just HTTP handlers)
+- Fast development cycle
+
+**Cons:**
+- More HTTP requests than SPA approach
+- Partial HTML responses require careful template organization
+- Limited offline capability
+
+## Alternatives Considered
+
+**Option A: React/Vue SPA**
+- Rejected: Overkill for this use case, adds build complexity, harder to maintain
+
+**Option B: Full page reloads**
+- Rejected: Poor UX, especially on mobile
+
+**Option C: Custom JavaScript + JSON APIs**
+- Rejected: Reinventing what HTMX provides, more code to maintain
diff --git a/docs/adr/004-concurrent-data-fetching.md b/docs/adr/004-concurrent-data-fetching.md
new file mode 100644
index 0000000..c7238f8
--- /dev/null
+++ b/docs/adr/004-concurrent-data-fetching.md
@@ -0,0 +1,104 @@
+# ADR 004: Concurrent Data Fetching with Graceful Degradation
+
+## Status
+Accepted
+
+## Context
+The dashboard fetches data from 5+ external APIs on each page load:
+- Todoist (tasks)
+- Trello (boards, cards)
+- PlanToEat (meals, shopping)
+- Google Calendar (events)
+- Google Tasks (tasks)
+
+Sequential fetching would be unacceptably slow (5+ seconds). However, concurrent fetching introduces:
+- Rate limiting concerns (especially Trello)
+- Partial failure scenarios
+- Data race risks
+
+## Decision
+Implement **parallel fetching with semaphore-limited concurrency** and **cache-first fallback** for graceful degradation.
+
+### Technical Details:
+
+**Parallel Aggregation (`internal/handlers/handlers.go`):**
+```go
+func (h *Handler) aggregateData(ctx context.Context) (*DashboardData, error) {
+ var wg sync.WaitGroup
+ var mu sync.Mutex
+ data := &DashboardData{}
+
+ // Launch goroutines for each data source
+ wg.Add(4)
+ go func() { defer wg.Done(); fetchTasks(ctx, &mu, data) }()
+ go func() { defer wg.Done(); fetchBoards(ctx, &mu, data) }()
+ go func() { defer wg.Done(); fetchMeals(ctx, &mu, data) }()
+ go func() { defer wg.Done(); fetchCalendar(ctx, &mu, data) }()
+ wg.Wait()
+
+ return data, nil
+}
+```
+
+**Semaphore for Trello (`internal/api/trello.go`):**
+```go
+const maxConcurrentRequests = 5
+
+func (c *TrelloClient) GetBoardsWithCards(ctx context.Context) ([]Board, error) {
+ sem := make(chan struct{}, maxConcurrentRequests)
+ // ... limit concurrent board fetches
+}
+```
+
+**Cache-First Fallback:**
+```go
+func (h *Handler) fetchWithFallback(ctx context.Context, fetch func() error, getCache func() (T, error)) T {
+ if err := fetch(); err != nil {
+ log.Printf("Warning: API fetch failed, using cache: %v", err)
+ cached, _ := getCache()
+ return cached
+ }
+ return freshData
+}
+```
+
+**Error Collection:**
+- Errors are collected in `data.Errors` slice
+- UI displays warning banner if any source failed
+- Page still renders with available data
+
+## Consequences
+
+**Pros:**
+- Fast page loads (parallel fetching)
+- Resilient to individual API failures
+- Respects rate limits (semaphore pattern)
+- Users see cached data rather than error page
+
+**Cons:**
+- Complexity in error handling
+- Cache fallback may show stale data without clear indication
+- Debugging requires checking multiple error sources
+- Mutex needed for shared data structure
+
+## Alternatives Considered
+
+**Option A: Sequential fetching**
+- Rejected: 5+ second page loads unacceptable
+
+**Option B: Fail-fast on any error**
+- Rejected: One flaky API shouldn't break entire dashboard
+
+**Option C: Background sync with eventual consistency**
+- Rejected: Adds complexity, users expect fresh data on load
+
+## Implementation Notes
+
+**Race Condition Prevention:**
+- All goroutines write to different fields OR use mutex
+- Trello client uses mutex for `boards[i]` slice element writes
+- Run `go test -race ./...` to verify
+
+**Monitoring:**
+- Log all API failures with `Warning:` prefix
+- Consider adding metrics for cache hit/miss rates
diff --git a/docs/adr/005-agent-api-authentication.md b/docs/adr/005-agent-api-authentication.md
new file mode 100644
index 0000000..e64a5a8
--- /dev/null
+++ b/docs/adr/005-agent-api-authentication.md
@@ -0,0 +1,95 @@
+# ADR 005: Agent API Authentication Architecture
+
+## Status
+Accepted
+
+## Context
+External agents (CLI tools, automation scripts, AI assistants) need secure access to dashboard context without exposing user credentials. Traditional approaches have weaknesses:
+
+- **API Keys**: Long-lived, often stored insecurely, difficult to revoke
+- **OAuth2**: Complex setup, overkill for personal dashboard
+- **SSH Keys**: Key management burden on user
+
+Requirements:
+- User awareness of agent access (no hidden API keys)
+- Easy revocation (deny re-auth requests)
+- Time-limited sessions to reduce exposure
+- Support for both CLI and browser-based agents
+
+## Decision
+Implement **notification-based approval flow** with ephemeral sessions.
+
+### Technical Details:
+
+**Identity Model:**
+- Agents identified by `name` + `agent_id` (UUID) pair
+- Binding persisted on first approval
+- Impersonation detected if name/agent_id mismatch
+
+**Trust Levels:**
+- `TRUSTED`: Previously approved, auto-approve on re-auth
+- `UNKNOWN`: New agent, requires user approval
+- `BLOCKED`: Denied agent, reject immediately
+
+**Session Model:**
+- 1-hour TTL tokens
+- One active session per agent_id
+- Session token in Authorization header
+
+**Approval Flow:**
+```
+Agent Dashboard Browser
+ | | |
+ |-- POST /auth/request --> | |
+ | |-- WebSocket push ----> |
+ | | | (user sees modal)
+ | | |
+ |<-- request_token --------| |
+ | | |
+ |-- GET /auth/poll ------> | |
+ | (polling) | |
+ | | <-- POST /approve ---- |
+ | | |
+ |<-- session_token --------| |
+ | | |
+ |-- GET /context --------> | |
+ | (with session_token) | |
+```
+
+**Implementation:**
+- `internal/handlers/agent.go` - Auth flow handlers (615 LOC)
+- `internal/handlers/websocket.go` - Real-time notifications (216 LOC)
+- `migrations/010_agent_tables.sql` - Storage schema
+- `web/static/js/app.js` - Browser UI for approval modal
+
+**Rate Limiting:**
+- 10 requests/minute per IP on auth endpoints
+- Prevents brute-force token guessing
+
+## Consequences
+
+**Pros:**
+- User-visible agent access (approval modal shows agent name)
+- Easy revocation by denying re-auth or blocking agent
+- Trust level caching reduces approval fatigue for known agents
+- Time-limited sessions reduce credential exposure
+- Works for both CLI agents (polling) and browser agents (web endpoints)
+
+**Cons:**
+- Requires browser window open for first-time approval
+- Poll loop adds latency to auth flow (~1-5 seconds)
+- Session expiry interrupts long-running agent tasks (must re-auth)
+
+## Alternatives Considered
+
+**Option A: Traditional API Keys**
+- Rejected: Long-lived credentials, no user awareness of access
+
+**Option B: OAuth2 Device Flow**
+- Rejected: Complex implementation, requires external auth server setup
+
+**Option C: SSH-style Key Pairs**
+- Rejected: Key management burden, harder to revoke
+
+**Option D: Magic Links (email-based)**
+- Rejected: Adds email dependency, slower approval flow
diff --git a/migrations/README.md b/migrations/README.md
new file mode 100644
index 0000000..e849b9c
--- /dev/null
+++ b/migrations/README.md
@@ -0,0 +1,36 @@
+# Database Migrations
+
+Sequential SQL migrations for task-dashboard schema evolution.
+
+## Migration History
+
+| # | File | Purpose |
+|---|------|---------|
+| 001 | `001_initial_schema.sql` | Initial schema (tasks, boards, cards, meals) |
+| 002 | `002_add_cache_metadata.sql` | Cache metadata table for TTL tracking |
+| 003 | `003_add_sync_tokens.sql` | Sync tokens for incremental sync |
+| 004 | `004_add_auth.sql` | Authentication (users, sessions) |
+| 005 | `005_add_bugs.sql` | Bug tracking table |
+| 006 | `006_remove_resolved_bugs.sql` | Add resolved_at timestamp to bugs |
+| 007 | — | **SKIPPED** (reserved, never used) |
+| 008 | `008_user_shopping_items.sql` | User-added shopping items |
+| 009 | `009_shopping_item_checks.sql` | External item check state |
+| 010 | `010_agent_tables.sql` | Agent authentication (agents, agent_sessions) |
+| 011 | `011_completed_tasks.sql` | Completed tasks log |
+| 012 | `012_feature_toggles.sql` | Feature toggle system |
+| 013 | `013_source_config.sql` | Source filtering configuration |
+
+## Migration 007 Gap
+
+Migration 007 was reserved during development but never implemented. The gap is intentional and preserved to maintain clean git history. Future migrations continue from 014.
+
+## Running Migrations
+
+Migrations are applied automatically on application startup via `store.RunMigrations()`. The `schema_migrations` table tracks which migrations have been applied.
+
+## Creating New Migrations
+
+1. Create file: `migrations/NNN_description.sql` (next number is 014)
+2. Write idempotent SQL (use `IF NOT EXISTS` where possible)
+3. Test locally: `go run cmd/dashboard/main.go`
+4. Verify: Check `schema_migrations` table for new entry