diff --git a/lara.lock b/lara.lock
index 40080338..9387bd6e 100644
--- a/lara.lock
+++ b/lara.lock
@@ -183,12 +183,12 @@ files:
settings.allNotesVisibility.unsupported: 257fe04419c9f6543a43e58b1edf9eb5
settings.allNotesVisibility.unsupportedDescription: a3b8aa66900c742f001cd4533b3df44a
settings.aiAgents.title: 27f08387b26e1ceeb1b60bd9c97e7a47
- settings.aiAgents.description: 042a8037f1a4f90c76ce31a49fdff59c
+ settings.aiAgents.description: 768c138c3432fb159ac58c5a4471e786
settings.aiFeatures.enable: af47a6b2bd32a7b7309bac7bef34f026
settings.aiFeatures.enableDescription: 7d3916f7f9e1bf8b8797f50f4533b9da
settings.aiAgents.default: 6af573559fd05d8c35bc57b41cc78e24
settings.aiAgents.defaultTarget: 5acfc74fd97a6dd2d67d15c66de5eed5
- settings.aiAgents.agentGroup: 965530cbbec45b1754ed3ece120399f7
+ settings.aiAgents.agentGroup: 11eaa7f817e3f24d54f3cf3025be49b1
settings.aiAgents.localGroup: d34f4b997ce78da5aa57d657a5d6fcb5
settings.aiAgents.apiGroup: 589a257cbd265eaa7de93de8b4084dff
settings.aiAgents.installed: 73329564760013a7824ff9d5d1af91ff
@@ -199,11 +199,11 @@ files:
settings.aiAgents.apiLocalKey: 119de2f31867b273a134f05bc56b9e57
settings.aiAgents.apiEnv: e011db3dff54ed3deae37a9615e31ebf
settings.aiAgents.apiNoKey: 5bbccbfcd09b28902bbf5319dd6e6053
- settings.aiAgents.installedTitle: 5cb9b5ae5ebc66652814dff4584705cc
- settings.aiAgents.installedDescription: fb9ba9667725fb40fa1e5d58a2c02692
+ settings.aiAgents.installedTitle: 0de6536215f76c44351ba4d809804c7a
+ settings.aiAgents.installedDescription: 27c8ed48439ac4a613409f5303fbca84
settings.aiAgents.noVersion: 89831adb7114946e916b9c31d57a1e33
settings.aiProviders.title: 63eb84d8510f9f086d282ec7d47adaa1
- settings.aiProviders.description: 6c86c013eb6fb198b51e29ec47d66464
+ settings.aiProviders.description: d29dfa440713d15de311d29a64a27767
settings.aiProviders.localTitle: c7c20443d8aaf04271df9d713f5c02ce
settings.aiProviders.localDescription: 7abed40ef2e46741c64ff47e423cca39
settings.aiProviders.apiTitle: 66537b9e5200ebbbfbd091144d8afbcc
diff --git a/src/components/AiAgentsOnboardingPrompt.tsx b/src/components/AiAgentsOnboardingPrompt.tsx
index 158a43cc..590e16db 100644
--- a/src/components/AiAgentsOnboardingPrompt.tsx
+++ b/src/components/AiAgentsOnboardingPrompt.tsx
@@ -21,7 +21,7 @@ function getPromptCopy(statuses: AiAgentsStatus) {
if (isAiAgentsStatusChecking(statuses)) {
return {
accentClassName: 'bg-muted text-muted-foreground',
- description: 'Checking coding agents. You can also use a local model or API provider.',
+ description: 'Checking local agents. You can also use a local model or API provider.',
icon: ,
title: 'Checking AI agents',
}
@@ -38,7 +38,7 @@ function getPromptCopy(statuses: AiAgentsStatus) {
return {
accentClassName: 'bg-[var(--feedback-success-bg)] text-[var(--feedback-success-text)]',
- description: 'You can use the detected coding agents, or add local/API models in Settings.',
+ description: 'You can use the detected local agents, or add local/API models in Settings.',
icon: ,
title: 'AI is ready',
}
@@ -58,7 +58,7 @@ function AiModeChoices() {
},
{
icon: ,
- title: 'Coding agent',
+ title: 'Local agent',
description: 'Use Claude Code, Codex, OpenCode, Gemini CLI, or Pi for tool-capable vault editing on desktop.',
},
]
diff --git a/src/components/SettingsPanel.test.tsx b/src/components/SettingsPanel.test.tsx
index daf90660..f318c244 100644
--- a/src/components/SettingsPanel.test.tsx
+++ b/src/components/SettingsPanel.test.tsx
@@ -130,7 +130,7 @@ describe('SettingsPanel', () => {
expect(screen.getAllByText('Sync & Updates').length).toBeGreaterThan(0)
})
- it('separates coding agents, local models, and API models in AI settings', async () => {
+ it('separates local agents, local models, and API models in AI settings', async () => {
const aiAgentsStatus: AiAgentsStatus = {
claude_code: { status: 'installed', version: '2.1.18' },
codex: { status: 'missing', version: null },
@@ -148,7 +148,7 @@ describe('SettingsPanel', () => {
/>
)
- expect(screen.getByText('Recognized coding agents')).toBeInTheDocument()
+ expect(screen.getByText('Recognized local agents')).toBeInTheDocument()
expect(screen.getByText('Claude Code')).toBeInTheDocument()
expect(screen.getByText('2.1.18')).toBeInTheDocument()
expect(screen.getByRole('tab', { name: 'Local model' })).toBeInTheDocument()
@@ -159,7 +159,7 @@ describe('SettingsPanel', () => {
fireEvent.click(screen.getByRole('button', { name: 'Test model' }))
expect(await screen.findByText('Connection works. The model replied successfully.')).toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Add local model' })).toBeInTheDocument()
- expect(screen.queryByText('Recognized coding agents')).not.toBeInTheDocument()
+ expect(screen.queryByText('Recognized local agents')).not.toBeInTheDocument()
fireEvent.mouseDown(screen.getByRole('tab', { name: 'API model' }), { button: 0, ctrlKey: false })
expect(screen.getByRole('button', { name: 'Add API model' })).toBeInTheDocument()
@@ -182,7 +182,7 @@ describe('SettingsPanel', () => {
)
expect(within(screen.getByTestId('settings-ai-features-enabled')).getByRole('switch')).toHaveAttribute('aria-checked', 'false')
- expect(screen.queryByText('Recognized coding agents')).not.toBeInTheDocument()
+ expect(screen.queryByText('Recognized local agents')).not.toBeInTheDocument()
fireEvent.click(within(screen.getByTestId('settings-ai-features-enabled')).getByRole('switch'))
saveSettingsPanel()
diff --git a/src/components/status-bar/AiAgentsBadge.test.tsx b/src/components/status-bar/AiAgentsBadge.test.tsx
index 0e391b8d..c737335d 100644
--- a/src/components/status-bar/AiAgentsBadge.test.tsx
+++ b/src/components/status-bar/AiAgentsBadge.test.tsx
@@ -105,6 +105,25 @@ describe('AiAgentsBadge', () => {
expect(screen.getByRole('menuitemradio', { name: /OpenAI.*gpt-5\.5/ })).toHaveAttribute('aria-checked', 'true')
})
+ it('does not show install actions for missing local agents', () => {
+ renderBadge({
+ statuses: {
+ claude_code: { status: 'installed', version: '1.0.20' },
+ codex: { status: 'missing', version: null },
+ opencode: { status: 'missing', version: null },
+ pi: { status: 'missing', version: null },
+ gemini: { status: 'missing', version: null },
+ },
+ })
+ openAiAgentsMenu()
+
+ expect(screen.queryByText('Install')).not.toBeInTheDocument()
+ expect(screen.queryByText('Install Codex')).not.toBeInTheDocument()
+ expect(screen.queryByText('Install OpenCode')).not.toBeInTheDocument()
+ expect(screen.queryByText('Install Pi')).not.toBeInTheDocument()
+ expect(screen.queryByText('Install Gemini CLI')).not.toBeInTheDocument()
+ })
+
it('shows the vault guidance summary and restore action', async () => {
const onRestoreGuidance = vi.fn()
diff --git a/src/components/status-bar/AiAgentsBadge.tsx b/src/components/status-bar/AiAgentsBadge.tsx
index 6fdcbde8..cd493e95 100644
--- a/src/components/status-bar/AiAgentsBadge.tsx
+++ b/src/components/status-bar/AiAgentsBadge.tsx
@@ -26,7 +26,6 @@ import {
type VaultAiGuidanceStatus,
} from '../../lib/vaultAiGuidance'
import { translate, type AppLocale } from '../../lib/i18n'
-import { openExternalUrl } from '../../utils/url'
import {
DropdownMenu,
DropdownMenuContent,
@@ -82,10 +81,6 @@ function installedAgentDefinitions(statuses: AiAgentsStatus): AiAgentDefinition[
return AI_AGENT_DEFINITIONS.filter((definition) => isAiAgentInstalled(statuses, definition.id))
}
-function missingAgentDefinitions(statuses: AiAgentsStatus): AiAgentDefinition[] {
- return AI_AGENT_DEFINITIONS.filter((definition) => !isAiAgentInstalled(statuses, definition.id))
-}
-
function triggerLabel(defaultAgent: AiAgentId): string {
return getAiAgentDefinition(defaultAgent).shortLabel
}
@@ -188,7 +183,6 @@ function AgentMenuContent({
locale = 'en',
}: AiAgentsBadgeProps & { selectedTarget: AiTarget; selectedAgentReady: boolean }) {
const installedAgents = installedAgentDefinitions(statuses)
- const missingAgents = missingAgentDefinitions(statuses)
const modelTargets = configuredModelTargets(providers)
const selectedAgentValue = selectedTarget.kind === 'agent' && selectedAgentReady ? selectedTarget.agent : undefined
@@ -226,20 +220,6 @@ function AgentMenuContent({
locale={locale}
onSetDefaultTarget={onSetDefaultTarget}
/>
- {missingAgents.length > 0 && (
- <>
-
- {translate(locale, 'status.ai.install')}
- {missingAgents.map((definition) => (
- void openExternalUrl(definition.installUrl)}
- >
- {translate(locale, 'status.ai.installAgent', { agent: definition.label })}
-
- ))}
- >
- )}