28 KiB
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):
- Copy
scripts/from gantt-board:cp -r /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts ./ - Update table names in scripts (e.g.,
items→tasksorprojects) - Create
scripts/.envwith Supabase credentials - Test:
./scripts/crud.sh listmust return data - Commit:
git add scripts/ && git commit -m "Add CLI tools for AI access" - 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.shexists and is executable./scripts/attach-file.shexists and is executable./scripts/crud.sh listreturns data successfully./scripts/.envexists with working credentials- CLI usage documented in README.md
- Scripts committed to git
If any item unchecked → PROJECT IS NOT READY.
2.5. CLI MUST STAY IN SYNC WITH WEB UI — ALWAYS
❌ FORBIDDEN: Web UI has features the CLI can't access
✅ REQUIRED: Every web API endpoint has a matching CLI command
The Rule:
- Web UI can do it → CLI can do it. No exceptions.
- When adding a web feature, add the CLI command in the SAME commit
- When modifying an API, update the CLI script in the SAME commit
- CLI is not an afterthought — it's part of the feature
Verification Process (BEFORE committing any API change):
# 1. List all API endpoints in the web app
find src/app/api -name "route.ts" | xargs grep -l "export async function"
# 2. Check that each endpoint has a CLI equivalent
# GET /api/items → ./scripts/crud.sh list
# POST /api/items → ./scripts/crud.sh create
# PATCH /api/items/[id] → ./scripts/crud.sh update
# POST /api/items/[id]/attachments → ./scripts/crud.sh attach
# 3. Test the CLI actually works
./scripts/crud.sh list
./scripts/crud.sh create '{"title":"Test"}'
# 4. If any API endpoint lacks CLI coverage → DO NOT COMMIT
Feature Completion Checklist:
- Web UI feature implemented
- API endpoint created/modified
- CLI command added/updated to match
- CLI tested and working
- README.md updated with new CLI usage
- All changes in SINGLE commit
Why: If the web can do it but CLI can't, I can't automate it. I shouldn't need to open a browser to do something the web can do programmatically.
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:
- Subagent: "File created at /path/to/file.md" → I heard "Task done"
- Marked task complete in memory
- Next session: You had to re-explain the problem
- You'd already told me twice (see message history)
Resolution (2/22):
- Created
attach-file.shCLI 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 giteaorgitea webon 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.shCLI 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 (100% API Coverage)
Location: /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/ (IN PROJECT, VERSION CONTROLLED)
Status: ✅ Rule 2.5 Compliant - All API endpoints have matching CLI commands
Audit Date: 2026-02-22
Coverage: 13 API endpoints → 13 CLI commands (100%)
Rule: CLI tools belong IN THE PROJECT DIRECTORY, not workspace scripts folder. They must be committed with the project or they'll get lost.
API-to-CLI Coverage Matrix
| API Endpoint | Method | CLI Command | Status |
|---|---|---|---|
| Tasks | |||
| /api/tasks | GET | task list |
✅ |
| /api/tasks | POST | task create |
✅ |
| /api/tasks | DELETE | task delete |
✅ |
| /api/tasks/natural | POST | task natural |
✅ |
| Projects | |||
| /api/projects | GET | project list |
✅ |
| /api/projects/[id] | GET | project get |
✅ |
| /api/projects | POST | project create |
✅ |
| /api/projects | PATCH | project update |
✅ |
| /api/projects | DELETE | project delete |
✅ |
| Sprints | |||
| /api/sprints | GET | sprint list |
✅ |
| /api/sprints/[id] | GET | sprint get |
✅ |
| /api/sprints | POST | sprint create |
✅ |
| /api/sprints | PATCH | sprint update |
✅ |
| /api/sprints | DELETE | sprint delete |
✅ |
| Auth | |||
| /api/auth/login | POST | auth login |
✅ |
| /api/auth/logout | POST | auth logout |
✅ |
| /api/auth/session | GET | auth session |
✅ |
| /api/auth/register | POST | auth register |
✅ |
| /api/auth/forgot-password | POST | auth forgot-password |
✅ |
| /api/auth/reset-password | POST | auth reset-password |
✅ |
| /api/auth/account | PATCH | auth account |
✅ |
| /api/auth/users | GET | auth users |
✅ |
| Debug | |||
| /api/debug | GET | debug |
✅ |
| Total | 22/22 (100%) |
Reference Implementation (Gantt Board)
Source of truth for the pattern:
- Location:
/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/ - Files:
gantt.sh- Unified CLI (API-based, all operations)gantt-task-crud.sh- Direct Supabase CRUDattach-file.sh- Direct Supabase file attachmentsview-attachment.sh- View attached files
Usage (Unified CLI - covers ALL API endpoints):
# Tasks
./scripts/gantt.sh task list [status] # List tasks
./scripts/gantt.sh task get <task-id> # Get task
./scripts/gantt.sh task create "Title" [status] [priority] # Create task
./scripts/gantt.sh task natural "Fix bug by Friday, high priority" # Natural language
./scripts/gantt.sh task update <id> <field> <val> # Update field
./scripts/gantt.sh task delete <task-id> # Delete task
./scripts/gantt.sh task comment <id> "text" # Add comment
./scripts/gantt.sh task attach <id> <file> # Attach file
# Projects & Sprints
./scripts/gantt.sh project list # List projects
./scripts/gantt.sh project get <id> # Get specific project
./scripts/gantt.sh project create "Name" [desc] [color] # Create project
./scripts/gantt.sh project update <id> <field> <val> # Update project
./scripts/gantt.sh project delete <id> # Delete project
./scripts/gantt.sh sprint list # List sprints
./scripts/gantt.sh sprint get <id> # Get specific sprint
./scripts/gantt.sh sprint create "Name" <project-id> [start] [end] [goal] # Create sprint
./scripts/gantt.sh sprint update <id> <field> <val> # Update sprint
./scripts/gantt.sh sprint delete <id> # Delete sprint
# Auth
./scripts/gantt.sh auth session # Check session
./scripts/gantt.sh auth login <email> <pass> # Log in
./scripts/gantt.sh auth logout # Log out
./scripts/gantt.sh auth register <email> <pass> # Register new account
./scripts/gantt.sh auth forgot-password <email> # Request password reset
./scripts/gantt.sh auth reset-password <tok> <pass> # Reset password
./scripts/gantt.sh auth account <field> <value> # Update account
./scripts/gantt.sh auth users # List users
# Debug
./scripts/gantt.sh debug # Debug endpoint
Usage (Direct Supabase - works without web server):
./scripts/gantt-task-crud.sh list [status] # List tasks
./scripts/gantt-task-crud.sh get <task-id> # Get task
./scripts/attach-file.sh <task-id> <file-path> # Attach file
./scripts/view-attachment.sh <task-id> [index] # View attachment
How it works:
gantt.shuses the REST API (requires web server running)- Direct scripts use Supabase service role key (works offline)
- Files stored as base64 data URLs in database
To copy to new project:
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.shfrom 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)
#!/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:
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)
# API config for CLI
API_URL=http://localhost:3000/api
API_KEY=your-service-role-key-here
File: .env.example (committed to repo)
# 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
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.localasSERVICE_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)
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(url, serviceRoleKey);
// Use supabase.from('table').select() etc.
File Attachment Pattern
Storage Options:
- Base64 in database (small files < 1MB): Store directly in JSONB field
- Supabase Storage (larger files): Upload to bucket, store reference URL
- External (S3/R2): Store URL reference only
CLI Attachment Script:
#!/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:
# 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.mdwith usage docs (copy fromCLI_README_TEMPLATE.md).env.exampledocumenting 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?
- API-to-CLI Coverage Verified: Every API endpoint has matching CLI command
If any check fails → NOT READY.
Template to copy: /Users/mattbruce/.openclaw/workspace/CLI_README_TEMPLATE.md
Ongoing Development: CLI Sync Maintenance
Rule 2.5 in practice: When adding ANY web feature:
# 1. BEFORE committing, audit API surface area
find src/app/api -name "route.ts" -exec basename $(dirname {}) \; | sort > /tmp/api-endpoints.txt
# 2. Audit CLI coverage
grep -E "^(cmd_|function cmd)" scripts/*.sh | sed 's/.*cmd_//' | sed 's/(.*//' | sort -u > /tmp/cli-commands.txt
# 3. Compare - if API has endpoints CLI doesn't cover → ADD THEM
# Example mismatch:
# API: POST /api/tasks/natural (natural language create)
# CLI: Only has cmd_task_create (manual create)
# → Must add cmd_task_natural to gantt.sh
# 4. Update README.md with new commands
# 5. Test new CLI command works
# 6. Commit web + CLI changes together
Coverage Matrix (maintain in scripts/README.md):
| API Endpoint | Method | CLI Command | Status |
|---|---|---|---|
| /api/tasks | GET | task list | ✅ |
| /api/tasks | POST | task create | ✅ |
| /api/tasks/natural | POST | task natural | ✅ |
| /api/tasks | DELETE | task delete | ✅ |
| ... | ... | ... | ... |
Monthly Audit Task: Run this during a heartbeat to ensure sync:
cd /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board
./scripts/audit-cli-coverage.sh # Script that compares API vs CLI
Audit Script Template: Copy to new projects:
cp /Users/mattbruce/.openclaw/workspace/scripts/audit-cli-coverage.sh \
/Users/mattbruce/Documents/Projects/OpenClaw/Web/{new-project}/scripts/
Then customize the CLI_MAP associative array to match your CLI commands.
If CLI lags behind API → File a bug task immediately.
Quick Commands
# 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
# 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 tasksgetTask(taskId)- Get single taskcreateTask(params)- Create new taskupdateTask(taskId, updates)- Update task fieldsdeleteTask(taskId)- Delete taskupdateTaskStatus(taskId, status)- Update statusassignTask(taskId, assigneeId)- Change assigneecompleteTask(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:
- ✅ Create the document
- ✅ Attach it to the task via gantt board API or UI
- ✅ VERIFY via API (no browser needed):
Must return non-empty array with the file../scripts/gantt-task-crud.sh get <task-id> | jq '.attachments' - ❌ DELETE local file only after API confirms attachment
- ❌ 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:
- ✅ Task completed → Log to memory/YYYY-MM-DD.md
- ✅ Decision made → Document in MEMORY.md
- ✅ New process/tool discovered → Add to TOOLS.md or MEMORY.md
- ✅ Error/lesson learned → Write to MEMORY.md "Lessons Learned"
- ✅ Context switch → Quick checkpoint update
- ✅ 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.