Docker's /images/create API streams progress JSON for every layer.
For large images, this can be gigabytes of output that was being
buffered by curl and n8n, causing hangs and disk usage spikes.
Now pipes through `tail -c 10000` to only keep the last 10KB where
error/success messages appear. Discards the streaming progress data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Reference $('Format Update Result') instead of $json for currentImageId
- The Telegram node doesn't pass through input data, it returns API response
- Also add no-op command fallback when currentImageId is missing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --max-time 600 (10 min) to curl pull command
- Add timeout: 660 to n8n executeCommand node
Docker's /images/create API streams progress until complete.
Without timeout, large image pulls could hang indefinitely.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Testing session found and fixed multiple issues:
- Show Menu keyboard/HTML issues
- Container exact match priority
- Update acknowledgment and error handling
- Old image removal after update
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Send "Updating <container>..." message immediately when update starts
so user knows the command was received during long image pulls
2. Check pull response for rate limiting and other errors before
continuing with update. Errors like "toomanyrequests" now show
a proper error message instead of silently failing to update.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mimics Unraid's update behavior by removing the orphan image after
the new container is started. The old image ID is now passed through
the entire update flow and used to call DELETE /images/{id} at the end.
Removal is fire-and-forget with force=false so it will fail gracefully
if another container still uses the image.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed matching in Match Container, Match Update Container, and Match
Logs Container nodes:
1. First check for exact name match (e.g., "jellyplex" matches only jellyplex)
2. Then fall back to substring matching (container name contains query)
3. Removed reverse matching (query contains container name) which caused
"jellyplex" to incorrectly match "plex"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Native Telegram node replyKeyboard wasn't displaying. Fallback to
simple text message listing available commands. Can revisit persistent
keyboard feature later.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP Request node with $credentials reference was causing 404 errors.
Native Telegram node handles credentials more reliably for static menus.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
n8n IF nodes don't support credentials - $credentials syntax only works
in nodes that make external calls. Reverted to direct user ID in the
IF conditions and updated README with simpler configuration instructions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Step-by-step installation guide for Unraid
- n8n container configuration with Docker socket access
- Credential creation instructions for Telegram API and Auth
- Usage section with all 6 commands documented
- No troubleshooting section (focused on initial setup)
Tasks completed: 2/2
- Standardize error messages to terse format
- Migrate user ID to n8n credentials system
SUMMARY: .planning/phases/05-polish-deploy/05-02-SUMMARY.md
- Auth nodes now reference $credentials.telegramAuth.userId
- Added telegramAuth credential reference to both IF nodes
- Removed hardcoded user ID from workflow JSON
- Workflow can now be safely exported/shared
- Docker socket errors now show 'Cannot connect to Docker'
- Action failures now show 'Failed to {action} {container}'
- Removed HTTP status codes and technical details from error messages
- Simplified callback action error handling
- Remove Prepare Claude Request, Claude Intent Parser, Parse Intent,
Intent Router, Send Unknown Intent, Send Intent Error nodes
- Remove Anthropic API credential reference
- Rename Route Message to Keyword Router with updated rules
- Update IF User Authenticated to connect to Keyword Router
- Update Parse and Match to work without NLU context
- Update Parse Action Command to parse from message text directly
- Update Match Container to reference Parse Action Command
- Update Parse Logs Command to work with keyword routing
Keyword Router handles: /start, status, restart, start, stop,
update, logs with fallback to menu
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Workflow currently has Claude API nodes that need removal.
Added to Phase 5 scope along with keyword routing replacement.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove Claude API integration and intent parsing (04-02-PLAN)
- REQ-08 (conversational queries) moved to out of scope
- Phase 4 renamed from "Logs & Intelligence" to "Logs" (complete)
- v1.0 now focuses on keyword-based container control
Simple substring matching works well for container management.
NLU adds complexity without proportional value for v1.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP Request node with credential access via URL expression was
failing. Native Telegram node handles credentials internally and
is more reliable for this use case.
Add defensive error handling to throw clear error if chatId is
missing before attempting to send Telegram message. This helps
debug 'resource not found' errors by identifying data flow issues.
Fixed Check Match Count and Check Update Match Count nodes:
- Changed typeValidation from 'strict' to 'loose'
- Changed rightValue from strings ('0', '1') to numbers (0, 1)
- Removed empty leftValue from options
This fixes 'Wrong type: string but expecting number' errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed Match Container to get action data from Parse Intent node
instead of the old Parse Action node which isn't executed in the
intent-based routing flow.
Mapping:
- action -> intent.parameters.action
- containerQuery -> intent.container
- chatId -> intent.original_message.chat.id
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Parse and Match now returns formatted text directly, so Format Response
node is redundant. Connect Parse and Match directly to Send Docker Response
to avoid 'Unexpected response format' error.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed typeValidation from 'strict' to 'loose' and rightValue from
strings to numbers to fix type mismatch error in Switch node conditions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split Claude API call into two nodes:
- Prepare Claude Request: Code node that builds the request body
- Claude Intent Parser: HTTP Request node that sends the request
This fixes the 'model: Field Required' error caused by complex
expression evaluation issues in the HTTP Request node's jsonBody.
Also updated Parse Intent to get original message from the new node.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed empty leftValue from options and changed condition check from
object notEmpty to string notEmpty using optional chaining on specific
properties (message?.text, callback_query?.id).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Connection keys referenced hyphenated IDs (code-parse-logs) instead of
actual node names (Parse Logs Command). Fixed 10 connection sources to
use proper node names.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Answer Batch Query to dismiss callback loading state
- Add Delete Batch Confirm Message to remove confirmation message
- Add Send Batch Result to display final success/failure message
- Wire up complete flow: Format Result -> Answer -> Delete -> Send
- UI cleanup keeps chat clean with only result message remaining
- Update Parse Callback Data to detect batch (c is array) vs single
- Add isBatch and containerIds fields to callback data
- Add 'batch' route in Route Callback switch (output 2)
- Add Build Batch Commands node to prepare curl commands for each container
- Add Prepare Batch Execution to combine commands with result markers
- Add Execute Batch Action to run all container actions sequentially
- Add Parse Batch Result to parse RESULT_N:statusCode output
- Add Format Batch Result to build success/failure message
- Replace placeholder 'Format Multiple Matches' with 'Build Batch Keyboard'
- Create inline_keyboard with 'Yes, <action> N containers' and 'Cancel' buttons
- Encode batch container IDs in callback_data (limit 4 for 64-byte constraint)
- Use HTTP Request for sendMessage (same pattern as suggestion flow)
- Format container list with bullet points in confirmation message
- Add Parse Callback Data code node to decode callback_query JSON
- Add Route Callback switch for cancel/expired/execute branches
- Add Handle Cancel with answer query and delete message
- Add Handle Expired with alert message and delete message
- Add Build Callback Action to construct curl command from callback
- Add Execute Callback Action to run Docker API call
- Add Parse Callback Result to check status and build response
- Add Answer Action Query, Delete Suggestion Message, Send Callback Result
- 2-minute timeout enforced via timestamp in callback_data
- Replace Format No Match with Find Closest Match code node
- Add Check Suggestion IF node to route based on hasSuggestion
- Add Build Suggestion Keyboard code node for inline button payload
- Add Send Suggestion HTTP Request to Telegram API with inline_keyboard
- Update Match Container to include allContainers for suggestion logic
- Suggestion shown when score >= 2 (partial match found)
- Update Telegram Trigger to receive both message and callback_query updates
- Add Route Update Type switch to route messages vs callbacks
- Add IF Callback Authenticated node for callback query auth
- Restructure connections: message flow through auth, callback through separate auth