- New mandatory rule: Every web API endpoint must have matching CLI - Added verification process for API-to-CLI coverage - Added ongoing maintenance checklist - Added coverage matrix template
721 lines
26 KiB
Markdown
721 lines
26 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.**
|
|
|
|
---
|
|
|
|
### 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):**
|
|
```bash
|
|
# 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:**
|
|
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.sh` - Unified CLI (API-based, all operations)
|
|
- `gantt-task-crud.sh` - Direct Supabase CRUD
|
|
- `attach-file.sh` - Direct Supabase file attachments
|
|
- `view-attachment.sh` - View attached files
|
|
|
|
**Usage (Unified CLI - covers ALL API endpoints):**
|
|
```bash
|
|
# 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 sprint list # List sprints
|
|
|
|
# Auth
|
|
./scripts/gantt.sh auth session # Check session
|
|
./scripts/gantt.sh auth login <email> <pass> # Log in
|
|
```
|
|
|
|
**Usage (Direct Supabase - works without web server):**
|
|
```bash
|
|
./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.sh` uses 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:**
|
|
```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?
|
|
- [ ] **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:
|
|
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
cd /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board
|
|
./scripts/audit-cli-coverage.sh # Script that compares API vs CLI
|
|
```
|
|
|
|
**If CLI lags behind API → File a bug task immediately.**
|
|
|
|
## 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.
|