diff --git a/docs/configuration.md b/docs/configuration.md index 1ee65512..78f6a6f4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -12,7 +12,7 @@ Settings are organized into tabs: | Tab | Contents | |-----|----------| -| **General** | Shell configuration, input send behavior, default toggles (history, thinking), automatic tab naming, power management, updates, privacy, usage stats, storage location | +| **General** | About Me (conductor profile), shell configuration, input send behavior, default toggles (history, thinking), automatic tab naming, power management, updates, privacy, usage stats, storage location | | **Display** | Font family and size, terminal width, log level and buffer, max output lines per response, document graph settings, context window warnings | | **Shortcuts** | Customize keyboard shortcuts (see [Keyboard Shortcuts](./keyboard-shortcuts)) | | **Themes** | Dark, light, and vibe mode themes, custom theme builder with import/export | diff --git a/docs/slash-commands.md b/docs/slash-commands.md index 4aaafae0..dc283706 100644 --- a/docs/slash-commands.md +++ b/docs/slash-commands.md @@ -44,6 +44,12 @@ Create your own slash commands in **Settings → AI Commands**. Each command has Commands support **template variables** that are automatically substituted at runtime: +### Conductor Variables + +| Variable | Description | +|----------|-------------| +| `{{CONDUCTOR_PROFILE}}` | Your "About Me" profile from Settings → General. Tells agents about your background, preferences, and communication style. | + ### Agent Variables | Variable | Description | diff --git a/src/__tests__/renderer/components/SettingsModal.test.tsx b/src/__tests__/renderer/components/SettingsModal.test.tsx index 3192a233..d858f297 100644 --- a/src/__tests__/renderer/components/SettingsModal.test.tsx +++ b/src/__tests__/renderer/components/SettingsModal.test.tsx @@ -68,6 +68,10 @@ vi.mock('../../../renderer/components/CustomThemeBuilder', () => ({ // Mock useSettings hook (used for context management settings and SSH remote ignore settings) vi.mock('../../../renderer/hooks/settings/useSettings', () => ({ useSettings: () => ({ + // Conductor profile settings + conductorProfile: '', + setConductorProfile: vi.fn(), + // Context management settings contextManagementSettings: { autoGroomContexts: true, maxContextTokens: 100000, diff --git a/src/__tests__/renderer/components/Wizard/WizardKeyboardNavigation.test.tsx b/src/__tests__/renderer/components/Wizard/WizardKeyboardNavigation.test.tsx index 421a025c..dcfcce96 100644 --- a/src/__tests__/renderer/components/Wizard/WizardKeyboardNavigation.test.tsx +++ b/src/__tests__/renderer/components/Wizard/WizardKeyboardNavigation.test.tsx @@ -154,6 +154,12 @@ const mockMaestro = { shell: { openExternal: vi.fn(), }, + sshRemote: { + getConfigs: vi.fn().mockResolvedValue({ success: true, configs: [] }), + }, + sessions: { + getAll: vi.fn().mockResolvedValue([]), + }, }; // Mock theme diff --git a/src/__tests__/renderer/components/Wizard/WizardThemeStyles.test.tsx b/src/__tests__/renderer/components/Wizard/WizardThemeStyles.test.tsx index 74043a24..e9cbfb41 100644 --- a/src/__tests__/renderer/components/Wizard/WizardThemeStyles.test.tsx +++ b/src/__tests__/renderer/components/Wizard/WizardThemeStyles.test.tsx @@ -159,6 +159,12 @@ const mockMaestro = { fs: { readFile: vi.fn(), }, + sshRemote: { + getConfigs: vi.fn().mockResolvedValue({ success: true, configs: [] }), + }, + sessions: { + getAll: vi.fn().mockResolvedValue([]), + }, }; // Helper to render with required providers diff --git a/src/__tests__/shared/templateVariables.test.ts b/src/__tests__/shared/templateVariables.test.ts index 7d27a9d6..6d1d8c3e 100644 --- a/src/__tests__/shared/templateVariables.test.ts +++ b/src/__tests__/shared/templateVariables.test.ts @@ -58,6 +58,11 @@ describe('TEMPLATE_VARIABLES constant', () => { }); }); + it('should include conductor variables', () => { + const variables = TEMPLATE_VARIABLES.map((v) => v.variable); + expect(variables).toContain('{{CONDUCTOR_PROFILE}}'); + }); + it('should include key agent variables', () => { const variables = TEMPLATE_VARIABLES.map((v) => v.variable); expect(variables).toContain('{{AGENT_NAME}}'); @@ -138,6 +143,24 @@ describe('substituteTemplateVariables', () => { vi.useRealTimers(); }); + describe('Conductor Variables', () => { + it('should replace {{CONDUCTOR_PROFILE}} with conductorProfile', () => { + const context = createTestContext({ + conductorProfile: 'Senior developer specializing in TypeScript and React', + }); + const result = substituteTemplateVariables('Profile: {{CONDUCTOR_PROFILE}}', context); + expect(result).toBe('Profile: Senior developer specializing in TypeScript and React'); + }); + + it('should replace {{CONDUCTOR_PROFILE}} with empty string when conductorProfile is undefined', () => { + const context = createTestContext({ + conductorProfile: undefined, + }); + const result = substituteTemplateVariables('Profile: {{CONDUCTOR_PROFILE}}', context); + expect(result).toBe('Profile: '); + }); + }); + describe('Agent Variables', () => { it('should replace {{AGENT_NAME}} with session.name', () => { const context = createTestContext({ diff --git a/src/prompts/group-chat-moderator-system.md b/src/prompts/group-chat-moderator-system.md index 8f692a36..16b0d403 100644 --- a/src/prompts/group-chat-moderator-system.md +++ b/src/prompts/group-chat-moderator-system.md @@ -1,4 +1,10 @@ -You are a Group Chat Moderator in Maestro, a multi-agent orchestration tool. Your role is to: +You are a Group Chat Moderator in Maestro, a multi-agent orchestration tool. + +## Conductor Profile + +{{CONDUCTOR_PROFILE}} + +Your role is to: 1. **Assist the user directly** - You are a capable AI assistant. For simple questions or tasks, respond directly without delegating to other agents. diff --git a/src/prompts/maestro-system-prompt.md b/src/prompts/maestro-system-prompt.md index 93555f5c..13447a2c 100644 --- a/src/prompts/maestro-system-prompt.md +++ b/src/prompts/maestro-system-prompt.md @@ -2,6 +2,10 @@ You are **{{AGENT_NAME}}**, powered by **{{TOOL_TYPE}}**, operating as a Maestro-managed AI coding agent. +## Conductor Profile + +{{CONDUCTOR_PROFILE}} + ## About Maestro Maestro is an Electron desktop application for managing multiple AI coding assistants simultaneously with a keyboard-first interface. For more information: @@ -27,8 +31,11 @@ Your session history is stored at `{{AGENT_HISTORY_PATH}}`. When you need contex - `timestamp`: When the task was completed (Unix ms) - `type`: `AUTO` (automated) or `USER` (interactive) - `success`: Whether the task succeeded +- `fullResponse`: Complete AI response text (for detailed context) +- `elapsedTimeMs`: How long the task took +- `contextUsage`: Context window usage percentage at completion -To recall recent work, read the file and scan the most recent entries by timestamp. +To recall recent work, read the file and scan the most recent entries by timestamp. Use `summary` for quick scanning and `fullResponse` when you need detailed context about what was done. ## Auto-run Documents diff --git a/src/prompts/wizard-inline-system.md b/src/prompts/wizard-inline-system.md index cb9314c5..af9f69f8 100644 --- a/src/prompts/wizard-inline-system.md +++ b/src/prompts/wizard-inline-system.md @@ -1,9 +1,25 @@ You are a planning assistant helping in an existing Maestro session for "{{PROJECT_NAME}}". +## Conductor Profile + +{{CONDUCTOR_PROFILE}} + ## Your Role You are helping plan work in an active session. The user has an established project context and wants to create or extend a Playbook. +## Task Recall + +Your session history is stored at `{{AGENT_HISTORY_PATH}}`. When you need context about previously completed work in this project, read this JSON file and parse the `entries` array. Each entry contains: +- `summary`: Brief description of the task +- `timestamp`: When the task was completed (Unix ms) +- `type`: `AUTO` (automated) or `USER` (interactive) +- `success`: Whether the task succeeded +- `fullResponse`: Complete AI response text (for detailed context) +- `elapsedTimeMs`: How long the task took + +To recall recent work, read the file and scan the most recent entries by timestamp. Use `summary` for quick scanning and `fullResponse` when you need detailed context about what has already been accomplished. + ## File Access Restrictions **WRITE ACCESS (Limited):** diff --git a/src/prompts/wizard-system.md b/src/prompts/wizard-system.md index af3e2e67..e8e8c5f5 100644 --- a/src/prompts/wizard-system.md +++ b/src/prompts/wizard-system.md @@ -1,9 +1,25 @@ You are a friendly project discovery assistant helping to set up "{{PROJECT_NAME}}". +## Conductor Profile + +{{CONDUCTOR_PROFILE}} + ## Your Role You are 🎼 Maestro's onboarding assistant, helping the user define their project so we can create an actionable plan. +## Task Recall + +Your session history is stored at `{{AGENT_HISTORY_PATH}}`. When you need context about previously completed work in this project, read this JSON file and parse the `entries` array. Each entry contains: +- `summary`: Brief description of the task +- `timestamp`: When the task was completed (Unix ms) +- `type`: `AUTO` (automated) or `USER` (interactive) +- `success`: Whether the task succeeded +- `fullResponse`: Complete AI response text (for detailed context) +- `elapsedTimeMs`: How long the task took + +To recall recent work, read the file and scan the most recent entries by timestamp. Use `summary` for quick scanning and `fullResponse` when you need detailed context about what has already been accomplished. + ## File Access Restrictions **WRITE ACCESS (Limited):** diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 1ae69f95..a54fa61f 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -453,6 +453,7 @@ function MaestroConsoleInner() { const settings = useSettings(); const { settingsLoaded, + conductorProfile, llmProvider, setLlmProvider, modelSlug, @@ -4551,6 +4552,7 @@ You are taking over this conversation. Based on the context above, provide a bri const substitutedSystemPrompt = substituteTemplateVariables(maestroSystemPrompt, { session: targetSession, gitBranch, + conductorProfile, }); effectivePrompt = `${substitutedSystemPrompt}\n\n---\n\n# User Request\n\n${effectivePrompt}`; } @@ -7497,7 +7499,8 @@ You are taking over this conversation. Based on the context above, provide a bri activeTab.id, // Tab ID for per-tab isolation activeSession.id, // Session ID for playbook creation activeSession.autoRunFolderPath, // User-configured Auto Run folder path (if set) - activeSession.sessionSshRemoteConfig // SSH remote config for remote execution + activeSession.sessionSshRemoteConfig, // SSH remote config for remote execution + conductorProfile // Conductor profile (user's About Me from settings) ); // Rename the tab to "Wizard" immediately when wizard starts @@ -7526,7 +7529,7 @@ You are taking over this conversation. Based on the context above, provide a bri }; addLogToActiveTab(activeSession.id, wizardLog); }, - [activeSession, startInlineWizard, addLogToActiveTab] + [activeSession, startInlineWizard, addLogToActiveTab, conductorProfile] ); // Launch wizard in a new tab - triggered from Auto Run panel button @@ -7580,7 +7583,8 @@ You are taking over this conversation. Based on the context above, provide a bri newTab.id, activeSession.id, activeSession.autoRunFolderPath, // User-configured Auto Run folder path (if set) - activeSession.sessionSshRemoteConfig // SSH remote config for remote execution + activeSession.sessionSshRemoteConfig, // SSH remote config for remote execution + conductorProfile // Conductor profile (user's About Me from settings) ); // Show a system log entry @@ -7597,6 +7601,7 @@ You are taking over this conversation. Based on the context above, provide a bri defaultShowThinking, startInlineWizard, addLogToTab, + conductorProfile, ]); // Determine if wizard is active for the current tab @@ -7634,6 +7639,7 @@ You are taking over this conversation. Based on the context above, provide a bri isWizardActive: isWizardActiveForCurrentTab, onSkillsCommand: handleSkillsCommand, automaticTabNamingEnabled, + conductorProfile, }); // Auto-send context when a tab with autoSendOnActivate becomes active @@ -10113,6 +10119,7 @@ You are taking over this conversation. Based on the context above, provide a bri promptToSend = substituteTemplateVariables(matchingCommand.prompt, { session, gitBranch, + conductorProfile, }); commandMetadata = { command: matchingCommand.command, @@ -10411,6 +10418,7 @@ You are taking over this conversation. Based on the context above, provide a bri const substitutedSystemPrompt = substituteTemplateVariables(maestroSystemPrompt, { session, gitBranch, + conductorProfile, }); // Prepend system prompt to user's message @@ -10482,6 +10490,7 @@ You are taking over this conversation. Based on the context above, provide a bri const substitutedPrompt = substituteTemplateVariables(promptWithArgs, { session, gitBranch, + conductorProfile, }); // For NEW sessions (no agentSessionId), prepend Maestro system prompt @@ -10494,6 +10503,7 @@ You are taking over this conversation. Based on the context above, provide a bri const substitutedSystemPrompt = substituteTemplateVariables(maestroSystemPrompt, { session, gitBranch, + conductorProfile, }); // Prepend system prompt to command's prompt (for agent only) diff --git a/src/renderer/components/MainPanel.tsx b/src/renderer/components/MainPanel.tsx index a00d8e9b..d34daf4a 100644 --- a/src/renderer/components/MainPanel.tsx +++ b/src/renderer/components/MainPanel.tsx @@ -977,7 +977,7 @@ export const MainPanel = React.memo( {/* Hide branch name text at narrow widths, show on hover via title */} {!useIconOnlyGitBranch && ( - + {gitInfo?.branch || 'GIT'} )} diff --git a/src/renderer/components/SettingsModal.tsx b/src/renderer/components/SettingsModal.tsx index 63032f50..89d79f8d 100644 --- a/src/renderer/components/SettingsModal.tsx +++ b/src/renderer/components/SettingsModal.tsx @@ -31,6 +31,7 @@ import { Monitor, PartyPopper, Tag, + User, } from 'lucide-react'; import { useSettings } from '../hooks'; import type { @@ -283,6 +284,9 @@ export const SettingsModal = memo(function SettingsModal(props: SettingsModalPro // Context management settings from useSettings hook const { + // Conductor Profile (About Me) + conductorProfile, + setConductorProfile, contextManagementSettings, updateContextManagementSettings, // Document Graph settings @@ -951,6 +955,44 @@ export const SettingsModal = memo(function SettingsModal(props: SettingsModalPro
{activeTab === 'general' && (
+ {/* About Me (Conductor Profile) */} +
+ +

+ Tell us a little about yourself so that agents created under Maestro know how to + work and communicate with you. As the conductor, you orchestrate the symphony of AI + agents. (Optional, max 1000 characters) +

+
+