Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6ca2655
Add three-tier AI documentation system
Mar 10, 2026
2d0bbff
Add design doc for project-centric navigation with inbox
Mar 10, 2026
3ace449
Add implementation plan for project-centric navigation
Mar 10, 2026
8c045f8
feat: add Project and InboxItem type definitions
Mar 10, 2026
0360e76
feat: add projectStore with CRUD, selectors, and tests
Mar 10, 2026
5b19b61
feat: add inboxStore with dedup, dismissal, selectors, and tests
Mar 10, 2026
ab1362d
feat: add selectSessionsByProject selector to sessionStore
Mar 10, 2026
6b3043e
feat: add projects electron-store and IPC persistence handlers
Mar 10, 2026
5d2d86b
feat: expose window.maestro.projects IPC bridge
Mar 10, 2026
3418fac
feat: add useProjectRestoration with group-to-project migration
Mar 10, 2026
209f17e
feat: add useProjectRestoration with group→project migration
Mar 10, 2026
b4d8ca5
feat: add ProjectSidebar components (InboxItem, InboxSection, Project…
Mar 10, 2026
0cbcd9a
fix: use theme colors for inbox dots, optimize selectInboxItems
Mar 10, 2026
4593046
feat: add useInboxWatcher hook for session state → inbox triggers
Mar 10, 2026
f549fa9
feat: wire ProjectSidebar, useProjectRestoration, and useInboxWatcher…
Mar 10, 2026
cb26704
feat: add keyboard shortcuts for project cycling and new project
Mar 10, 2026
1972888
refactor: remove group and bookmark code from sessionStore
Mar 10, 2026
a56e321
fix: update persistence test for new projects IPC handlers
Mar 10, 2026
f874089
docs: update CLAUDE.md for project-centric navigation
Mar 10, 2026
8873b3e
fix: add projectsStore to HandlerDependencies in IPC handler index
Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .claude/memory/agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Agent System

## Active Agents

| ID | Binary | JSON Flag | Resume Flag | Read-Only Flag | Session Storage |
|----|--------|-----------|-------------|----------------|-----------------|
| `claude-code` | `claude` | `--output-format stream-json` | `--resume <id>` | `--permission-mode plan` | `~/.claude/projects/` |
| `codex` | `codex` | `--json` | `exec resume <thread_id>` | `--sandbox read-only` | `~/.codex/sessions/` |
| `opencode` | `opencode` | `--format json` | `--session <id>` | `--agent plan` | `~/.config/opencode/storage/` |
| `factory-droid` | `factory` | `-o stream-json` | `-s <id>` | default mode | `~/.factory/` |
| `terminal` | (system shell) | N/A | N/A | N/A | N/A |

## Capabilities (23 flags per agent, `src/main/agents/capabilities.ts`)

Key flags: `supportsResume`, `supportsReadOnlyMode`, `supportsJsonOutput`, `supportsSessionId`, `supportsImageInput`, `supportsSlashCommands`, `supportsSessionStorage`, `supportsCostTracking`, `supportsUsageStats`, `supportsBatchMode`, `supportsStreaming`, `supportsModelSelection`, `supportsThinkingDisplay`, `supportsContextMerge`

UI features auto-enable/disable based on capability flags.

## Adding a New Agent (6 steps)

1. Add definition → `src/main/agents/definitions.ts`
2. Define capabilities → `src/main/agents/capabilities.ts`
3. Create output parser → `src/main/parsers/{agent}-output-parser.ts`
4. Register parser → `src/main/parsers/index.ts`
5. (Optional) Session storage → `src/main/storage/{agent}-session-storage.ts`
6. (Optional) Error patterns → `src/main/parsers/error-patterns.ts`

## Output Parser Interface

```typescript
// Common parsed event structure
type: 'init' | 'text' | 'tool_use' | 'result' | 'error' | 'usage' | 'system'
sessionId?: string
text?: string
```

Registry: `registerOutputParser(agentId, parser)` / `getOutputParser(agentId)`

## Gotcha: Agent-Specific Session ID Terminology

- Claude Code: `session_id`
- Codex: `thread_id`
- Different field names, same concept. Parsers normalize this.
86 changes: 86 additions & 0 deletions .claude/memory/build-deploy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Build System & CI/CD

## Tech Stack

| Technology | Version | Purpose |
|------------|---------|---------|
| Electron | 28.x | Desktop app shell |
| React | 18.x | UI framework |
| TypeScript | 5.x | Type safety |
| Vite | 5.x | Bundler (renderer + web) |
| Vitest | 4.x | Test framework |
| Tailwind CSS | 3.x | Utility-first styling |
| Zustand | 5.x | State management |
| node-pty | 1.x | Terminal emulation |
| better-sqlite3 | 12.x | Stats database |
| Fastify | 4.x | Web server (mobile remote) |
| Commander | 14.x | CLI framework |
| React Flow | 11.x | Document graph visualization |
| Recharts | 3.x | Usage dashboard charts |

## Build Sequence

```bash
npm run build
→ build:prompts # .md → generated TypeScript
→ build:main # tsc → dist/main (CommonJS)
→ build:preload # esbuild → dist/main/preload.js
→ build:renderer # vite → dist/renderer (ESM)
→ build:web # vite → dist/web
→ build:cli # esbuild → dist/cli
```

## TypeScript Configs (3 separate)

| Config | Module | Scope |
|--------|--------|-------|
| `tsconfig.main.json` | CommonJS | Main process + shared |
| `tsconfig.json` (root) | ESNext | Renderer + web + shared |
| `tsconfig.cli.json` | CommonJS | CLI + shared + prompts |

## CI Pipeline (`.github/workflows/ci.yml`)

**Job 1: Lint** — prettier check, eslint, tsc (all 3 configs)
**Job 2: Test** — vitest run (unit tests only)

Integration/E2E/performance tests NOT in CI (manual).

## Pre-commit Hooks

Husky + lint-staged:
- `*` → `prettier --write`
- `*.{js,ts,tsx,...}` → `eslint --fix`

Lightweight by design — heavy checks in CI.

## Packaging

```bash
npm run package # All platforms
npm run package:mac # macOS (.dmg, .zip) — x64 + arm64
npm run package:win # Windows (.exe NSIS + portable)
npm run package:linux # Linux (.AppImage, .deb, .rpm)
```

Output: `release/` directory. Auto-publish via GitHub Actions on tag push.

## Key Build Scripts (`scripts/`)

| Script | Purpose |
|--------|---------|
| `generate-prompts.mjs` | Compile .md prompts to TypeScript |
| `build-preload.mjs` | Bundle preload script with esbuild |
| `build-cli.mjs` | Bundle CLI with sourcemaps |
| `refresh-speckit.mjs` | Sync Spec-Kit prompts from GitHub |
| `refresh-openspec.mjs` | Sync OpenSpec prompts from Fission-AI |
| `set-version.mjs` | Update version across configs |
| `notarize.js` | macOS code signing post-build |

## Environment Flags

- `NODE_ENV=development` — dev mode
- `USE_PROD_DATA=1` — use production data dir in dev
- `MAESTRO_DEMO_DIR=<path>` — demo mode with fresh data
- `VITE_PORT=<port>` — custom dev server port (default 5173)
- `DISABLE_HMR=1` — disable hot module replacement
- `DEBUG_GROUP_CHAT=1` — enable group chat debug logging
60 changes: 60 additions & 0 deletions .claude/memory/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Data Model & State Management

## Zustand Stores (11 total, `src/renderer/stores/`)

| Store | Purpose | Key state |
|-------|---------|-----------|
| `sessionStore` | Sessions, groups, active session | `sessions[]`, `groups[]`, `activeSessionId` |
| `settingsStore` | User preferences | themes, fonts, agent config, SSH remotes |
| `modalStore` | 50+ modal visibility + data | Registry pattern, not 50 fields |
| `tabStore` | Tab management | unified tab order, closed tab history |
| `agentStore` | Agent detection/capabilities | detected agents, capabilities map |
| `uiStore` | UI toggles | right panel tab, focus area |
| `batchStore` | Batch runner state | progress, docs, tasks |
| `groupChatStore` | Group chat | messages, participants |
| `notificationStore` | Toast queue | notifications[] |
| `operationStore` | Long-running ops | merge/transfer progress |
| `fileExplorerStore` | File tree | expansion state, scroll |

Comment on lines +3 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update this data-model doc to match the new project/inbox architecture.

It still documents the pre-PR shape: “11” stores, no projectStore/inboxStore, no Session.projectId, and no projects persistence file. That makes this memory doc misleading for anyone implementing follow-up changes on top of the new navigation model.

Also applies to: 19-36, 47-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/memory/data-model.md around lines 3 - 18, The memory doc describes
the old 11-store layout; update it to reflect the new project/inbox navigation
by replacing the store list with the current stores (add projectStore and
inboxStore, remove or rename any deprecated stores), update `sessionStore` to
include `projectId` on Session objects, and add the new projects persistence
file and its purpose; also revise the sections referenced (lines ~19-36 and
~47-55) so descriptions, key state (e.g., `projects[]`, `activeProjectId`,
`inboxItems[]`), and purposes match the new architecture and navigation model,
ensuring identifiers like sessionStore, projectStore, inboxStore,
Session.projectId, and the projects persistence file are mentioned.

## Session Interface (key fields)

```typescript
interface Session {
id: string;
name: string;
toolType: ToolType; // 'claude-code' | 'codex' | 'opencode' | 'factory-droid'
state: SessionState; // 'idle' | 'busy' | 'connecting' | 'error'
inputMode: 'ai' | 'terminal';
cwd: string; // Changes via cd
projectRoot: string; // Never changes (used for session storage)
aiTabs: AITab[];
activeTabId: string;
filePreviewTabs: FilePreviewTab[];
activeFileTabId: string | null;
unifiedTabOrder: UnifiedTabRef[]; // TabBar source of truth
executionQueue: QueuedItem[];
}
```

## Critical Invariant: unifiedTabOrder

**Every tab MUST have an entry in `unifiedTabOrder`.** Tabs missing from this array are invisible in TabBar even if content renders.

- When adding tabs: update both tab array AND `unifiedTabOrder`
- When activating: use `ensureInUnifiedTabOrder()` from `tabHelpers.ts`
- `buildUnifiedTabs(session)` is the canonical tab list builder

## Settings Persistence

Settings stored via `electron-store` at platform-specific paths:
- macOS: `~/Library/Application Support/maestro/`
- Windows: `%APPDATA%/maestro/`
- Linux: `~/.config/maestro/`

Files: `maestro-settings.json`, `maestro-sessions.json`, `maestro-groups.json`, `maestro-agent-configs.json`

## State Management Pattern

- **Zustand** for persistent/large state (selector-based subscriptions)
- **React Context** for transient UI state (LayerStack, Input, GitStatus, InlineWizard)
- Minimal prop drilling — components read directly from stores
40 changes: 40 additions & 0 deletions .claude/memory/features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Feature-Specific Notes

## Usage Dashboard (`src/renderer/components/UsageDashboard/`)

- Backend: SQLite (`better-sqlite3`) with WAL mode → `src/main/stats-db.ts`
- Tables: `query_events`, `auto_run_sessions`, `auto_run_tasks`, `_migrations`
- Real-time: backend broadcasts `stats:updated` event, frontend debounces refresh
- Colorblind palettes: Wong-based, 3 variants → `src/renderer/constants/colorblindPalettes.ts`
- Charts wrapped in `ChartErrorBoundary` with retry

## Document Graph (`src/renderer/components/DocumentGraph/`)

- Scans markdown for `[[wiki-links]]` and `[markdown](links)`
- React Flow for visualization
- Force-directed + hierarchical layout (`layoutAlgorithms.ts`)
- File watching via chokidar (NOT available for SSH remotes)
- Large files truncated: >1MB → parse first 100KB only
- Default 50 nodes, "Load more" adds 25

## Group Chat System (`src/main/group-chat/`)

- Moderator AI orchestrates multi-agent conversations
- @mentions route messages to specific agents
- No @mentions in moderator response = conversation complete
- Output buffer: 10MB limit (larger than process-manager's 100KB)
- Storage: `~/Library/Application Support/maestro/group-chats/{chatId}/`

## Auto Run

- File-based document runner: markdown docs with checkbox tasks
- Playbooks: saved configurations for repeated batch runs
- Playbook assets: `assets/` subfolder (config files, YAML, Dockerfiles)
- Worktree support: operates in isolated git directory for true parallelization
- Achievement system: 15 conductor levels (1 min → 200 hours)

## Director's Notes (Encore Feature)

- First Encore Feature — canonical gating example
- Flag: `encoreFeatures.directorNotes`
- Generates AI synopsis of work across sessions
71 changes: 71 additions & 0 deletions .claude/memory/ipc-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# IPC API Surface

## Adding an IPC Handler

1. Create handler in `src/main/ipc/handlers/{domain}.ts`:
```typescript
export function registerMyHandlers(deps: { getStore: () => Store }) {
ipcMain.handle('myDomain:myAction', async (_, arg) => {
return result;
});
}
```
2. Register in `src/main/index.ts` → `setupIpcHandlers()`
3. Add preload API in `src/main/preload/` (module per namespace)
4. Type the API in preload types

## Handler Pattern

All handlers use dependency injection:
```typescript
registerProcessHandlers({
getProcessManager: () => processManager,
getAgentDetector: () => agentDetector,
agentConfigsStore,
settingsStore,
getMainWindow: () => mainWindow,
});
```

Error handling wrapper: `withIpcErrorLogging()` for standardized logging.

## Key Namespaces (40+)

| Namespace | Purpose |
|-----------|---------|
| `settings` | Get/set/getAll app settings |
| `sessions` / `groups` | Agent and group persistence |
| `process` | spawn, write, interrupt, kill, resize |
| `agents` | detect, getCapabilities, discoverModels |
| `agentSessions` | List/read/search provider sessions |
| `git` | status, diff, log, worktrees, createPR |
| `fs` | readDir, readFile, stat |
| `autorun` | Document + image management |
| `playbooks` | Batch run configuration CRUD |
| `stats` | Usage analytics (SQLite + WAL) |
| `groupChat` | Multi-agent coordination |
| `context` | Merge/groom/summarize sessions |
| `documentGraph` | File watching (chokidar) |
| `history` | Per-agent history (5000 entries/agent) |
| `tunnel` | Cloudflare tunnel management |
| `sshRemote` | SSH config management |
| `notification` | Desktop notifications, TTS |
| `web` / `live` / `webserver` | Web interface management |
| `symphony` | Open-source contribution system |

## IPC Handler Count

31 handler files in `src/main/ipc/handlers/` (~18,900 LOC total)

## Service Layer (Renderer)

Services in `src/renderer/services/` wrap IPC with error handling:
```typescript
// Pattern: never throw, return safe defaults
const gitService = {
async isRepo(cwd: string): Promise<boolean> {
try { return await window.maestro.git.isRepo(cwd); }
catch { return false; }
}
};
```
69 changes: 69 additions & 0 deletions .claude/memory/patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Implementation Patterns

## Settings Persistence

```typescript
// 1. State with default
const [mySetting, setMySettingState] = useState(defaultValue);

// 2. Wrapper that persists
const setMySetting = (value) => {
setMySettingState(value);
window.maestro.settings.set('mySetting', value);
};

// 3. Load from batch in useEffect
const allSettings = await window.maestro.settings.getAll();
if (allSettings['mySetting'] !== undefined) setMySettingState(allSettings['mySetting']);
```

## Adding a Modal

1. Create component in `src/renderer/components/`
2. Add priority in `src/renderer/constants/modalPriorities.ts`
3. Register with layer stack (use `onCloseRef` pattern to avoid re-registration):
```typescript
const onCloseRef = useRef(onClose);
onCloseRef.current = onClose;
useEffect(() => {
if (isOpen) {
const id = registerLayer({
type: 'modal',
priority: MODAL_PRIORITIES.YOUR_MODAL,
onEscape: () => onCloseRef.current(),
});
return () => unregisterLayer(id);
}
}, [isOpen, registerLayer, unregisterLayer]); // onClose NOT in deps
```

## Theme Colors

13 required colors per theme. Use inline styles for theme colors:
```typescript
style={{ color: theme.colors.textMain }} // Correct
className="text-gray-500" // Wrong for themed text
```
Use Tailwind for layout only.

## Encore Features (Feature Gating)

Gate ALL access points when adding new Encore Features:
1. Type flag → `EncoreFeatureFlags` in `src/renderer/types/index.ts`
2. Default `false` → `useSettings.ts`
3. Toggle UI → SettingsModal Encore tab
4. App.tsx → conditional rendering + callbacks
5. Keyboard shortcuts → guard with `ctx.encoreFeatures?.yourFeature`
6. Hamburger menu → make setter optional, conditional render
7. Command palette → pass `undefined` handler when disabled

## Execution Queue

Messages queue when AI is busy. Write ops queue sequentially; read-only can parallelize.

## Lazy Component Loading

Heavy modals loaded on-demand in App.tsx:
```typescript
const SettingsModal = lazy(() => import('./components/Settings/SettingsModal'));
```
Loading