docs(09): create phase plan

Phase 09: Batch Operations
- 4 plans in 4 waves
- 3 autonomous, 1 with checkpoint
- Ready for execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Berger
2026-02-03 21:01:06 -05:00
parent 3ca89c3815
commit a409671dc6
5 changed files with 817 additions and 4 deletions
@@ -0,0 +1,188 @@
---
phase: 09-batch-operations
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [n8n-workflow.json]
autonomous: true
must_haves:
truths:
- "User can type 'update plex sonarr radarr' and bot recognizes multiple containers"
- "Fuzzy matching finds containers even with partial names"
- "Exact match gets priority (plex matches plex, not jellyplex)"
- "Ambiguous matches show disambiguation prompt"
artifacts:
- path: "n8n-workflow.json"
provides: "Batch command parsing and container matching"
contains: "Parse Batch Command"
key_links:
- from: "Parse Batch Command node"
to: "Match Containers node"
via: "Parsed action and container names array"
pattern: "containerNames.*split"
- from: "Match Containers node"
to: "disambiguation or execution path"
via: "Switch based on match results"
pattern: "needsDisambiguation"
---
<objective>
Parse multi-container batch commands and match container names with fuzzy matching and exact-match priority.
Purpose: Enable batch operations by recognizing commands like "update plex sonarr radarr" and resolving container names accurately.
Output: Workflow nodes that parse batch commands and match containers, with disambiguation for ambiguous matches.
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/09-batch-operations/09-CONTEXT.md
@.planning/phases/09-batch-operations/09-RESEARCH.md
@.planning/phases/08-inline-keyboard-infrastructure/08-01-SUMMARY.md
@n8n-workflow.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Add batch command detection and parsing</name>
<files>n8n-workflow.json</files>
<action>
Add a new branch in the command routing logic to detect batch commands (multiple container names after action keyword).
1. In the existing command matching flow (after "Extract Keywords" or equivalent), add a Code node "Detect Batch Command":
- Input: message text
- Check if command matches pattern: `{action} {name1} {name2} ...` where action is update/start/stop/restart
- Parse action and container names array (split by spaces after action keyword)
- Output: `{ isBatch: boolean, action: string, containerNames: string[], originalMessage: string }`
- Single container = not batch (handled by existing flow)
- Two or more containers = batch
2. Add an IF node "Is Batch Command" that routes:
- TRUE: To new batch processing flow (Plan 01-02 nodes)
- FALSE: To existing single-container flow (preserve current behavior)
3. The batch flow should NOT trigger for:
- "status" (always shows list)
- "logs {name} {count}" (second word is line count, not container)
- Commands with only one container name
Callback format from context: Existing callbacks use colon-separated format. Batch text commands use space-separated. Keep them distinct.
</action>
<verify>
Test via n8n execution:
- "update plex sonarr" -> isBatch: true, action: "update", containerNames: ["plex", "sonarr"]
- "update plex" -> isBatch: false (single container, use existing flow)
- "logs plex 50" -> isBatch: false (logs has line count parameter)
- "status" -> Not routed to batch flow
</verify>
<done>Batch commands detected and parsed into action + container names array; single-container commands continue to existing flow</done>
</task>
<task type="auto">
<name>Task 2: Add container name matching with exact-match priority</name>
<files>n8n-workflow.json</files>
<action>
Add container matching logic that resolves user-provided names to actual container names.
1. Add Code node "Match Batch Containers":
- Input: `containerNames` array from batch parser, `containers` array from Docker API (reuse existing "Get All Containers" HTTP node)
- For each user-provided name:
a. Normalize: lowercase, trim whitespace
b. Check exact match first: `containers.find(c => c.Names[0].replace('/', '').toLowerCase() === normalized)`
c. If no exact match, check substring match: `containers.filter(c => c.Names[0].toLowerCase().includes(normalized))`
d. Record match result: { input: "plex", matched: "plex", type: "exact" } or { input: "plex", matches: ["plex", "jellyplex"], type: "ambiguous" }
- Aggregate results into: `{ allMatched: Container[], needsDisambiguation: { input, matches }[], notFound: string[] }`
2. Add IF node "Needs Disambiguation":
- TRUE (any ambiguous matches): Route to disambiguation message
- FALSE (all matched or some not found): Continue to batch execution or error
3. Add Code node "Build Disambiguation Message" for ambiguous matches:
- Format: "Multiple matches found:\n- 'plex' could match: plex, jellyplex\nPlease be more specific."
- Include inline keyboard with exact container names as buttons for user to select
4. Add Code node "Build Not Found Message" for completely unmatched names:
- Format: "Container not found: {name}"
- Only show if notFound array is not empty and no disambiguation needed
Decision from context: "if 'plex' matches both 'plex' and 'jellyplex', user should be able to specify they want only 'plex'" - this is why exact match has priority. If user types exact name, it wins.
</action>
<verify>
Test via n8n execution with mock container list ["plex", "jellyplex", "sonarr", "radarr"]:
- Input ["plex"] -> exact match "plex", no disambiguation
- Input ["jelly"] -> ambiguous, matches ["jellyplex"], could ask if they meant jellyplex
- Input ["plex", "sonarr"] -> both exact match, no disambiguation
- Input ["notacontainer"] -> notFound: ["notacontainer"]
</verify>
<done>Container names resolved with exact-match priority; ambiguous matches show disambiguation; not-found names reported clearly</done>
</task>
<task type="auto">
<name>Task 3: Wire batch routing and add "batch stop" confirmation</name>
<files>n8n-workflow.json</files>
<action>
Complete the batch command routing and add confirmation for batch stop operations.
1. Wire the routing from "Is Batch Command" TRUE output:
- Connect to "Get All Containers" (reuse existing node or create duplicate for batch)
- Then to "Match Batch Containers"
- Then to "Needs Disambiguation" IF node
- Disambiguation TRUE -> "Build Disambiguation Message" -> "Send Disambiguation" (HTTP editMessageText or sendMessage)
- Disambiguation FALSE -> Check action type
2. Add Switch node "Route Batch Action":
- update: Continue to batch execution (Plan 02)
- start/restart: Continue to batch execution (Plan 02) - immediate, no confirmation
- stop: Route to confirmation flow (batch stop is dangerous per context)
3. Add confirmation flow for batch stop (per context: "Batch stop confirms due to fuzzy matching risk"):
- Code node "Build Batch Stop Confirmation": "Stop {N} containers?\n\n{list names}\n\n[Confirm] [Cancel]"
- Callback format: `bstop:confirm:{comma-separated-names}:{timestamp}` or `bstop:cancel`
- HTTP node to send confirmation message with inline keyboard
- Add to Route Callback node: handle `bstop:` prefix callbacks
- On confirm: check 30-second timeout, then continue to batch execution
- On cancel: return to container list
4. Named batch update/start/restart run immediately without confirmation (per context: "Named batches run immediately without confirmation").
</action>
<verify>
Test via n8n execution:
- "update plex sonarr" -> Matches containers, routes to batch update (output waits for Plan 02)
- "stop plex sonarr" -> Shows confirmation "Stop 2 containers? plex, sonarr [Confirm] [Cancel]"
- "start plex sonarr" -> Routes to batch start immediately (no confirmation)
- Disambiguation keyboard buttons work and re-route correctly
</verify>
<done>Batch commands route correctly; batch stop shows confirmation; other batch actions proceed immediately; disambiguation allows user selection</done>
</task>
</tasks>
<verification>
1. Workflow imports successfully in n8n
2. Batch command detection works for all action types
3. Container matching prioritizes exact matches
4. Disambiguation shows when multiple fuzzy matches exist
5. Batch stop shows confirmation dialog
6. Existing single-container commands still work unchanged
</verification>
<success_criteria>
- "update plex sonarr" parses into batch update for two containers
- "stop plex sonarr" shows confirmation before executing
- "plex" exactly matches "plex" even when "jellyplex" exists
- Ambiguous input like "jelly" prompts for clarification
- Single-container commands route to existing flow (no regression)
</success_criteria>
<output>
After completion, create `.planning/phases/09-batch-operations/09-01-SUMMARY.md`
</output>