From 62019d5916864c94ba1e892117b19c90aa07dc3f Mon Sep 17 00:00:00 2001 From: Soham Dasgupta Date: Tue, 13 Jan 2026 14:14:56 +0530 Subject: [PATCH 1/4] feat: add OpenCode CLI support in Docker - Install OpenCode CLI in Dockerfile alongside Claude and Cursor - Add automaker-opencode-config volume for persisting auth - Add OpenCode directory setup in docker-entrypoint.sh - Update docker-isolation.md with OpenCode documentation - Add OpenCode bind mount example to docker-compose.override.yml.example --- Dockerfile | 6 ++++++ docker-compose.override.yml.example | 4 ++++ docker-compose.yml | 9 +++++++++ docker-entrypoint.sh | 15 +++++++++++++++ docs/docker-isolation.md | 12 ++++++++++++ 5 files changed, 46 insertions(+) diff --git a/Dockerfile b/Dockerfile index c32b1764..b31ffd09 100644 --- a/Dockerfile +++ b/Dockerfile @@ -95,6 +95,12 @@ RUN curl https://cursor.com/install -fsS | bash && \ ls -la /home/automaker/.local/bin/ && \ echo "=== PATH is: $PATH ===" && \ (which cursor-agent && cursor-agent --version) || echo "cursor-agent installed (may need auth setup)" + +# Install OpenCode CLI (for multi-provider AI model access) +RUN curl -fsSL https://opencode.ai/install | bash && \ + echo "=== Checking OpenCode CLI installation ===" && \ + ls -la /home/automaker/.local/bin/ && \ + (which opencode && opencode --version) || echo "opencode installed (may need auth setup)" USER root # Add PATH to profile so it's available in all interactive shells (for login shells) diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example index b4ef6c47..f7f63cc8 100644 --- a/docker-compose.override.yml.example +++ b/docker-compose.override.yml.example @@ -16,6 +16,10 @@ services: # This shares your 'cursor-agent login' OAuth session with the container # - ~/.cursor:/home/automaker/.cursor + # OpenCode CLI - mount your ~/.local/share/opencode directory + # This shares your 'opencode auth login' session with the container + # - ~/.local/share/opencode:/home/automaker/.local/share/opencode + environment: # Set root directory for all projects and file operations # Users can only create/open projects within this directory diff --git a/docker-compose.yml b/docker-compose.yml index 227450ad..69d2ddd2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -78,6 +78,10 @@ services: # This allows 'cursor-agent login' authentication to persist between restarts - automaker-cursor-config:/home/automaker/.cursor + # Persist OpenCode CLI configuration and authentication across container restarts + # This allows 'opencode auth login' authentication to persist between restarts + - automaker-opencode-config:/home/automaker/.local/share/opencode + # NO host directory mounts - container cannot access your laptop files # If you need to work on a project, create it INSIDE the container # or use a separate docker-compose override file @@ -101,3 +105,8 @@ volumes: name: automaker-cursor-config # Named volume for Cursor CLI configuration and authentication # Persists cursor-agent login authentication across container restarts + + automaker-opencode-config: + name: automaker-opencode-config + # Named volume for OpenCode CLI configuration and authentication + # Persists opencode auth login authentication across container restarts diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 017213dc..9321ce37 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -25,6 +25,21 @@ fi chown -R automaker:automaker /home/automaker/.cursor chmod -R 700 /home/automaker/.cursor +# Ensure OpenCode CLI config directory exists with correct permissions +# OpenCode stores config and auth in ~/.local/share/opencode/ +if [ ! -d "/home/automaker/.local/share/opencode" ]; then + mkdir -p /home/automaker/.local/share/opencode +fi +chown -R automaker:automaker /home/automaker/.local/share/opencode +chmod -R 700 /home/automaker/.local/share/opencode + +# OpenCode also uses ~/.config/opencode for configuration +if [ ! -d "/home/automaker/.config/opencode" ]; then + mkdir -p /home/automaker/.config/opencode +fi +chown -R automaker:automaker /home/automaker/.config/opencode +chmod -R 700 /home/automaker/.config/opencode + # If CURSOR_AUTH_TOKEN is set, write it to the cursor auth file # On Linux, cursor-agent uses ~/.config/cursor/auth.json for file-based credential storage # The env var CURSOR_AUTH_TOKEN is also checked directly by cursor-agent diff --git a/docs/docker-isolation.md b/docs/docker-isolation.md index eb8fe7e1..0f486f5f 100644 --- a/docs/docker-isolation.md +++ b/docs/docker-isolation.md @@ -80,6 +80,16 @@ echo "CURSOR_AUTH_TOKEN=$(./scripts/get-cursor-token.sh)" >> .env - **macOS**: Tokens are stored in Keychain (service: `cursor-access-token`) - **Linux**: Tokens are stored in `~/.config/cursor/auth.json` (not `~/.cursor`) +### OpenCode CLI + +OpenCode stores its configuration and auth at `~/.local/share/opencode/`. To share your host authentication with the container: + +```yaml +# In docker-compose.override.yml +volumes: + - ~/.local/share/opencode:/home/automaker/.local/share/opencode +``` + ### Apply to container ```bash @@ -107,6 +117,7 @@ echo "CURSOR_AUTH_TOKEN=$(jq -r '.accessToken' ~/.config/cursor/auth.json)" >> . volumes: - ~/.claude:/home/automaker/.claude - ~/.config/cursor:/home/automaker/.config/cursor + - ~/.local/share/opencode:/home/automaker/.local/share/opencode ``` ## Troubleshooting @@ -117,3 +128,4 @@ volumes: | Can't access web UI | Verify container is running with `docker ps \| grep automaker` | | Need a fresh start | Run `docker-compose down && docker volume rm automaker-data && docker-compose up -d --build` | | Cursor auth fails | Re-extract token with `./scripts/get-cursor-token.sh` - tokens expire periodically. Make sure you've run `cursor-agent login` on your host first. | +| OpenCode not detected | Mount `~/.local/share/opencode` to `/home/automaker/.local/share/opencode`. Make sure you've run `opencode auth login` on your host first. | From 67f18021c3d3f3e5b61b7afcda44ee343385d4c9 Mon Sep 17 00:00:00 2001 From: Soham Dasgupta Date: Tue, 13 Jan 2026 19:50:54 +0530 Subject: [PATCH 2/4] feat: add OpenCode CLI config path to Docker example --- docker-compose.override.yml.example | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example index f7f63cc8..dfd74bd4 100644 --- a/docker-compose.override.yml.example +++ b/docker-compose.override.yml.example @@ -19,6 +19,7 @@ services: # OpenCode CLI - mount your ~/.local/share/opencode directory # This shares your 'opencode auth login' session with the container # - ~/.local/share/opencode:/home/automaker/.local/share/opencode + # - ~/.config/opencode:/home/automaker/.config/opencode environment: # Set root directory for all projects and file operations From 33ae860059995bbd823147089ce9c8d34967c161 Mon Sep 17 00:00:00 2001 From: Soham Dasgupta Date: Tue, 13 Jan 2026 20:01:22 +0530 Subject: [PATCH 3/4] feat: update Docker volumes for OpenCode CLI data and user configuration --- docker-compose.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 69d2ddd2..97526b5f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,7 +80,10 @@ services: # Persist OpenCode CLI configuration and authentication across container restarts # This allows 'opencode auth login' authentication to persist between restarts - - automaker-opencode-config:/home/automaker/.local/share/opencode + - automaker-opencode-data:/home/automaker/.local/share/opencode + + # Persist OpenCode user configuration across container restarts + - automaker-opencode-config:/home/automaker/.config/opencode # NO host directory mounts - container cannot access your laptop files # If you need to work on a project, create it INSIDE the container @@ -106,7 +109,12 @@ volumes: # Named volume for Cursor CLI configuration and authentication # Persists cursor-agent login authentication across container restarts + automaker-opencode-data: + name: automaker-opencode-data + # Named volume for OpenCode CLI data and authentication (~/.local/share/opencode) + # Persists opencode auth login authentication across container restarts + automaker-opencode-config: name: automaker-opencode-config - # Named volume for OpenCode CLI configuration and authentication - # Persists opencode auth login authentication across container restarts + # Named volume for OpenCode user configuration (~/.config/opencode) + # Persists user configuration across container restarts From bb710ada1a432e37cfbf9e9bd535fdecdc67a9fc Mon Sep 17 00:00:00 2001 From: webdevcody Date: Tue, 13 Jan 2026 09:30:15 -0500 Subject: [PATCH 4/4] feat: enhance settings view and feature defaults management - Introduced default feature model settings in the settings view, allowing users to specify the default AI model for new feature cards. - Updated navigation to include a direct link to model defaults in the settings menu. - Enhanced the Add Feature dialog to utilize the default feature model from the app store. - Implemented synchronization of the default feature model in settings migration and sync hooks. - Improved UI components to reflect changes in default settings, ensuring a cohesive user experience. --- .../board-view/dialogs/add-feature-dialog.tsx | 42 +++++++++++++++---- .../dialogs/edit-feature-dialog.tsx | 32 ++++++++++++-- .../ui/src/components/views/settings-view.tsx | 11 ++++- .../views/settings-view/config/navigation.ts | 2 +- .../feature-defaults-section.tsx | 34 ++++++++++++++- apps/ui/src/hooks/use-settings-migration.ts | 1 + apps/ui/src/hooks/use-settings-sync.ts | 2 + apps/ui/src/routes/settings.tsx | 10 +++++ apps/ui/src/store/app-store.ts | 4 ++ libs/types/src/settings.ts | 3 ++ 10 files changed, 124 insertions(+), 17 deletions(-) diff --git a/apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx b/apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx index 736f3c40..dfee5c30 100644 --- a/apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx +++ b/apps/ui/src/components/views/board-view/dialogs/add-feature-dialog.tsx @@ -21,7 +21,8 @@ import { FeatureTextFilePath as DescriptionTextFilePath, ImagePreviewMap, } from '@/components/ui/description-image-dropzone'; -import { Play, Cpu, FolderKanban } from 'lucide-react'; +import { Play, Cpu, FolderKanban, Settings2 } from 'lucide-react'; +import { useNavigate } from '@tanstack/react-router'; import { toast } from 'sonner'; import { cn } from '@/lib/utils'; import { modelSupportsThinking } from '@/lib/utils'; @@ -33,7 +34,7 @@ import { PlanningMode, Feature, } from '@/store/app-store'; -import type { ReasoningEffort, PhaseModelEntry } from '@automaker/types'; +import type { ReasoningEffort, PhaseModelEntry, AgentModel } from '@automaker/types'; import { supportsReasoningEffort, isClaudeModel } from '@automaker/types'; import { TestingTabContent, @@ -152,6 +153,7 @@ export function AddFeatureDialog({ forceCurrentBranchMode, }: AddFeatureDialogProps) { const isSpawnMode = !!parentFeature; + const navigate = useNavigate(); const [workMode, setWorkMode] = useState('current'); // Form state @@ -187,7 +189,8 @@ export function AddFeatureDialog({ const [selectedAncestorIds, setSelectedAncestorIds] = useState>(new Set()); // Get defaults from store - const { defaultPlanningMode, defaultRequirePlanApproval, useWorktrees } = useAppStore(); + const { defaultPlanningMode, defaultRequirePlanApproval, useWorktrees, defaultFeatureModel } = + useAppStore(); // Track previous open state to detect when dialog opens const wasOpenRef = useRef(false); @@ -207,7 +210,7 @@ export function AddFeatureDialog({ ); setPlanningMode(defaultPlanningMode); setRequirePlanApproval(defaultRequirePlanApproval); - setModelEntry({ model: 'opus' }); + setModelEntry(defaultFeatureModel); // Initialize description history (empty for new feature) setDescriptionHistory([]); @@ -228,6 +231,7 @@ export function AddFeatureDialog({ defaultBranch, defaultPlanningMode, defaultRequirePlanApproval, + defaultFeatureModel, useWorktrees, selectedNonMainWorktreeBranch, forceCurrentBranchMode, @@ -318,7 +322,7 @@ export function AddFeatureDialog({ // When a non-main worktree is selected, use its branch name for custom mode setBranchName(selectedNonMainWorktreeBranch || ''); setPriority(2); - setModelEntry({ model: 'opus' }); + setModelEntry(defaultFeatureModel); setWorkMode( getDefaultWorkMode(useWorktrees, selectedNonMainWorktreeBranch, forceCurrentBranchMode) ); @@ -473,9 +477,31 @@ export function AddFeatureDialog({ {/* AI & Execution Section */}
-
- - AI & Execution +
+
+ + AI & Execution +
+ + + + + + +

Change default model and planning settings for new features

+
+
+
diff --git a/apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx b/apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx index 9912201d..ae7d655b 100644 --- a/apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx +++ b/apps/ui/src/components/views/board-view/dialogs/edit-feature-dialog.tsx @@ -21,7 +21,8 @@ import { FeatureTextFilePath as DescriptionTextFilePath, ImagePreviewMap, } from '@/components/ui/description-image-dropzone'; -import { GitBranch, Cpu, FolderKanban } from 'lucide-react'; +import { GitBranch, Cpu, FolderKanban, Settings2 } from 'lucide-react'; +import { useNavigate } from '@tanstack/react-router'; import { toast } from 'sonner'; import { cn, modelSupportsThinking } from '@/lib/utils'; import { Feature, ModelAlias, ThinkingLevel, useAppStore, PlanningMode } from '@/store/app-store'; @@ -86,6 +87,7 @@ export function EditFeatureDialog({ isMaximized, allFeatures, }: EditFeatureDialogProps) { + const navigate = useNavigate(); const [editingFeature, setEditingFeature] = useState(feature); // Derive initial workMode from feature's branchName const [workMode, setWorkMode] = useState(() => { @@ -363,9 +365,31 @@ export function EditFeatureDialog({ {/* AI & Execution Section */}
-
- - AI & Execution +
+
+ + AI & Execution +
+ + + + + + +

Change default model and planning settings for new features

+
+
+
diff --git a/apps/ui/src/components/views/settings-view.tsx b/apps/ui/src/components/views/settings-view.tsx index aa6a8a84..2655e8a5 100644 --- a/apps/ui/src/components/views/settings-view.tsx +++ b/apps/ui/src/components/views/settings-view.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; +import { useSearch } from '@tanstack/react-router'; import { useAppStore } from '@/store/app-store'; -import { useSetupStore } from '@/store/setup-store'; import { useSettingsView, type SettingsViewId } from './settings-view/hooks'; import { NAV_ITEMS } from './settings-view/config/navigation'; @@ -51,6 +51,8 @@ export function SettingsView() { setDefaultPlanningMode, defaultRequirePlanApproval, setDefaultRequirePlanApproval, + defaultFeatureModel, + setDefaultFeatureModel, autoLoadClaudeMd, setAutoLoadClaudeMd, promptCustomization, @@ -86,8 +88,11 @@ export function SettingsView() { } }; + // Get initial view from URL search params + const { view: initialView } = useSearch({ from: '/settings' }); + // Use settings view navigation hook - const { activeView, navigateTo } = useSettingsView(); + const { activeView, navigateTo } = useSettingsView({ initialView }); // Handle navigation - if navigating to 'providers', default to 'claude-provider' const handleNavigate = (viewId: SettingsViewId) => { @@ -152,11 +157,13 @@ export function SettingsView() { skipVerificationInAutoMode={skipVerificationInAutoMode} defaultPlanningMode={defaultPlanningMode} defaultRequirePlanApproval={defaultRequirePlanApproval} + defaultFeatureModel={defaultFeatureModel} onDefaultSkipTestsChange={setDefaultSkipTests} onEnableDependencyBlockingChange={setEnableDependencyBlocking} onSkipVerificationInAutoModeChange={setSkipVerificationInAutoMode} onDefaultPlanningModeChange={setDefaultPlanningMode} onDefaultRequirePlanApprovalChange={setDefaultRequirePlanApproval} + onDefaultFeatureModelChange={setDefaultFeatureModel} /> ); case 'worktrees': diff --git a/apps/ui/src/components/views/settings-view/config/navigation.ts b/apps/ui/src/components/views/settings-view/config/navigation.ts index f63d0494..6a810973 100644 --- a/apps/ui/src/components/views/settings-view/config/navigation.ts +++ b/apps/ui/src/components/views/settings-view/config/navigation.ts @@ -37,8 +37,8 @@ export const GLOBAL_NAV_GROUPS: NavigationGroup[] = [ { label: 'Model & Prompts', items: [ - { id: 'model-defaults', label: 'Model Defaults', icon: Workflow }, { id: 'defaults', label: 'Feature Defaults', icon: FlaskConical }, + { id: 'model-defaults', label: 'Model Defaults', icon: Workflow }, { id: 'worktrees', label: 'Worktrees', icon: GitBranch }, { id: 'prompts', label: 'Prompt Customization', icon: MessageSquareText }, { id: 'api-keys', label: 'API Keys', icon: Key }, diff --git a/apps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsx b/apps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsx index c3b4e9ae..956d28fa 100644 --- a/apps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsx +++ b/apps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsx @@ -10,6 +10,7 @@ import { ScrollText, ShieldCheck, FastForward, + Cpu, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { @@ -19,6 +20,8 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; +import type { PhaseModelEntry } from '@automaker/types'; +import { PhaseModelSelector } from '../model-defaults/phase-model-selector'; type PlanningMode = 'skip' | 'lite' | 'spec' | 'full'; @@ -28,11 +31,13 @@ interface FeatureDefaultsSectionProps { skipVerificationInAutoMode: boolean; defaultPlanningMode: PlanningMode; defaultRequirePlanApproval: boolean; + defaultFeatureModel: PhaseModelEntry; onDefaultSkipTestsChange: (value: boolean) => void; onEnableDependencyBlockingChange: (value: boolean) => void; onSkipVerificationInAutoModeChange: (value: boolean) => void; onDefaultPlanningModeChange: (value: PlanningMode) => void; onDefaultRequirePlanApprovalChange: (value: boolean) => void; + onDefaultFeatureModelChange: (value: PhaseModelEntry) => void; } export function FeatureDefaultsSection({ @@ -41,11 +46,13 @@ export function FeatureDefaultsSection({ skipVerificationInAutoMode, defaultPlanningMode, defaultRequirePlanApproval, + defaultFeatureModel, onDefaultSkipTestsChange, onEnableDependencyBlockingChange, onSkipVerificationInAutoModeChange, onDefaultPlanningModeChange, onDefaultRequirePlanApprovalChange, + onDefaultFeatureModelChange, }: FeatureDefaultsSectionProps) { return (
+ {/* Default Feature Model Setting */} +
+
+ +
+
+
+ + +
+

+ The default AI model and thinking level used when creating new feature cards. +

+
+
+ + {/* Separator */} +
+ {/* Planning Mode Default */}
-
)} {/* Separator */} - {defaultPlanningMode === 'skip' &&
} +
{/* Automated Testing Setting */}
diff --git a/apps/ui/src/hooks/use-settings-migration.ts b/apps/ui/src/hooks/use-settings-migration.ts index bb86c10c..e4375cbf 100644 --- a/apps/ui/src/hooks/use-settings-migration.ts +++ b/apps/ui/src/hooks/use-settings-migration.ts @@ -562,6 +562,7 @@ export function hydrateStoreFromSettings(settings: GlobalSettings): void { useWorktrees: settings.useWorktrees ?? true, defaultPlanningMode: settings.defaultPlanningMode ?? 'skip', defaultRequirePlanApproval: settings.defaultRequirePlanApproval ?? false, + defaultFeatureModel: settings.defaultFeatureModel ?? { model: 'opus' }, muteDoneSound: settings.muteDoneSound ?? false, enhancementModel: settings.enhancementModel ?? 'sonnet', validationModel: settings.validationModel ?? 'opus', diff --git a/apps/ui/src/hooks/use-settings-sync.ts b/apps/ui/src/hooks/use-settings-sync.ts index 41ef6693..1fb9dbd0 100644 --- a/apps/ui/src/hooks/use-settings-sync.ts +++ b/apps/ui/src/hooks/use-settings-sync.ts @@ -42,6 +42,7 @@ const SETTINGS_FIELDS_TO_SYNC = [ 'useWorktrees', 'defaultPlanningMode', 'defaultRequirePlanApproval', + 'defaultFeatureModel', 'muteDoneSound', 'enhancementModel', 'validationModel', @@ -466,6 +467,7 @@ export async function refreshSettingsFromServer(): Promise { useWorktrees: serverSettings.useWorktrees, defaultPlanningMode: serverSettings.defaultPlanningMode, defaultRequirePlanApproval: serverSettings.defaultRequirePlanApproval, + defaultFeatureModel: serverSettings.defaultFeatureModel ?? { model: 'opus' }, muteDoneSound: serverSettings.muteDoneSound, enhancementModel: serverSettings.enhancementModel, validationModel: serverSettings.validationModel, diff --git a/apps/ui/src/routes/settings.tsx b/apps/ui/src/routes/settings.tsx index 74170d94..c509e93a 100644 --- a/apps/ui/src/routes/settings.tsx +++ b/apps/ui/src/routes/settings.tsx @@ -1,6 +1,16 @@ import { createFileRoute } from '@tanstack/react-router'; import { SettingsView } from '@/components/views/settings-view'; +import type { SettingsViewId } from '@/components/views/settings-view/hooks'; + +interface SettingsSearchParams { + view?: SettingsViewId; +} export const Route = createFileRoute('/settings')({ component: SettingsView, + validateSearch: (search: Record): SettingsSearchParams => { + return { + view: search.view as SettingsViewId | undefined, + }; + }, }); diff --git a/apps/ui/src/store/app-store.ts b/apps/ui/src/store/app-store.ts index 36aec5ed..280ba7c1 100644 --- a/apps/ui/src/store/app-store.ts +++ b/apps/ui/src/store/app-store.ts @@ -657,6 +657,7 @@ export interface AppState { defaultPlanningMode: PlanningMode; defaultRequirePlanApproval: boolean; + defaultFeatureModel: PhaseModelEntry; // Plan Approval State // When a plan requires user approval, this holds the pending approval details @@ -1104,6 +1105,7 @@ export interface AppActions { setDefaultPlanningMode: (mode: PlanningMode) => void; setDefaultRequirePlanApproval: (require: boolean) => void; + setDefaultFeatureModel: (entry: PhaseModelEntry) => void; // Plan Approval actions setPendingPlanApproval: ( @@ -1277,6 +1279,7 @@ const initialState: AppState = { specCreatingForProject: null, defaultPlanningMode: 'skip' as PlanningMode, defaultRequirePlanApproval: false, + defaultFeatureModel: { model: 'opus' } as PhaseModelEntry, pendingPlanApproval: null, claudeRefreshInterval: 60, claudeUsage: null, @@ -3093,6 +3096,7 @@ export const useAppStore = create()((set, get) => ({ setDefaultPlanningMode: (mode) => set({ defaultPlanningMode: mode }), setDefaultRequirePlanApproval: (require) => set({ defaultRequirePlanApproval: require }), + setDefaultFeatureModel: (entry) => set({ defaultFeatureModel: entry }), // Plan Approval actions setPendingPlanApproval: (approval) => set({ pendingPlanApproval: approval }), diff --git a/libs/types/src/settings.ts b/libs/types/src/settings.ts index 38402c24..a4efa469 100644 --- a/libs/types/src/settings.ts +++ b/libs/types/src/settings.ts @@ -375,6 +375,8 @@ export interface GlobalSettings { defaultPlanningMode: PlanningMode; /** Default: require manual approval before generating */ defaultRequirePlanApproval: boolean; + /** Default model and thinking level for new feature cards */ + defaultFeatureModel: PhaseModelEntry; // Audio Preferences /** Mute completion notification sound */ @@ -698,6 +700,7 @@ export const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = { useWorktrees: true, defaultPlanningMode: 'skip', defaultRequirePlanApproval: false, + defaultFeatureModel: { model: 'opus' }, muteDoneSound: false, phaseModels: DEFAULT_PHASE_MODELS, enhancementModel: 'sonnet',