From 0ee37acfec90a12cea99f7998ab3f52eb20df19b Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 30 Jan 2026 15:29:24 -0500 Subject: [PATCH] phase 4 planning --- .../phases/04-logs-intelligence/04-01-PLAN.md | 198 ++++++++++++++ .../phases/04-logs-intelligence/04-02-PLAN.md | 253 ++++++++++++++++++ 2 files changed, 451 insertions(+) create mode 100644 .planning/phases/04-logs-intelligence/04-01-PLAN.md create mode 100644 .planning/phases/04-logs-intelligence/04-02-PLAN.md 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`
+