test-repo/MEMORY.md

614 lines
22 KiB
Markdown

# MEMORY.md - Curated Long-Term Memory
## 🚨 NEVER BREAK THESE RULES 🚨
### 0. NEVER MARK TASKS DONE WITHOUT VALIDATION — EVER
**FORBIDDEN:** Saying "task is done" based on subagent report or assumption
**REQUIRED:** I verify the deliverable MYSELF via API, file check, or screenshot
**The Rule:**
- Subagent says "done" → I say "VERIFYING" → Check via API/file/UI → THEN confirm
- If I can't verify → "Task complete pending verification" → Ask how to confirm
- NEVER trust "success" messages without seeing proof
**Why:** I'm the one accountable. "The subagent said it worked" is not an excuse.
---
### 1. ALWAYS SEND FULL URLs TO GANTT TASKS — NEVER JUST IDs
**FORBIDDEN:** "Task 33ebc71e-7d40-456c-8f98-bb3578d2bb2b is done"
**REQUIRED:** "https://gantt-board.vercel.app/tasks/33ebc71e-7d40-456c-8f98-bb3578d2bb2b is done"
**Format:** `https://gantt-board.vercel.app/tasks/{task-id}`
**Why:** Matt needs clickable links on his phone. Sending IDs wastes his time. I have ZERO excuse for this.
---
### 2. EVERY WEB PROJECT MUST HAVE CLI TOOLS IN scripts/ — MANDATORY
**FORBIDDEN:** Creating a web app without programmatic CLI access
**REQUIRED:** Every project gets `./scripts/` folder with CRUD + attachment capability
**The Rule - Non-Negotiable:**
```
/Users/mattbruce/Documents/Projects/OpenClaw/Web/{project-name}/
├── scripts/ # MUST EXIST
│ ├── crud.sh # MUST support: list, get, create, update, delete
│ ├── attach-file.sh # MUST support: attach files to items
│ └── .env.example # MUST document required env vars
```
**Implementation Pattern (Copy-Paste from Gantt Board):**
1. Copy `scripts/` from gantt-board: `cp -r /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts ./`
2. Update table names in scripts (e.g., `items``tasks` or `projects`)
3. Create `scripts/.env` with Supabase credentials
4. Test: `./scripts/crud.sh list` must return data
5. Commit: `git add scripts/ && git commit -m "Add CLI tools for AI access"`
6. Document: Add CLI section to README.md
**Why:** If I can't access it via CLI, I can't work on it when Matt's remote. Browser automation requiring clicks is UNACCEPTABLE.
**Project Readiness Checklist (BEFORE saying "project is ready"):**
- [ ] `./scripts/crud.sh` exists and is executable
- [ ] `./scripts/attach-file.sh` exists and is executable
- [ ] `./scripts/crud.sh list` returns data successfully
- [ ] `./scripts/.env` exists with working credentials
- [ ] CLI usage documented in README.md
- [ ] Scripts committed to git
**If any item unchecked → PROJECT IS NOT READY.**
---
### 3. NEVER CLOSE/MARK TASKS AS DONE — MATT DOES THIS
**FORBIDDEN:** Changing task status to "done" or "complete"
**ALLOWED:** Attaching files, updating descriptions, adding comments
**Matt and ONLY Matt marks tasks complete.** I handle the work, he handles the status.
**VERIFY BEFORE ANY STATUS CHANGE:**
- "Ready to mark this done?"
- "Should I update the status?"
- **Wait for explicit YES before touching status**
**FORBIDDEN:** "Task 33ebc71e-7d40-456c-8f98-bb3578d2bb2b is done"
**REQUIRED:** "https://gantt-board.vercel.app/tasks/33ebc71e-7d40-456c-8f98-bb3578d2bb2b is done"
**Format:** `https://gantt-board.vercel.app/tasks/{task-id}`
**Why:** Matt needs clickable links on his phone. Sending IDs wastes his time. I have ZERO excuse for this.
---
## Critical Information
### Who I Am
- Name: Max
- Role: Digital assistant to Matt Bruce
- Mission: Help build iOS empire for retirement
### Matt's Identity
- Name: Matt Bruce
- Email: mbrucedogs@gmail.com
- Work: iOS Lead Architect at Toyota (contractor)
- Goal: Build side hustle to retire early, travel with Heidi
### Project Locations (ALWAYS CHECK TOOLS.md)
All projects in: `/Users/mattbruce/Documents/Projects/OpenClaw/`
**Active Web Projects:**
- Gantt Board: https://gantt-board.vercel.app (port 3000)
- Login: mbruce+max@topdoglabs.com / !7883Gantt
- Stack: Next.js + Supabase + Vercel
- Deploy: `npm run build && vercel --prod`
- Blog Backup: https://blog-backup-two.vercel.app (port 3002)
- Mission Control: https://mission-control-rho-pink.vercel.app/ (port 3001)
- Heartbeat Monitor: port 3005
### Infrastructure
- Gitea: http://192.168.1.128:3000 (ai-agent / !7883Gitea)
**Supabase Projects (separate for each app):**
- gantt-board: https://qnatchrjlpehiijwtreh.supabase.co
- Other projects: Each has their own Supabase project (see TOOLS.md)
### Key Decisions
- All web projects use Supabase for auth/database
- Vercel CLI deployment (no GitHub for gantt-board)
- Project folder structure enforced (Web/iOS/Documents)
## Lessons Learned
### 2026-02-21 - Subagent Task Verification FAILURE
**Problem:** iOS MRR Research task marked "done" but file was NOT attached to gantt board. Subagent created local file, didn't complete attachment step.
**Root Cause:** Trusted subagent "success" without verifying the actual deliverable. "File created" ≠ "Task complete."
**The Fuckup:**
1. Subagent: "File created at /path/to/file.md" → I heard "Task done"
2. Marked task complete in memory
3. Next session: You had to re-explain the problem
4. You'd already told me twice (see message history)
**Resolution (2/22):**
- Created `attach-file.sh` CLI script for file attachments
- Attached iOS MRR file via Supabase API directly
- Updated task status to done via CLI
- Deleted local file (single source of truth now in gantt board)
**Never Again:**
- Subagent says "done" → I verify the actual requirement via API
- For gantt attachments: Must confirm file is ATTACHED, not just created
- Build CLI tools for anything I'll need to do repeatedly
- **Rule:** If I can't do it via API/CLI, I can't do it reliably
---
### 2026-02-21 - Memory Failures
**Problem:** Complete memory loss of previous day's work caused frustration.
**Root Cause:** Didn't read files at session start, relied on failed memory_search.
**Solution:**
- Created SESSION_STARTUP.md with explicit checklist
- Updated AGENTS.md with mandatory file reading order
- All project info now in TOOLS.md
- Created PROJECT_SETUP.md for folder structure rules
**Never Again:**
- Always read SESSION_STARTUP.md first
- Read TOOLS.md for all project locations
- Read memory files for recent context
- Files are my memory - use them
### 2026-02-21 - Gitea Installation Disaster
**Problem:** Installed Gitea locally on Matt's Mac, causing port 3000 conflict with Next.js dev server.
**Root Cause:** Forgot Gitea was already running on separate machine (192.168.1.128:3000).
**Solution:** Uninstalled local Gitea, documented in TOOLS.md that it's on another machine.
**Never Again:**
- Gitea runs at http://192.168.1.128:3000 (remote server)
- Port 3000 is for Next.js dev server on Matt's Mac
- NEVER run `brew install gitea` or `gitea web` on Matt's machine
- Use existing Gitea server for all git operations
## Design Principle: API-First for AI Access
**Every app I build MUST have programmatic access.** Browser automation requiring manual clicks defeats the purpose of having an AI assistant.
| Approach | Effort for Matt | Reliability |
|----------|-----------------|-------------|
| **API/CLI** | Zero - I handle it | High |
| **Database direct** (Supabase) | Zero - I query it | High |
| **Browser relay** | High - must click to connect | Low |
| **Desktop apps** | 100% - I can't touch them | N/A |
**Rule for all future projects:**
- ✅ REST API for all CRUD operations
- ✅ CLI wrapper for scripted access
- ✅ Database queries when API doesn't exist
- ❌ No "I'll just use the browser" - that's asking Matt to babysit me
**Gantt board example:**
- Tasks: ✅ API exists → I can verify, update, complete without Matt
- Attachments: ✅ NOW SOLVED - `attach-file.sh` CLI created 2/22
**CRITICAL: Gantt Board Must Work Remotely**
- Matt accesses tasks from outside the house
- I must attach files WITHOUT requiring browser clicks or manual intervention
- CLI/API approach is the ONLY valid solution
- Browser relay requiring extension clicks is UNACCEPTABLE for this use case
**When planning a new app:**
First question: "How will I (Max) interact with this programmatically without Matt's help?"
---
## Gantt Board CLI Tools (Working 2/22)
**Location:** `/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/` (IN PROJECT, VERSION CONTROLLED)
**Rule:** CLI tools belong IN THE PROJECT DIRECTORY, not workspace scripts folder. They must be committed with the project or they'll get lost.
**✅ CORRECTLY PLACED:** These scripts are now in the gantt-board project repo and committed.
### Reference Implementation (Gantt Board)
**Source of truth for the pattern:**
- **Location:** `/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/`
- **Files:** `gantt-task-crud.sh`, `attach-file.sh`, `view-attachment.sh`
- **Usage:**
```bash
./scripts/gantt-task-crud.sh list [status] # List all tasks
./scripts/gantt-task-crud.sh get <task-id> # Get specific task
./scripts/gantt-task-crud.sh create "Title" [status] [priority]
./scripts/gantt-task-crud.sh update <task-id> <field> <value>
./scripts/gantt-task-crud.sh delete <task-id>
./scripts/attach-file.sh <task-id> <file-path> # Attach file
./scripts/view-attachment.sh <task-id> [index] # View attachment
```
**How it works:** Uses Supabase service role key directly. Files stored as base64 data URLs.
**To copy to new project:**
```bash
cp -r /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts \
/Users/mattbruce/Documents/Projects/OpenClaw/Web/{new-project}/
# Then update table names in the scripts
```
---
## CLI/API Implementation Guide (Reference for Rule #2)
**Every app I build MUST have programmatic access without browser automation.** This is non-negotiable.
### CRITICAL: Scripts Live INSIDE the Project Repo
**NOT** in a shared workspace scripts folder. Each project owns its own CLI.
```
/Users/mattbruce/Documents/Projects/OpenClaw/Web/project-name/
├── api/ # REST API routes (Next.js App Router)
│ └── (auth)/ # Protected routes
├── lib/
│ ├── api-client.ts # Typed API client for internal use
│ └── cli/ # CLI scripts directory
│ ├── README.md # Usage docs
│ └── crud.ts # Generic CRUD operations
├── scripts/ # CLI scripts LIVE HERE
│ ├── crud.sh # Main CLI entry point
│ └── attach-file.sh # File attachment script
└── supabase/ # DB functions (if direct DB needed)
```
**Why inside the project:**
- Version controlled with the project
- Self-documenting (API + CLI in same repo)
- Portable (clone repo, CLI works)
- Project-specific logic stays with project
- I can run `./scripts/crud.sh` from the project root
**NO EXCEPTIONS:** Every web project gets this. No excuses.
### Required Capabilities Checklist
For EVERY project, I must be able to do these via CLI/API:
| Capability | Implementation | Location |
|------------|----------------|----------|
| **List** items | API endpoint + CLI | `api/items/route.ts` + `cli/crud.sh list` |
| **Get** single item | API endpoint + CLI | `api/items/[id]/route.ts` + `cli/crud.sh get <id>` |
| **Create** item | API endpoint + CLI | `api/items/route.ts` + `cli/crud.sh create` |
| **Update** item | API endpoint + CLI | `api/items/[id]/route.ts` + `cli/crud.sh update <id>` |
| **Delete** item | API endpoint + CLI | `api/items/[id]/route.ts` + `cli/crud.sh delete <id>` |
| **Attach files** | API endpoint (base64) + CLI | `api/items/[id]/attachments/route.ts` |
| **Query/filter** | API with query params | `api/items?status=open&assignee=xyz` |
| **Status changes** | API PATCH + CLI | `cli/crud.sh status <id> <new-status>` |
### CLI Script Template (Copy-Paste Starter)
**File:** `scripts/crud.sh` (inside the project, NOT workspace)
```bash
#!/bin/bash
# Generic CRUD CLI for [ProjectName]
# Usage: ./scripts/crud.sh <action> [args]
set -e
BASE_URL="${API_URL:-http://localhost:3000/api}"
API_KEY="${API_KEY:-$PROJECT_API_KEY}"
action=$1
shift
case $action in
list)
curl -s "$BASE_URL/items?limit=100" \
-H "Authorization: Bearer $API_KEY" | jq '.'
;;
get)
id=$1
curl -s "$BASE_URL/items/$id" \
-H "Authorization: Bearer $API_KEY" | jq '.'
;;
create)
# Read from stdin or args
if [ -t 0 ]; then
data="$1"
else
data=$(cat)
fi
curl -s -X POST "$BASE_URL/items" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "$data" | jq '.'
;;
update)
id=$1
field=$2
value=$3
curl -s -X PATCH "$BASE_URL/items/$id" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "{\"$field\": \"$value\"}" | jq '.'
;;
delete)
id=$1
curl -s -X DELETE "$BASE_URL/items/$id" \
-H "Authorization: Bearer $API_KEY"
echo "Deleted $id"
;;
attach)
id=$1
file=$2
base64=$(base64 -i "$file")
filename=$(basename "$file")
curl -s -X POST "$BASE_URL/items/$id/attachments" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "{\"filename\": \"$filename\", \"data\": \"$base64\"}" | jq '.'
;;
*)
echo "Usage: $0 {list|get <id>|create <json>|update <id> <field> <value>|delete <id>|attach <id> <file>}"
exit 1
;;
esac
```
**Usage from project root:**
```bash
cd /Users/mattbruce/Documents/Projects/OpenClaw/Web/[project-name]
./scripts/crud.sh list
./scripts/crud.sh get <id>
./scripts/crud.sh create '{"title":"New Item"}'
```
### Environment Configuration
**File:** `.env.local` (gitignored, per-project)
```bash
# API config for CLI
API_URL=http://localhost:3000/api
API_KEY=your-service-role-key-here
```
**File:** `.env.example` (committed to repo)
```bash
# Copy to .env.local and fill in real values
API_URL=http://localhost:3000/api
API_KEY=your-api-key-here
```
### TypeScript API Client Template
**File:** `lib/api-client.ts`
```typescript
const API_BASE = process.env.NEXT_PUBLIC_API_URL || '/api';
const API_KEY = process.env.API_KEY;
export async function apiRequest<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const res = await fetch(`${API_BASE}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
...options.headers,
},
});
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
// CRUD operations
export const api = {
list: (resource: string, params?: Record<string, string>) =>
apiRequest(`/${resource}?${new URLSearchParams(params)}`),
get: (resource: string, id: string) =>
apiRequest(`/${resource}/${id}`),
create: (resource: string, data: unknown) =>
apiRequest(`/${resource}`, { method: 'POST', body: JSON.stringify(data) }),
update: (resource: string, id: string, data: unknown) =>
apiRequest(`/${resource}/${id}`, { method: 'PATCH', body: JSON.stringify(data) }),
delete: (resource: string, id: string) =>
apiRequest(`/${resource}/${id}`, { method: 'DELETE' }),
attach: (resource: string, id: string, file: { filename: string; data: string }) =>
apiRequest(`/${resource}/${id}/attachments`, { method: 'POST', body: JSON.stringify(file) }),
};
```
### Authentication Pattern
**Option 1: Service Role Key (Server-side only)**
- Store in `.env.local` as `SERVICE_ROLE_KEY`
- Use for CLI scripts that run server-side
- NEVER expose to client
**Option 2: API Keys (Cross-origin safe)**
- Generate per-integration
- Store in database with permissions
- Pass as `Authorization: Bearer <key>` header
**Option 3: Supabase Direct (When API doesn't exist yet)**
```typescript
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(url, serviceRoleKey);
// Use supabase.from('table').select() etc.
```
### File Attachment Pattern
**Storage Options:**
1. **Base64 in database** (small files < 1MB): Store directly in JSONB field
2. **Supabase Storage** (larger files): Upload to bucket, store reference URL
3. **External (S3/R2)**: Store URL reference only
**CLI Attachment Script:**
```bash
#!/bin/bash
# attach-file.sh - Universal file attachment
ITEM_ID=$1
FILE_PATH=$2
API_URL="${API_URL}/api/items/$ITEM_ID/attachments"
# Detect mime type
mime=$(file -b --mime-type "$FILE_PATH")
base64=$(base64 -i "$FILE_PATH")
filename=$(basename "$FILE_PATH")
curl -s -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "{
\"filename\": \"$filename\",
\"mimeType\": \"$mime\",
\"data\": \"$base64\",
\"size\": $(stat -f%z "$FILE_PATH" 2>/dev/null || stat -c%s "$FILE_PATH")
}" | jq '.'
```
### Verification Pattern (Always Verify!)
After ANY operation, verify via API:
```bash
# Create → Verify
task_id=$(./scripts/crud.sh create '{"title":"Test"}' | jq -r '.id')
./scripts/crud.sh get $task_id | jq '.title' # Should echo "Test"
# Attach → Verify
./scripts/crud.sh attach $task_id ./file.md
./scripts/crud.sh get $task_id | jq '.attachments | length' # Should be > 0
# Update → Verify
./scripts/crud.sh update $task_id status done
./scripts/crud.sh get $task_id | jq '.status' # Should echo "done"
```
### When Starting a New Project
**Checklist before saying "project structure ready":**
- [ ] API routes exist for CRUD operations
- [ ] CLI scripts created in `scripts/` directory
- [ ] API client module in `lib/api-client.ts`
- [ ] `scripts/README.md` with usage docs (copy from `CLI_README_TEMPLATE.md`)
- [ ] `.env.example` documenting required env vars
- [ ] Test: Can I list items via CLI without browser?
- [ ] Test: Can I attach a file via CLI?
- [ ] Test: Can I verify operations via CLI get?
**If any check fails → NOT READY.**
**Template to copy:** `/Users/mattbruce/.openclaw/workspace/CLI_README_TEMPLATE.md`
## Quick Commands
```bash
# Deploy Gantt Board
cd /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board
npm run build && vercel --prod
# Check all projects
ls /Users/mattbruce/Documents/Projects/OpenClaw/Web/
```
## Gantt Board Task CRUD
I have full CRUD capabilities on gantt board tasks via Supabase API:
**Bash script:** `/Users/mattbruce/.openclaw/workspace/scripts/gantt-task-crud.sh`
```bash
# List tasks (optionally filter by status)
./scripts/gantt-task-crud.sh list [open|done|...]
# Get single task
./scripts/gantt-task-crud.sh get <task-id>
# Create task
./scripts/gantt-task-crud.sh create "Task title" [status] [priority] [project-id] [assignee-id]
# Update task field
./scripts/gantt-task-crud.sh update <task-id> <field> <value>
# Delete task
./scripts/gantt-task-crud.sh delete <task-id>
```
**TypeScript module:** `/Users/mattbruce/.openclaw/workspace/scripts/gantt-task-crud.ts`
- `listTasks(status?)` - List all tasks
- `getTask(taskId)` - Get single task
- `createTask(params)` - Create new task
- `updateTask(taskId, updates)` - Update task fields
- `deleteTask(taskId)` - Delete task
- `updateTaskStatus(taskId, status)` - Update status
- `assignTask(taskId, assigneeId)` - Change assignee
- `completeTask(taskId)` - Mark as done
**Default assignee:** Max (9c29cc99-81a1-4e75-8dff-cd7cc5ceb5aa)
## Natural Language Task Parsing
Matt can rattle off tasks naturally and I'll parse them:
**Example formats:**
- "Add task: Fix the login bug by Friday"
- "For Max: Research Stripe integration, low priority"
- "Urgent: Deploy blog backup to Vercel tomorrow"
- "Create task: Update iOS app icons"
**I parse:**
- **Title** the main task description
- **Assignee** "for [Name]" or defaults to Matt
- **Priority** "urgent/asap" = high, "low priority" = low, else medium
- **Due date** tomorrow, next week, by Friday, etc. (natural language)
## Document/File Management Rules
### RULE: Task Documents → Attach + Verify via API
When creating documents for gantt board tasks:
1. Create the document
2. Attach it to the task via gantt board API or UI
3. **VERIFY via API** (no browser needed):
```bash
./scripts/gantt-task-crud.sh get <task-id> | jq '.attachments'
```
Must return non-empty array with the file.
4.**DELETE local file only after API confirms attachment**
5.**Never mark task "done" until API verification passes**
**CRITICAL:** Creating a file locally is NOT the same as attaching it. Subagents often stop at step 1.
**Why:** Prevents workspace clutter and ensures single source of truth is in the gantt board.
---
## Memory Maintenance — Critical Rule
**Update memory files CONTINUOUSLY throughout the day, not at the end.**
- After significant decisions → write to MEMORY.md
- After task completions → update memory/YYYY-MM-DD.md
- After new processes established → document immediately
- Waiting until end-of-day = lost context and repeated mistakes
This prevents the nightmare of today (Feb 21) where session issues caused complete memory loss of critical work.
### My Memory Update Plan
**TRIGGERS — Update memory when:**
1. ✅ Task completed → Log to memory/YYYY-MM-DD.md
2. ✅ Decision made → Document in MEMORY.md
3. ✅ New process/tool discovered → Add to TOOLS.md or MEMORY.md
4. ✅ Error/lesson learned → Write to MEMORY.md "Lessons Learned"
5. ✅ Context switch → Quick checkpoint update
6. ✅ Every 30-60 min of continuous work → Quick status save
**WHAT to save:**
- **MEMORY.md:** Decisions, lessons, key info, processes (curated)
- **memory/YYYY-MM-DD.md:** Raw log of work, conversations, tasks done
- **TOOLS.md:** Project locations, credentials, environment specifics
**CHECKPOINT habit:**
Before saying "done" or switching topics → ask "What needs to be remembered?"
**Safety net:**
If session crashes, next session reads files first. Files are source of truth.