---
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