From ef6cb4e11675e06376e9bb182c956c378aea5cc1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Sat, 21 Feb 2026 17:24:19 -0600 Subject: [PATCH] Add mandatory CLI standard - all web projects must have scripts/ folder --- MEMORY.md | 74 ++++++++++--- STANDARD_CLI_INTEGRATION.md | 210 ++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+), 16 deletions(-) create mode 100644 STANDARD_CLI_INTEGRATION.md diff --git a/MEMORY.md b/MEMORY.md index 585c55b..2a5bcb4 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -25,7 +25,42 @@ --- -### 2. NEVER CLOSE/MARK TASKS AS DONE — MATT DOES 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 @@ -173,31 +208,34 @@ First question: "How will I (Max) interact with this programmatically without Ma **✅ CORRECTLY PLACED:** These scripts are now in the gantt-board project repo and committed. -### Task CRUD +### 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 # Get specific task -./scripts/gantt-task-crud.sh create "Title" [status] [priority] # Create task -./scripts/gantt-task-crud.sh update # Update task -./scripts/gantt-task-crud.sh delete # Delete task +./scripts/gantt-task-crud.sh create "Title" [status] [priority] +./scripts/gantt-task-crud.sh update +./scripts/gantt-task-crud.sh delete +./scripts/attach-file.sh # Attach file +./scripts/view-attachment.sh [index] # View attachment ``` -### File Attachments (NO BROWSER NEEDED) -```bash -./scripts/attach-file.sh # Attach file to task -./scripts/view-attachment.sh [index] # View attachment content -``` +**How it works:** Uses Supabase service role key directly. Files stored as base64 data URLs. -**How it works:** Uses Supabase service role key directly. Files stored as base64 data URLs in the attachments array. No storage bucket needed. - -**Verification:** +**To copy to new project:** ```bash -./scripts/gantt-task-crud.sh get | jq '.attachments | length' +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 Architecture Pattern (Apply to ALL Projects) +## CLI/API Implementation Guide (Reference for Rule #2) **Every app I build MUST have programmatic access without browser automation.** This is non-negotiable. @@ -227,7 +265,7 @@ First question: "How will I (Max) interact with this programmatically without Ma - Project-specific logic stays with project - I can run `./scripts/crud.sh` from the project root -**Exception:** Cross-project utilities (like git helpers) can live in workspace scripts, but app-specific CRUD must be in the app repo. +**NO EXCEPTIONS:** Every web project gets this. No excuses. ### Required Capabilities Checklist @@ -450,12 +488,16 @@ task_id=$(./scripts/crud.sh create '{"title":"Test"}' | jq -r '.id') - [ ] 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 diff --git a/STANDARD_CLI_INTEGRATION.md b/STANDARD_CLI_INTEGRATION.md new file mode 100644 index 0000000..1ddb330 --- /dev/null +++ b/STANDARD_CLI_INTEGRATION.md @@ -0,0 +1,210 @@ +# CLI Integration Standard + +Standard for adding programmatic CLI access to all projects so AI agents can work without browser automation. + +## Rule: CLI Tools Live INSIDE the Project + +**Location:** `{project-root}/scripts/` + +**Why:** +- Version controlled with the project +- Self-documenting (API + CLI in same repo) +- Portable (clone repo, CLI works immediately) +- Project-specific logic stays with project +- No hunting around workspace folders + +## Required File Structure + +``` +project-root/ +├── scripts/ +│ ├── crud.sh # Main CRUD operations +│ ├── attach-file.sh # File attachments +│ ├── README.md # Usage documentation +│ └── .env.example # Required environment variables +├── api/ # REST API routes (used by CLI) +│ └── items/ +│ ├── route.ts +│ └── [id]/ +│ ├── route.ts +│ └── attachments/ +│ └── route.ts +└── README.md # Project README with CLI section +``` + +## Required CLI Commands + +Every project MUST implement these: + +```bash +# From project root: +./scripts/crud.sh list [filters] # List all items +./scripts/crud.sh get # Get single item +./scripts/crud.sh create # Create item +./scripts/crud.sh update # Update field +./scripts/crud.sh delete # Delete item +./scripts/attach-file.sh # Attach file to item +``` + +## Environment Variables + +Each project's CLI needs these in `scripts/.env` (gitignored): + +```bash +# Supabase direct access (for bypassing auth) +SUPABASE_URL=https://xxxx.supabase.co +SUPABASE_SERVICE_ROLE_KEY=eyJ... + +# Or API-based access +API_URL=http://localhost:3000/api +API_KEY=secret_key_for_cli_access +``` + +## Supabase Direct Pattern (Recommended) + +For Supabase projects, use direct DB access with service role key: + +**File:** `scripts/crud.sh` +```bash +#!/bin/bash +set -e + +# Load env from scripts/.env +source "$(dirname "$0")/.env" + +action=$1 +shift + +case $action in + list) + curl -s "${SUPABASE_URL}/rest/v1/items?select=*" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" | jq '.' + ;; + get) + id=$1 + curl -s "${SUPABASE_URL}/rest/v1/items?id=eq.${id}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" | jq '.[0]' + ;; + create) + data=$1 + curl -s -X POST "${SUPABASE_URL}/rest/v1/items" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Content-Type: application/json" \ + -d "$data" | jq '.' + ;; + update) + id=$1 + field=$2 + value=$3 + curl -s -X PATCH "${SUPABASE_URL}/rest/v1/items?id=eq.${id}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Content-Type: application/json" \ + -d "{\"${field}\": \"${value}\"}" | jq '.' + ;; + delete) + id=$1 + curl -s -X DELETE "${SUPABASE_URL}/rest/v1/items?id=eq.${id}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" + echo "Deleted ${id}" + ;; + *) + echo "Usage: $0 {list|get |create |update |delete }" + exit 1 + ;; +esac +``` + +## File Attachment Pattern + +**File:** `scripts/attach-file.sh` +```bash +#!/bin/bash +set -e + +source "$(dirname "$0")/.env" + +ITEM_ID=$1 +FILE_PATH=$2 + +if [ -z "$ITEM_ID" ] || [ -z "$FILE_PATH" ]; then + echo "Usage: $0 " + exit 1 +fi + +if [ ! -f "$FILE_PATH" ]; then + echo "Error: File not found: $FILE_PATH" + exit 1 +fi + +# Read and encode file +mime=$(file -b --mime-type "$FILE_PATH") +base64=$(base64 -i "$FILE_PATH") +filename=$(basename "$FILE_PATH") +size=$(stat -f%z "$FILE_PATH" 2>/dev/null || stat -c%s "$FILE_PATH") + +# Build attachment JSON +attachment=$(jq -n \ + --arg id "$(uuidgen | tr '[:upper:]' '[:lower:]')" \ + --arg name "$filename" \ + --arg type "$mime" \ + --arg data "data:${mime};base64,${base64}" \ + --argjson size "$size" \ + '{id: $id, name: $name, type: $type, dataUrl: $data, size: $size}') + +# Get current attachments, append new one +current=$(curl -s "${SUPABASE_URL}/rest/v1/items?id=eq.${ITEM_ID}&select=attachments" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" | jq '.[0].attachments // []') + +updated=$(echo "$current" | jq ". + [$attachment]") + +# Update item +curl -s -X PATCH "${SUPABASE_URL}/rest/v1/items?id=eq.${ITEM_ID}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Content-Type: application/json" \ + -d "{\"attachments\": $updated}" | jq '.' + +echo "✅ Attached ${filename} (${size} bytes) to item ${ITEM_ID}" +``` + +## Per-Project Reference + +### Gantt Board +- **Location:** `/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/` +- **Scripts:** `gantt-task-crud.sh`, `attach-file.sh`, `view-attachment.sh` +- **Auth:** Supabase service role key +- **Table:** `public.tasks` + +### Adding CLI to a New Project + +1. Create `scripts/` directory in project root +2. Copy template scripts from gantt-board +3. Update table names and fields for your project +4. Create `scripts/.env` with Supabase credentials +5. Test: `./scripts/crud.sh list` +6. Commit to git: `git add scripts/ && git commit -m "Add CLI tools for AI access"` +7. Update project's README.md with CLI usage section + +## Agent Instructions + +When working on a project: +1. Check for `scripts/` directory in project root +2. If CLI exists, use it: `./scripts/crud.sh list` +3. If CLI doesn't exist, create it using patterns above +4. NEVER create files in workspace scripts folder for project-specific tools + +## Verification Checklist + +Before saying a task is done: +- [ ] CLI tools are in `{project}/scripts/`, NOT workspace +- [ ] Scripts are executable (`chmod +x`) +- [ ] `.env` file exists with credentials (gitignored) +- [ ] Scripts work: `./scripts/crud.sh list` returns data +- [ ] Changes are committed to git +- [ ] Project README documents CLI usage