diff --git a/.planning/phases/03-generate-node-refactor/03-01-PLAN.md b/.planning/phases/03-generate-node-refactor/03-01-PLAN.md
new file mode 100644
index 00000000..4a923ae8
--- /dev/null
+++ b/.planning/phases/03-generate-node-refactor/03-01-PLAN.md
@@ -0,0 +1,143 @@
+---
+phase: 03-generate-node-refactor
+plan: 01
+type: execute
+---
+
+
+Rename NanoBanana node to Generate and add multi-provider model selector.
+
+Purpose: Transform the hardcoded Gemini-only node into a generic generation node that can use any provider's models.
+Output: Generate node component with provider/model dropdown, updated types, store functions renamed.
+
+
+
+~/.claude/get-shit-done/workflows/execute-phase.md
+~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Prior phase context:
+@.planning/phases/01-provider-infrastructure/01-02-SUMMARY.md
+@.planning/phases/02-model-discovery/02-03-SUMMARY.md
+
+# Key source files:
+@src/components/nodes/NanoBananaNode.tsx
+@src/types/index.ts
+@src/store/workflowStore.ts
+@src/lib/providers/types.ts
+
+**Tech stack available:** Zustand, React, ProviderModel interface, /api/models endpoint
+**Established patterns:** Provider self-registration, localStorage settings persistence
+**Constraining decisions:**
+- Keep nanoBanana node type internally for backward compatibility
+- Gemini models use internal names (nano-banana, nano-banana-pro)
+
+
+
+
+
+ Task 1: Update types for multi-provider model selection
+ src/types/index.ts
+
+ 1. Add new types for selected model:
+ - `SelectedModel` interface with { provider: ProviderType, modelId: string, displayName: string }
+ - Keep existing ModelType for backward compatibility
+
+ 2. Update NanoBananaNodeData interface:
+ - Add optional `selectedModel?: SelectedModel` field
+ - Keep existing `model: ModelType` field for Gemini backward compatibility
+
+ 3. Add "gemini" to ProviderType union if not already present (it should be the Gemini provider identifier)
+
+ WHY: NanoBananaNodeData needs to store either legacy Gemini model selection OR new multi-provider selection. The optional selectedModel field enables graceful migration.
+
+ npx tsc --noEmit passes
+ Types compile, SelectedModel interface exists, NanoBananaNodeData has selectedModel field
+
+
+
+ Task 2: Rename component to GenerateNode with model selector UI
+ src/components/nodes/NanoBananaNode.tsx, src/components/nodes/index.ts
+
+ 1. Rename file from NanoBananaNode.tsx to GenerateNode.tsx
+
+ 2. Rename component from NanoBananaNode to GenerateNode (keep function export name)
+
+ 3. Add model selector UI that shows:
+ - Provider dropdown (gemini, replicate, fal) - only show enabled providers
+ - Model dropdown (fetched from /api/models for selected provider)
+ - For Gemini, show existing hardcoded models (Nano Banana, Nano Banana Pro)
+ - For other providers, fetch models dynamically
+
+ 4. When provider/model changes:
+ - Update node data with selectedModel: { provider, modelId, displayName }
+ - For Gemini, also update legacy model field for backward compatibility
+
+ 5. Keep existing aspect ratio/resolution controls for Gemini models
+ - Hide them for non-Gemini models (parameters will come from provider schema later)
+
+ 6. Update index.ts to export GenerateNode and alias it as NanoBananaNode for backward compatibility:
+ ```typescript
+ export { GenerateNode } from "./GenerateNode";
+ export { GenerateNode as NanoBananaNode } from "./GenerateNode";
+ ```
+
+ WHY: The component rename reflects its new multi-provider purpose. The alias maintains backward compatibility with existing imports.
+
+ npm run build succeeds, component renders in browser
+ GenerateNode.tsx exists, shows provider selector, model dropdown fetches from API for non-Gemini providers
+
+
+
+ Task 3: Update store and canvas references
+ src/store/workflowStore.ts, src/components/WorkflowCanvas.tsx
+
+ 1. In workflowStore.ts:
+ - Rename saveNanoBananaDefaults to saveGenerateDefaults (keep old name as alias)
+ - Rename loadNanoBananaDefaults to loadGenerateDefaults (keep old name as alias)
+ - Update localStorage key comment but keep actual key for migration
+ - Update createDefaultNodeData for "nanoBanana" case to include default selectedModel for Gemini
+
+ 2. In WorkflowCanvas.tsx:
+ - Update nodeTypes registration to use GenerateNode
+ - Keep "nanoBanana" as the type key (internal type name unchanged)
+ - Update minimap color mapping if it references "nanoBanana"
+
+ 3. In any file using NanoBananaNode import:
+ - Update import to use GenerateNode
+ - Files: ConnectionDropMenu.tsx, FloatingActionBar.tsx, etc.
+
+ WHY: Internal references update to new names while keeping the node type string "nanoBanana" for workflow file compatibility.
+
+ npm run build succeeds, existing workflows load correctly
+ All imports updated, store functions renamed with aliases, workflows still load
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npm run build` succeeds without errors
+- [ ] `npx tsc --noEmit` passes type checking
+- [ ] GenerateNode renders with provider dropdown
+- [ ] Gemini models show in model selector
+- [ ] Existing workflows with nanoBanana nodes still load
+
+
+
+
+- All tasks completed
+- All verification checks pass
+- GenerateNode component exists with multi-provider UI
+- Types support both legacy Gemini and new multi-provider selection
+- Backward compatibility maintained for existing workflows
+
+
+
diff --git a/.planning/phases/03-generate-node-refactor/03-02-PLAN.md b/.planning/phases/03-generate-node-refactor/03-02-PLAN.md
new file mode 100644
index 00000000..4954f2c1
--- /dev/null
+++ b/.planning/phases/03-generate-node-refactor/03-02-PLAN.md
@@ -0,0 +1,165 @@
+---
+phase: 03-generate-node-refactor
+plan: 02
+type: execute
+---
+
+
+Add provider-specific execution logic to the generate API route.
+
+Purpose: Enable the generate endpoint to route requests to the correct provider (Gemini, Replicate, fal.ai) based on the selected model.
+Output: Updated /api/generate route that dispatches to provider-specific generation logic.
+
+
+
+~/.claude/get-shit-done/workflows/execute-phase.md
+~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Prior plan context:
+@.planning/phases/03-generate-node-refactor/03-01-SUMMARY.md
+
+# Key source files:
+@src/app/api/generate/route.ts
+@src/lib/providers/types.ts
+@src/lib/providers/replicate.ts
+@src/lib/providers/fal.ts
+@src/lib/providers/index.ts
+
+**Tech stack available:** ProviderInterface with generate() method, provider registry
+**Established patterns:** API routes return { success, data/error }, provider self-registration
+**Constraining decisions:**
+- Gemini generation logic already works, preserve it
+- Provider implementations have generate() method defined in ProviderInterface
+
+
+
+
+
+ Task 1: Implement generate() method in Replicate provider
+ src/lib/providers/replicate.ts
+
+ 1. Implement the generate() method that currently throws "not implemented":
+ - Accept GenerationInput with model, prompt, images, parameters
+ - Call Replicate's prediction API: POST https://api.replicate.com/v1/predictions
+ - Handle input format: { version: model.id, input: { prompt, image?, ...parameters } }
+ - Poll for completion (Replicate is async) or use webhook pattern
+ - Return GenerationOutput with image/video data
+
+ 2. Handle image input:
+ - If images provided, check if Replicate model expects URLs
+ - For now, skip image input (Phase 5 adds image URL server)
+ - Log warning if images provided but skipped
+
+ 3. Fetch output:
+ - Poll GET /predictions/{id} until status is "succeeded" or "failed"
+ - Convert output URL to base64 data URL
+ - Return in GenerationOutput format
+
+ WHY: Replicate requires polling for async predictions. The generate() method encapsulates this complexity.
+
+ TypeScript compiles, generate() method exists and doesn't throw immediately
+ Replicate provider has working generate() method that calls prediction API
+
+
+
+ Task 2: Implement generate() method in fal.ai provider
+ src/lib/providers/fal.ts
+
+ 1. Implement the generate() method:
+ - Accept GenerationInput with model, prompt, images, parameters
+ - Call fal.ai's run endpoint: POST https://fal.run/{model.id}
+ - Include prompt and parameters in request body
+ - fal.ai is synchronous (waits for result)
+
+ 2. Handle auth:
+ - Use "Key {apiKey}" header format (already established)
+ - API key optional but rate limited without it
+
+ 3. Parse response:
+ - Extract image/video URL from response
+ - Convert to base64 data URL for consistency
+ - Handle different output formats (images array, video URL, etc.)
+
+ WHY: fal.ai's synchronous API is simpler than Replicate. The generate() method normalizes the response format.
+
+ TypeScript compiles, generate() method exists
+ fal.ai provider has working generate() method that calls fal.run endpoint
+
+
+
+ Task 3: Update generate API route to dispatch by provider
+ src/app/api/generate/route.ts
+
+ 1. Update request type to accept either:
+ - Legacy format: { model: ModelType, prompt, images, aspectRatio, resolution, useGoogleSearch }
+ - New format: { selectedModel: SelectedModel, prompt, images, parameters }
+
+ 2. Add provider dispatch logic:
+ ```typescript
+ if (body.selectedModel) {
+ // New multi-provider path
+ const { provider, modelId } = body.selectedModel;
+ if (provider === "gemini") {
+ // Use existing Gemini logic
+ } else {
+ // Get provider and call generate()
+ const providerImpl = getProvider(provider);
+ const model = await providerImpl.getModel(modelId);
+ const result = await providerImpl.generate({
+ model,
+ prompt: body.prompt,
+ images: body.images,
+ parameters: body.parameters
+ });
+ return NextResponse.json(result);
+ }
+ } else {
+ // Legacy Gemini path (existing code)
+ }
+ ```
+
+ 3. Extract Gemini-specific logic into helper function for clarity
+
+ 4. Ensure API key handling:
+ - For Gemini: use GEMINI_API_KEY from env
+ - For Replicate/fal: get from provider.getApiKey() (localStorage via client header)
+
+ 5. Add client headers for API keys:
+ - Accept X-Replicate-API-Key and X-Fal-API-Key headers
+ - Pass to provider implementations
+
+ WHY: The route becomes a dispatcher that preserves existing Gemini behavior while enabling new providers.
+
+ npm run build succeeds, existing Gemini generation still works
+ Generate route dispatches to correct provider, Gemini still works as before
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npm run build` succeeds without errors
+- [ ] Existing Gemini generation works (test with existing workflow)
+- [ ] Replicate provider generate() method implemented
+- [ ] fal.ai provider generate() method implemented
+- [ ] API route accepts both legacy and new request formats
+
+
+
+
+- All tasks completed
+- All verification checks pass
+- Generate API routes to correct provider based on selectedModel
+- Gemini generation unchanged for backward compatibility
+- Replicate and fal.ai providers have generate() implementations
+
+
+
diff --git a/.planning/phases/03-generate-node-refactor/03-03-PLAN.md b/.planning/phases/03-generate-node-refactor/03-03-PLAN.md
new file mode 100644
index 00000000..da0d89ad
--- /dev/null
+++ b/.planning/phases/03-generate-node-refactor/03-03-PLAN.md
@@ -0,0 +1,154 @@
+---
+phase: 03-generate-node-refactor
+plan: 03
+type: execute
+---
+
+
+Ensure backward compatibility for existing workflows containing nanoBanana nodes.
+
+Purpose: Existing saved workflows must load and execute correctly without modification.
+Output: Migration logic, verified backward compatibility, updated workflow execution.
+
+
+
+~/.claude/get-shit-done/workflows/execute-phase.md
+~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+
+# Prior plan context:
+@.planning/phases/03-generate-node-refactor/03-01-SUMMARY.md
+@.planning/phases/03-generate-node-refactor/03-02-SUMMARY.md
+
+# Key source files:
+@src/store/workflowStore.ts
+@src/types/index.ts
+@src/components/nodes/GenerateNode.tsx
+
+**Tech stack available:** Zustand, workflow JSON persistence
+**Established patterns:** Workflow load/save in workflowStore
+**Constraining decisions:**
+- Node type "nanoBanana" must remain unchanged in workflow files
+- Legacy ModelType ("nano-banana", "nano-banana-pro") must still work
+
+
+
+
+
+ Task 1: Add migration logic for loaded workflows
+ src/store/workflowStore.ts
+
+ 1. In loadWorkflow() or where workflow JSON is parsed, add migration:
+ - When loading a nanoBanana node without selectedModel field
+ - Automatically set selectedModel based on legacy model field:
+ ```typescript
+ if (node.type === "nanoBanana" && node.data.model && !node.data.selectedModel) {
+ node.data.selectedModel = {
+ provider: "gemini",
+ modelId: node.data.model,
+ displayName: node.data.model === "nano-banana" ? "Nano Banana" : "Nano Banana Pro"
+ };
+ }
+ ```
+
+ 2. Keep legacy model field synced for saves:
+ - When selectedModel is Gemini, also update the model field
+ - This ensures old versions can still read the workflow
+
+ 3. Add version field to workflow if not present:
+ - Set workflowVersion in saved JSON for future migrations
+ - Not strictly necessary but good practice
+
+ WHY: Migration on load allows old workflows to work without manual editing. Syncing both fields maintains bidirectional compatibility.
+
+ Load an existing workflow file, check node data has both model and selectedModel
+ Old workflows load with selectedModel populated, new saves include both fields
+
+
+
+ Task 2: Update executeWorkflow for multi-provider generation
+ src/store/workflowStore.ts
+
+ 1. In executeWorkflow()'s nanoBanana case:
+ - Check if node has selectedModel
+ - If selectedModel exists and provider !== "gemini", pass API keys in headers:
+ ```typescript
+ const headers: Record = {
+ "Content-Type": "application/json"
+ };
+ if (nodeData.selectedModel?.provider === "replicate") {
+ const settings = get().providerSettings;
+ const replicateConfig = settings.providers.find(p => p.id === "replicate");
+ if (replicateConfig?.apiKey) {
+ headers["X-Replicate-API-Key"] = replicateConfig.apiKey;
+ }
+ }
+ // Similar for fal
+ ```
+
+ 2. Build request payload:
+ - Include selectedModel in request body for new providers
+ - Keep existing fields for Gemini backward compatibility
+
+ 3. Handle response format:
+ - Provider generate() returns GenerationOutput with outputs array
+ - Extract first image/video output as outputImage
+ - For video outputs, store separately (Phase 6 handles video display)
+
+ WHY: The store's execution logic needs to pass provider API keys (stored client-side) to the server route.
+
+ Execute workflow with Gemini model, verify generation still works
+ Workflow execution handles both legacy and new model selection formats
+
+
+
+ Task 3: Update GenerateNode to handle legacy data
+ src/components/nodes/GenerateNode.tsx
+
+ 1. When component mounts or data changes:
+ - If model exists but not selectedModel, derive selectedModel from model
+ - Display the correct provider/model in dropdowns
+
+ 2. Ensure UI state reflects actual node data:
+ - Provider dropdown shows "gemini" for legacy nodes
+ - Model dropdown shows correct Gemini model name
+
+ 3. When saving defaults, save in both formats:
+ - saveGenerateDefaults should save both model and selectedModel
+ - Ensures new nodes get correct defaults
+
+ WHY: The UI must correctly display legacy nodes that were migrated on load.
+
+ Open workflow with old nanoBanana node, verify dropdowns show correct selection
+ GenerateNode displays correct provider/model for both legacy and new nodes
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `npm run build` succeeds without errors
+- [ ] Load existing workflow with nanoBanana nodes - nodes display correctly
+- [ ] Execute existing workflow - Gemini generation works
+- [ ] Create new Generate node - defaults are correct
+- [ ] Save and reload workflow - data persists correctly
+
+
+
+
+- All tasks completed
+- All verification checks pass
+- Existing workflows load and execute without errors
+- Migration logic populates selectedModel from legacy model field
+- Both old and new format nodes work in same workflow
+- Phase 3 complete
+
+
+