From 9cee3f78483532828a2f72c65eb2b952b2ded670 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 13 Jan 2026 15:03:20 -1000 Subject: remove agent access feature --- AI_AGENT_ACCESS.md | 340 ----------------------------------------------------- 1 file changed, 340 deletions(-) delete mode 100644 AI_AGENT_ACCESS.md (limited to 'AI_AGENT_ACCESS.md') diff --git a/AI_AGENT_ACCESS.md b/AI_AGENT_ACCESS.md deleted file mode 100644 index 40fe6a1..0000000 --- a/AI_AGENT_ACCESS.md +++ /dev/null @@ -1,340 +0,0 @@ -# AI Agent Access Design - -## Overview -Add a dedicated API endpoint optimized for AI agents (like Claude) to access dashboard data in a structured, machine-readable format with simple authentication. - -## Authentication Strategy - -### API Key-Based Auth -Simple bearer token authentication that's easy to use from Claude.ai: -- Generate a long, random API key for AI access -- Store in environment variable: `AI_AGENT_API_KEY` -- Use standard `Authorization: Bearer {key}` header -- No complex OAuth flows or JWT rotation - -### Why This Approach? -1. **Simple for Claude**: Just include auth header in requests -2. **Stateless**: No session management needed -3. **Revocable**: Change key in .env to revoke access -4. **Standard**: Uses common HTTP authorization pattern - -## API Endpoints - -### GET /api/ai/dashboard -Returns complete dashboard data in AI-optimized JSON format. - -**Request:** -```http -GET /api/ai/dashboard HTTP/1.1 -Host: localhost:8080 -Authorization: Bearer {AI_AGENT_API_KEY} -``` - -**Response (Success - 200 OK):** -```json -{ - "status": "success", - "timestamp": "2026-01-09T14:30:00Z", - "data": { - "trello_boards": [ - { - "id": "board123", - "name": "Work Projects", - "cards": [ - { - "id": "card1", - "name": "Complete project proposal", - "list": "In Progress", - "due_date": "2026-01-15", - "url": "https://trello.com/c/card1" - } - ] - } - ], - "todoist_tasks": [ - { - "id": "task1", - "content": "Buy groceries", - "project": "Personal", - "priority": 1, - "due_date": "2026-01-10", - "completed": false, - "labels": ["shopping"], - "url": "https://todoist.com/task/1" - } - ], - "obsidian_notes": [ - { - "filename": "meeting-notes.md", - "title": "Team Meeting Notes", - "content_preview": "Discussed Q1 goals...", - "modified": "2026-01-09T10:00:00Z", - "tags": ["meetings", "work"] - } - ], - "plantoeat_meals": [ - { - "id": "meal1", - "recipe": "Spaghetti Carbonara", - "date": "2026-01-09", - "meal_type": "dinner", - "url": "https://plantoeat.com/recipe/123" - } - ] - }, - "metadata": { - "cache_age_seconds": 45, - "sources_refreshed": ["trello", "todoist"], - "errors": [] - } -} -``` - -**Response (Unauthorized - 401):** -```json -{ - "status": "error", - "error": "Invalid or missing API key", - "hint": "Include 'Authorization: Bearer {key}' header" -} -``` - -### GET /api/ai/boards/{board_id}/cards -Get cards from a specific Trello board. - -**Request:** -```http -GET /api/ai/boards/board123/cards HTTP/1.1 -Authorization: Bearer {AI_AGENT_API_KEY} -``` - -### GET /api/ai/tasks?filter={filter} -Get filtered tasks (today, week, overdue, completed). - -**Request:** -```http -GET /api/ai/tasks?filter=today HTTP/1.1 -Authorization: Bearer {AI_AGENT_API_KEY} -``` - -### POST /api/ai/task -Create a new Todoist task (Phase 2). - -**Request:** -```http -POST /api/ai/task HTTP/1.1 -Authorization: Bearer {AI_AGENT_API_KEY} -Content-Type: application/json - -{ - "content": "Buy milk", - "project": "Personal", - "due_date": "2026-01-10", - "priority": 1, - "labels": ["shopping"] -} -``` - -## AI-Optimized Response Format - -### Design Principles -1. **Flat structure**: Avoid deep nesting where possible -2. **Explicit field names**: Use `due_date` not `dueDate` for clarity -3. **Include metadata**: Provide context about data freshness -4. **Clear errors**: Return actionable error messages -5. **Consistent types**: Always use ISO 8601 for dates - -### Example Claude.ai Usage -```markdown -User: "What tasks do I have due today?" - -Claude uses MCP tool or API call: -GET /api/ai/tasks?filter=today -Authorization: Bearer sk-ai-1234567890abcdef - -Claude response: "You have 3 tasks due today: -1. Buy groceries (Personal, Priority 1) -2. Complete project proposal (Work, Priority 2) -3. Call dentist (Health, Priority 3)" -``` - -## Implementation - -### Middleware: Auth Check -```go -// internal/middleware/ai_auth.go -func AIAuthMiddleware(apiKey string) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - authHeader := r.Header.Get("Authorization") - - if !strings.HasPrefix(authHeader, "Bearer ") { - respondJSON(w, 401, map[string]string{ - "status": "error", - "error": "Missing or invalid Authorization header", - "hint": "Include 'Authorization: Bearer {key}' header", - }) - return - } - - token := strings.TrimPrefix(authHeader, "Bearer ") - if token != apiKey { - respondJSON(w, 401, map[string]string{ - "status": "error", - "error": "Invalid API key", - }) - return - } - - next.ServeHTTP(w, r) - }) - } -} -``` - -### Handler: AI Dashboard -```go -// internal/handlers/ai_handlers.go -func (h *Handler) HandleAIDashboard(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - // Fetch all data - data, err := h.fetchDashboardData(ctx, false) - if err != nil { - respondJSON(w, 500, map[string]interface{}{ - "status": "error", - "error": err.Error(), - }) - return - } - - // Format for AI consumption - response := map[string]interface{}{ - "status": "success", - "timestamp": time.Now().Format(time.RFC3339), - "data": map[string]interface{}{ - "trello_boards": formatBoardsForAI(data.Boards), - "todoist_tasks": formatTasksForAI(data.Tasks), - "obsidian_notes": formatNotesForAI(data.Notes), - "plantoeat_meals": formatMealsForAI(data.Meals), - }, - "metadata": map[string]interface{}{ - "errors": data.Errors, - }, - } - - respondJSON(w, 200, response) -} -``` - -### Router Setup -```go -// cmd/dashboard/main.go -func main() { - // ... existing setup ... - - // AI Agent routes (protected by auth middleware) - if cfg.AIAgentAPIKey != "" { - aiRouter := chi.NewRouter() - aiRouter.Use(middleware.AIAuthMiddleware(cfg.AIAgentAPIKey)) - - r.Route("/api/ai", func(r chi.Router) { - r.Use(middleware.AIAuthMiddleware(cfg.AIAgentAPIKey)) - r.Get("/dashboard", h.HandleAIDashboard) - r.Get("/boards/{boardID}/cards", h.HandleAIBoardCards) - r.Get("/tasks", h.HandleAITasks) - // Phase 2: Write operations - // r.Post("/task", h.HandleAICreateTask) - }) - } -} -``` - -## Security Considerations - -1. **Key Storage**: Never commit API key to git -2. **Key Rotation**: Easy to change in .env file -3. **Rate Limiting**: Consider adding rate limits per key -4. **HTTPS Only**: Use HTTPS in production -5. **Logging**: Log API key usage (last 4 chars only) - -## Configuration - -### .env.example -```bash -# AI Agent Access -AI_AGENT_API_KEY=sk-ai-1234567890abcdef... -# Generate with: openssl rand -hex 32 -``` - -### config.go -```go -type Config struct { - // ... existing fields ... - AIAgentAPIKey string -} - -func Load() (*Config, error) { - cfg := &Config{ - // ... existing fields ... - AIAgentAPIKey: os.Getenv("AI_AGENT_API_KEY"), - } - return cfg, nil -} -``` - -## Usage from Claude.ai - -### With MCP (Model Context Protocol) -```json -{ - "mcpServers": { - "dashboard": { - "command": "curl", - "args": [ - "-H", "Authorization: Bearer ${AI_AGENT_API_KEY}", - "http://localhost:8080/api/ai/dashboard" - ] - } - } -} -``` - -### Direct API Call -Claude can make HTTP requests directly: -``` -GET http://localhost:8080/api/ai/dashboard -Authorization: Bearer sk-ai-1234567890abcdef -``` - -## Future Enhancements - -1. **Webhook Support**: POST updates to Claude.ai when data changes -2. **Streaming**: Server-sent events for real-time updates -3. **Scoped Keys**: Different keys for read vs write access -4. **GraphQL**: More flexible querying for AI agents -5. **Natural Language Queries**: `/api/ai/query?q=What's due today?` - -## Testing - -### Manual Test -```bash -# Generate API key -export AI_KEY=$(openssl rand -hex 32) - -# Add to .env -echo "AI_AGENT_API_KEY=sk-ai-$AI_KEY" >> .env - -# Test endpoint -curl -H "Authorization: Bearer sk-ai-$AI_KEY" \ - http://localhost:8080/api/ai/dashboard | jq . -``` - -### Unit Test -```go -func TestAIAuthMiddleware(t *testing.T) { - // Test valid key - // Test invalid key - // Test missing header -} -``` -- cgit v1.2.3