diff --git a/.planning/phases/04-logs-intelligence/04-01-PLAN.md b/.planning/phases/04-logs-intelligence/04-01-PLAN.md new file mode 100644 index 0000000..c322223 --- /dev/null +++ b/.planning/phases/04-logs-intelligence/04-01-PLAN.md @@ -0,0 +1,198 @@ +--- +phase: 04-logs-intelligence +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: [n8n-workflow.json] +autonomous: true + +user_setup: + - service: anthropic + why: "Claude API for natural language understanding" + env_vars: + - name: ANTHROPIC_API_KEY + source: "Anthropic Console -> API Keys -> Create Key" + dashboard_config: [] + +must_haves: + truths: + - "User can request logs for a container by name" + - "User can specify number of log lines (default 50)" + - "Logs are returned in readable format in Telegram" + artifacts: + - path: "n8n-workflow.json" + provides: "Logs command routing and Docker API integration" + contains: "logs" + key_links: + - from: "Switch node" + to: "Docker logs API call" + via: "logs command pattern match" + pattern: "logs|show logs" + - from: "Docker API response" + to: "Telegram reply" + via: "log formatting code node" +--- + + +Implement container log retrieval via Telegram commands. + +Purpose: Delivers REQ-07 (view logs with configurable line count) - users can troubleshoot containers directly from their phone by viewing recent logs. + +Output: Extended n8n workflow with logs command routing, Docker logs API call, and formatted log response. + + + +@/home/luc/.claude/get-shit-done/workflows/execute-plan.md +@/home/luc/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/04-logs-intelligence/04-RESEARCH.md +@.planning/phases/02-docker-integration/02-02-SUMMARY.md +@n8n-workflow.json + + + + + + Task 1: Add logs command routing to workflow + n8n-workflow.json + +Extend the main Switch node to detect logs commands. Pattern: "logs " or "show logs " with optional line count. + +Add new route in Switch node: +- Condition: message matches /^(show\s+)?logs\s+/i +- Route to new "Parse Logs Command" Code node + +Create "Parse Logs Command" Code node: +- Extract container name from message +- Extract line count if specified (e.g., "logs plex 100"), default to 50 +- Return: { container: string, lines: number } + +Example inputs to handle: +- "logs plex" -> { container: "plex", lines: 50 } +- "show logs sonarr" -> { container: "sonarr", lines: 50 } +- "logs nginx 100" -> { container: "nginx", lines: 100 } +- "show logs radarr last 200" -> { container: "radarr", lines: 200 } + + +In n8n workflow editor, send message "logs test" - should route to Parse Logs Command node (visible in execution view). Check output includes container and lines fields. + + Logs commands route to dedicated branch with parsed container name and line count. + + + + Task 2: Implement Docker logs API call with formatting + n8n-workflow.json + +After Parse Logs Command, add container matching (reuse existing fuzzy match pattern from actions branch). + +Create "Build Logs Command" Code node: +- Input: matched container ID and requested line count +- Build curl command: + ``` + curl -s --unix-socket /var/run/docker.sock "http://localhost/v1.53/containers/CONTAINER_ID/logs?stdout=1&stderr=1&tail=LINES×tamps=1" + ``` +- Note: Docker logs API returns binary stream with 8-byte header per line. First byte indicates stream (1=stdout, 2=stderr). + +Create "Execute Logs" Execute Command node: +- Run the curl command + +Create "Format Logs" Code node: +- Parse Docker log stream format (strip 8-byte headers from each line) +- Format for Telegram: + - Truncate if > 4000 chars (Telegram message limit) + - Add header: "Logs for (last N lines):" + - Use monospace formatting with tags (HTML parse mode already enabled) +- Handle empty logs gracefully: "No logs available for " +- Handle errors: "Could not retrieve logs for : " + +Wire to Telegram Send Message node for reply. + + +Test via Telegram: +1. "logs n8n" - should return recent n8n container logs in monospace format +2. "logs n8n 10" - should return only 10 lines +3. "logs nonexistent" - should return friendly "no container found" message + + Users can retrieve container logs via Telegram with configurable line count, formatted for readability. + + + + Task 3: Handle Docker log stream binary format + n8n-workflow.json + +The Docker logs API returns a multiplexed stream with 8-byte headers. Each frame: +- Byte 0: stream type (1=stdout, 2=stderr) +- Bytes 1-3: reserved (zeros) +- Bytes 4-7: frame size (big-endian uint32) +- Remaining bytes: log content + +Update "Format Logs" Code node to properly decode this: + +```javascript +// Docker logs binary stream decoder +const rawOutput = $input.item.json.stdout || ''; + +// Docker API with timestamps returns text lines when using tail parameter +// But may have 8-byte binary headers we need to strip +const lines = rawOutput.split('\n') + .filter(line => line.length > 0) + .map(line => { + // Check if line starts with binary header (non-printable chars in first 8 bytes) + if (line.length > 8 && line.charCodeAt(0) <= 2) { + return line.substring(8); + } + return line; + }) + .join('\n'); + +// Truncate for Telegram (4096 char limit, leave room for header) +const maxLen = 3800; +const truncated = lines.length > maxLen + ? lines.substring(0, maxLen) + '\n... (truncated)' + : lines; + +return { + formatted: truncated, + lineCount: lines.split('\n').length +}; +``` + +Add error indicator prefix for stderr lines if desired (optional enhancement). + + +Test with a container known to have logs: +1. Send "logs n8n 20" via Telegram +2. Verify output is readable text (no garbled binary characters) +3. Verify timestamps appear if container outputs them + + Docker log binary stream format properly decoded into readable text. + + + + + +After all tasks: +1. Send "logs n8n" - returns formatted logs +2. Send "logs plex 100" - returns up to 100 lines +3. Send "show logs sonarr" - alternative syntax works +4. Send "logs nonexistent" - friendly error message +5. Logs display in monospace (preformatted) in Telegram + + + +- REQ-07 delivered: Users can view container logs with configurable line count +- Default 50 lines when not specified +- Multiple syntax variations supported (logs X, show logs X) +- Binary stream format properly decoded +- Output formatted for Telegram readability (monospace, truncated if needed) + + + +After completion, create `.planning/phases/04-logs-intelligence/04-01-SUMMARY.md` + diff --git a/.planning/phases/04-logs-intelligence/04-02-PLAN.md b/.planning/phases/04-logs-intelligence/04-02-PLAN.md new file mode 100644 index 0000000..6dcfc7e --- /dev/null +++ b/.planning/phases/04-logs-intelligence/04-02-PLAN.md @@ -0,0 +1,253 @@ +--- +phase: 04-logs-intelligence +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: [n8n-workflow.json] +autonomous: false + +user_setup: + - service: anthropic + why: "Claude API for natural language understanding" + env_vars: + - name: ANTHROPIC_API_KEY + source: "Anthropic Console -> API Keys -> Create Key" + dashboard_config: [] + +must_haves: + truths: + - "Messages are parsed by Claude for intent detection" + - "Recognized intents route to appropriate handlers" + - "Unknown intents receive helpful response" + artifacts: + - path: "n8n-workflow.json" + provides: "Claude API integration and intent routing" + contains: "anthropic" + key_links: + - from: "Telegram message" + to: "Claude API" + via: "HTTP Request node" + pattern: "api.anthropic.com" + - from: "Claude response" + to: "Switch node" + via: "intent parsing code node" + pattern: "action.*view_logs|query_stats" +--- + + +Integrate Claude API for natural language understanding and intent-first message routing. + +Purpose: Enables conversational interaction (REQ-08) by understanding user intent before execution. Users can speak naturally instead of memorizing command syntax. + +Output: Extended n8n workflow with Claude API integration, intent parsing, and routing logic. + + + +@/home/luc/.claude/get-shit-done/workflows/execute-plan.md +@/home/luc/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/04-logs-intelligence/04-RESEARCH.md +@n8n-workflow.json + + + + + + Task 1: Add Claude API credential and HTTP Request node + n8n-workflow.json + +Create Claude API integration in the workflow. + +1. Add "Claude Intent Parser" HTTP Request node: + - Method: POST + - URL: https://api.anthropic.com/v1/messages + - Authentication: Header Auth + - Header: x-api-key = {{$credentials.anthropicApi.apiKey}} (or use Generic Credential) + - Header: anthropic-version = 2023-06-01 + - Header: content-type = application/json + - Body (JSON): + ```json + { + "model": "claude-sonnet-4-5-20250929", + "max_tokens": 256, + "system": [ + { + "type": "text", + "text": "You are a Docker container management assistant. Parse user requests and return ONLY valid JSON.\n\nValid actions:\n- view_logs: User wants to see container logs\n- query_stats: User asks about resource usage (memory, CPU)\n- container_action: User wants to start/stop/restart/update a container\n- container_status: User asks about container status\n- list_containers: User wants to see all containers\n- unknown: Cannot determine intent\n\nRespond with JSON: {\"action\": \"\", \"container\": \"\", \"parameters\": {}}\\n\\nExamples:\\n- \"show me plex logs\" -> {\"action\": \"view_logs\", \"container\": \"plex\", \"parameters\": {\"lines\": 50}}\\n- \"what's using the most memory?\" -> {\"action\": \"query_stats\", \"container\": null, \"parameters\": {\"metric\": \"memory\", \"sort\": \"desc\"}}\\n- \"restart nginx\" -> {\"action\": \"container_action\", \"container\": \"nginx\", \"parameters\": {\"action\": \"restart\"}}\\n- \"how's sonarr doing?\" -> {\"action\": \"container_status\", \"container\": \"sonarr\", \"parameters\": {}}\\n- \"hello\" -> {\"action\": \"unknown\", \"container\": null, \"parameters\": {\"message\": \"I can help with Docker containers. Try: 'show logs', 'restart plex', or 'what's using memory?'\"}}", + "cache_control": {"type": "ephemeral"} + } + ], + "messages": [ + {"role": "user", "content": "{{$json.message}}"} + ] + } + ``` + - Options: Timeout 30000ms, Retry on fail (3 attempts) + +Note: n8n may need a "Header Auth" credential type created with the API key, OR use the body to include auth. Check n8n's HTTP Request node documentation for Anthropic compatibility. + +Alternative if Header Auth credential doesn't work well: +- Use "None" authentication +- Add x-api-key header manually via "Send Headers" option +- Value: Use expression referencing an n8n credential or environment variable + + +1. In n8n, navigate to Credentials and ensure Anthropic/Header credential is configured +2. Test the HTTP Request node manually with a simple message like "hello" +3. Check response contains valid JSON with action field + + Claude API HTTP Request node configured and able to receive intent parsing responses. + + + + Task 2: Create intent parsing and validation logic + n8n-workflow.json + +After Claude HTTP Request node, add "Parse Intent" Code node to validate and extract the structured intent. + +```javascript +// Parse and validate Claude's intent response +const response = $input.item.json; + +// Claude response structure: { content: [{ type: "text", text: "..." }] } +let intentText = ''; +try { + intentText = response.content[0].text; +} catch (e) { + return { + action: 'error', + error: 'Invalid Claude response structure', + raw: JSON.stringify(response) + }; +} + +// Parse JSON from Claude's response +let intent; +try { + // Claude might wrap JSON in markdown code blocks, strip them + const cleaned = intentText.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim(); + intent = JSON.parse(cleaned); +} catch (e) { + return { + action: 'error', + error: 'Could not parse intent JSON', + raw: intentText + }; +} + +// Validate required fields +const validActions = ['view_logs', 'query_stats', 'container_action', 'container_status', 'list_containers', 'unknown']; +if (!intent.action || !validActions.includes(intent.action)) { + return { + action: 'unknown', + error: 'Invalid or missing action', + parameters: { message: 'I didn\'t understand that. Try: "show logs plex" or "restart nginx"' } + }; +} + +// Normalize container name if present +if (intent.container) { + intent.container = intent.container.toLowerCase().trim(); +} + +// Set defaults for parameters +intent.parameters = intent.parameters || {}; + +return intent; +``` + + +Test Parse Intent node with various Claude responses: +1. Valid JSON response -> extracts action and container +2. Malformed JSON -> returns error action with helpful message +3. Missing action field -> returns unknown with guidance + + Intent parsing extracts and validates Claude's response into usable workflow data. + + + + Task 3: Wire intent router to existing and new handlers + n8n-workflow.json + +Restructure workflow to use intent-first routing: + +1. After auth check (existing), route ALL messages through Claude Intent Parser first (not just unknown messages). + +2. Add "Intent Router" Switch node after Parse Intent: + - Condition 1: action == "view_logs" -> Route to logs handler (from 04-01) + - Condition 2: action == "query_stats" -> Route to stats handler (placeholder for 04-03) + - Condition 3: action == "container_action" -> Route to existing actions branch + - Condition 4: action == "container_status" -> Route to existing status branch + - Condition 5: action == "list_containers" -> Route to existing status summary + - Condition 6: action == "unknown" -> Route to Unknown Intent handler + - Condition 7: action == "error" -> Route to Error handler + +3. Create "Unknown Intent" handler: + - Telegram Send Message with helpful text from intent.parameters.message + - Default: "I can help manage your Docker containers. Try:\n- 'show logs plex'\n- 'restart sonarr'\n- 'what containers are running?'\n- 'what's using the most memory?'" + +4. Create "Stats Placeholder" handler (will be replaced in 04-03): + - Returns: "Stats queries coming soon! For now, try 'status' to see running containers." + +5. Update existing action/status handlers to use intent.container instead of re-parsing message. + +Important: Keep existing command-based routing as fallback for when Claude API is unavailable (rate limit, error). Add error handling around Claude call that falls back to pattern matching. + + +Test complete flow via Telegram: +1. "show me nginx logs" -> routes to view_logs handler +2. "restart plex" -> routes to container_action handler +3. "how's sonarr?" -> routes to container_status handler +4. "what's running" -> routes to list_containers handler +5. "hello there" -> routes to unknown with helpful message +6. "what's eating memory?" -> routes to stats placeholder + + All messages routed through Claude intent parsing with appropriate handler dispatch. + + + + + + Claude API integration with intent-first message routing + +1. Open Telegram chat with the bot +2. Send: "show me the logs for n8n" + - Expected: Should return n8n container logs (if 04-01 complete) or route correctly +3. Send: "restart plex" (or any container you can safely restart) + - Expected: Should trigger restart via existing action handler +4. Send: "hey how are you" + - Expected: Should return helpful message about available commands +5. Send: "what's using the most CPU?" + - Expected: Should return "Stats queries coming soon!" placeholder +6. Check n8n execution log to verify Claude API was called and intent parsed + + Type "approved" if conversational routing works, or describe issues + + + +After all tasks: +1. Claude API credential configured in n8n +2. HTTP Request node successfully calls Claude Messages API +3. Intent parsing extracts action, container, and parameters +4. Switch node routes to correct handlers based on intent +5. Unknown intents receive helpful guidance +6. Existing command-based functionality still works + + + +- Claude Sonnet 4.5 used for intent parsing with prompt caching +- Natural language queries parsed into structured intents +- All existing functionality (status, actions) accessible via conversation +- Graceful fallback/error handling when Claude unavailable +- Unknown intents guide users toward valid commands + + + +After completion, create `.planning/phases/04-logs-intelligence/04-02-SUMMARY.md` +
tags (HTML parse mode already enabled) +- Handle empty logs gracefully: "No logs available for " +- Handle errors: "Could not retrieve logs for : " + +Wire to Telegram Send Message node for reply. +