| # Agent Architecture - Surviving Next.js Restarts |
|
|
| ## Problem Statement |
|
|
| When using the Automaker app to iterate on itself: |
|
|
| 1. Agent modifies code files |
| 2. Next.js hot-reloads and restarts |
| 3. API routes are killed |
| 4. Agent conversation is lost |
|
|
| ## Solution: Electron Main Process Agent |
|
|
| The agent now runs in the **Electron main process** instead of Next.js API routes. This provides: |
|
|
| - ✅ **Survives Next.js restarts** - Main process is independent of renderer |
| - ✅ **Persistent state** - Conversations saved to disk automatically |
| - ✅ **Real-time streaming** - IPC events for live updates |
| - ✅ **Session recovery** - Reconnects automatically after restart |
|
|
| ## Architecture Overview |
|
|
| ``` |
| ┌─────────────────────────────────────────┐ |
| │ Electron Main Process │ |
| │ ┌───────────────────────────────┐ │ |
| │ │ Agent Service │ │ |
| │ │ - Manages sessions │ │ |
| │ │ - Runs Claude Agent SDK │ │ |
| │ │ - Persists to disk │ │ |
| │ │ - Streams via IPC │ │ |
| │ └───────────────────────────────┘ │ |
| └──────────────┬──────────────────────────┘ |
| │ IPC (survives restarts) |
| ┌──────────────┴──────────────────────────┐ |
| │ Electron Renderer (Next.js) │ |
| │ ┌───────────────────────────────┐ │ |
| │ │ React Frontend │ │ |
| │ │ - useElectronAgent hook │ │ |
| │ │ - Auto-reconnects │ │ |
| │ │ - Real-time updates │ │ |
| │ └───────────────────────────────┘ │ |
| └─────────────────────────────────────────┘ |
| ``` |
|
|
| ## Key Components |
|
|
| ### 1. Agent Service (`electron/agent-service.js`) |
|
|
| The core service running in the Electron main process: |
|
|
| - **Session Management**: Tracks multiple conversations by session ID |
| - **State Persistence**: Saves conversations to `userData/agent-sessions/*.json` |
| - **Streaming**: Sends real-time updates to renderer via IPC |
| - **Tool Support**: Full Read/Write/Edit/Bash/Grep/Glob capabilities |
| - **Error Recovery**: Continues after errors, saves state |
|
|
| ### 2. IPC Handlers (`electron/main.js`) |
|
|
| Electron main process handlers: |
|
|
| - `agent:start` - Initialize or resume a session |
| - `agent:send` - Send a message (returns immediately) |
| - `agent:getHistory` - Retrieve conversation history |
| - `agent:stop` - Stop current execution |
| - `agent:clear` - Clear conversation |
| - `agent:stream` - Event emitted for streaming updates |
|
|
| ### 3. Preload Bridge (`electron/preload.js`) |
|
|
| Secure IPC bridge exposed to renderer: |
|
|
| ```javascript |
| window.electronAPI.agent.start(sessionId, workingDir); |
| window.electronAPI.agent.send(sessionId, message, workingDir); |
| window.electronAPI.agent.onStream(callback); |
| ``` |
|
|
| ### 4. React Hook (`src/hooks/use-electron-agent.ts`) |
|
|
| Easy-to-use React hook: |
|
|
| ```typescript |
| const { |
| messages, // Conversation history |
| isProcessing, // Agent is working |
| isConnected, // Session initialized |
| sendMessage, // Send user message |
| stopExecution, // Stop current task |
| clearHistory, // Clear conversation |
| error, // Error state |
| } = useElectronAgent({ |
| sessionId: 'project_xyz', |
| workingDirectory: '/path/to/project', |
| onToolUse: (tool) => console.log('Using:', tool), |
| }); |
| ``` |
|
|
| ### 5. Frontend Component (`src/components/views/agent-view.tsx`) |
|
|
| Updated to use IPC instead of HTTP: |
|
|
| - Generates session ID from project path |
| - Auto-reconnects on mount |
| - Shows tool usage in real-time |
| - Displays connection status |
|
|
| ## Data Flow |
|
|
| ### Sending a Message |
|
|
| 1. User types message in React UI |
| 2. `sendMessage()` calls `window.electronAPI.agent.send()` |
| 3. IPC handler in main process receives message |
| 4. Agent service starts processing |
| 5. Main process streams updates via `agent:stream` events |
| 6. React hook receives events and updates UI |
| 7. Conversation saved to disk |
|
|
| ### Surviving a Restart |
|
|
| 1. Agent is modifying code → Next.js restarts |
| 2. React component unmounts |
| 3. **Main process keeps running** (agent continues) |
| 4. React component remounts after restart |
| 5. Calls `agent:start` with same session ID |
| 6. Main process returns full conversation history |
| 7. Subscribes to `agent:stream` events |
| 8. UI shows complete conversation + live updates |
|
|
| ## Session Storage |
|
|
| Sessions are stored in: |
|
|
| ``` |
| <userData>/agent-sessions/<sessionId>.json |
| ``` |
|
|
| Each session file contains: |
|
|
| ```json |
| [ |
| { |
| "id": "msg_1234_abc", |
| "role": "user", |
| "content": "Add a new feature...", |
| "timestamp": "2024-12-07T12:00:00.000Z" |
| }, |
| { |
| "id": "msg_1235_def", |
| "role": "assistant", |
| "content": "I'll help you add that feature...", |
| "timestamp": "2024-12-07T12:00:05.000Z" |
| } |
| ] |
| ``` |
|
|
| ## Session ID Generation |
|
|
| Session IDs are generated from project paths: |
|
|
| ```typescript |
| const sessionId = `project_${projectPath.replace(/[^a-zA-Z0-9]/g, '_')}`; |
| ``` |
|
|
| This ensures: |
|
|
| - Each project has its own conversation |
| - Conversations persist across app restarts |
| - Multiple projects can run simultaneously |
|
|
| ## Streaming Events |
|
|
| The agent emits these event types: |
|
|
| ### `message` |
|
|
| User message added to conversation |
|
|
| ### `stream` |
|
|
| Assistant response streaming (updates in real-time) |
|
|
| ### `tool_use` |
| |
| Agent is using a tool (Read, Write, Edit, etc.) |
| |
| ### `complete` |
| |
| Agent finished processing |
| |
| ### `error` |
| |
| Error occurred during processing |
| |
| ## Configuration |
| |
| The agent is configured with: |
| |
| ```javascript |
| { |
| model: "claude-opus-4-6", |
| maxTurns: 20, |
| cwd: workingDirectory, |
| allowedTools: [ |
| "Read", "Write", "Edit", "Glob", "Grep", |
| "Bash", "WebSearch", "WebFetch" |
| ], |
| permissionMode: "acceptEdits", // Auto-approve file edits |
| sandbox: { |
| enabled: true, // Sandboxed bash execution |
| autoAllowBashIfSandboxed: true |
| } |
| } |
| ``` |
| |
| ## Benefits |
| |
| ### For Self-Iteration |
| |
| Now you can ask the agent to modify Automaker itself: |
| |
| ``` |
| User: "Add a dark mode toggle to the settings" |
| Agent: *modifies files* |
| → Next.js restarts |
| → Agent continues working |
| → UI reconnects automatically |
| → Shows full conversation history |
| ``` |
| |
| ### For Long-Running Tasks |
| |
| The agent can work on complex tasks that take multiple turns: |
| |
| ``` |
| User: "Implement authentication with GitHub OAuth" |
| Agent: |
| 1. Creates auth API routes |
| 2. Next.js restarts |
| 3. Agent continues: Adds middleware |
| 4. Next.js restarts again |
| 5. Agent continues: Updates UI components |
| 6. All changes tracked, conversation preserved |
| ``` |
| |
| ## Testing |
| |
| To test the architecture: |
| |
| 1. Open a project in Automaker |
| 2. Ask the agent to modify a file in `src/` |
| 3. Watch Next.js restart |
| 4. Verify the conversation continues |
| 5. Check that history is preserved |
| 6. Restart the entire Electron app |
| 7. Verify conversation loads from disk |
| |
| ## Troubleshooting |
| |
| ### "Electron API not available" |
| |
| - Make sure you're running in Electron, not browser |
| - Check `window.isElectron` is `true` |
| |
| ### Session not persisting |
| |
| - Check userData directory exists |
| - Verify write permissions |
| - Look for errors in Electron console |
| |
| ### Next.js restart kills agent |
| |
| - Verify agent service is in `electron/main.js` |
| - Check IPC handlers are registered |
| - Ensure not using HTTP `/api/chat` route |
| |
| ## Future Enhancements |
| |
| - [ ] Multiple concurrent sessions |
| - [ ] Export conversation history |
| - [ ] Undo/redo for agent actions |
| - [ ] Progress bars for long-running tasks |
| - [ ] Voice input/output |
| - [ ] Agent memory across sessions |
| |