816 lines
27 KiB
Markdown
816 lines
27 KiB
Markdown
# Claude Multimodel Integration Plan
|
|
|
|
## Summary
|
|
|
|
`claude_team` will integrate with a single CLI runtime: `claude-multimodel`.
|
|
|
|
Inside that runtime, the app will track multiple provider states independently:
|
|
|
|
- `anthropic`
|
|
- `codex`
|
|
|
|
The dashboard will show one grouped status banner for the runtime and its providers.
|
|
That grouped banner should replace the current single-runtime dashboard banner, not sit beside a second provider banner.
|
|
|
|
Provider and model selection will happen at process launch time, not in the banner.
|
|
|
|
This avoids duplicating auth logic in `claude_team` and keeps `claude-multimodel` responsible
|
|
for provider login, token storage, and provider capability reporting.
|
|
|
|
## Core Decisions
|
|
|
|
### 1. Runtime model
|
|
|
|
There is one runtime:
|
|
|
|
- `claude-multimodel`
|
|
|
|
There are not multiple runtime binaries for this feature.
|
|
`Anthropic` and `Codex` are providers inside the same runtime.
|
|
|
|
Important consequence:
|
|
|
|
- there is no separate `Codex` binary to install
|
|
- there is no separate `Codex` version to display
|
|
- there is no separate `Codex` updater flow
|
|
|
|
### 2. Provider model
|
|
|
|
Provider status must be tracked independently.
|
|
|
|
Supported initial providers:
|
|
|
|
- `anthropic`
|
|
- `codex`
|
|
|
|
The user may be authenticated with both at the same time.
|
|
The UI must show both statuses independently without trying to choose a global active provider.
|
|
|
|
This provider model must also remain compatible with future providers that expose
|
|
multiple internal backend paths under one public provider id.
|
|
|
|
Example:
|
|
|
|
- public provider: `gemini`
|
|
- internal runtime backend: `api` or `cli`
|
|
|
|
In that scenario, `claude_team` should still treat `gemini` as one provider row.
|
|
Backend choice is diagnostic/runtime metadata inside the provider, not a second provider id.
|
|
|
|
Provider support must be treated per execution mode, not just globally.
|
|
At minimum, the integration needs to distinguish:
|
|
|
|
- interactive team launch / resume
|
|
- scheduled one-shot execution
|
|
|
|
Internal naming rule:
|
|
|
|
- app-level provider id: `codex`
|
|
- runtime/provider label in UI: `Codex`
|
|
- this maps to the OpenAI/Codex path inside `claude-multimodel`
|
|
- during migration, runtime-internal naming may still use `openai`; the bridge layer must normalize that to app-level `codex`
|
|
|
|
Backward-compatibility rule:
|
|
|
|
- existing persisted launches/schedules/teams that do not yet have `providerId` must default safely to `anthropic`
|
|
- missing `providerId` in old metadata must never block resume, launch, or schedule execution
|
|
|
|
### 3. Launch-time selection
|
|
|
|
Banner state is informational only.
|
|
|
|
Provider selection happens when launching a task/team/process:
|
|
|
|
- selected provider
|
|
- selected model
|
|
|
|
Future extension:
|
|
|
|
- per-teammate provider
|
|
- per-teammate model
|
|
|
|
Defaulting rule:
|
|
|
|
- for backward compatibility, flows with no explicit provider should default to `anthropic`
|
|
- provider defaulting must be explicit in code and persistence, not inferred from whichever UI tab/control happened to be last open
|
|
- model defaults must be provider-aware rather than using a single global default such as `opus`
|
|
- if a provider later adds internal backend selection, backend resolution must not silently change the app-level `providerId`
|
|
|
|
## Goals
|
|
|
|
- Show runtime status for `claude-multimodel`
|
|
- Show separate provider status for `Anthropic` and `Codex`
|
|
- Support login/logout/status checks through the runtime CLI
|
|
- Reuse the existing binary resolver and terminal-based login modal flow where possible
|
|
- Avoid reading runtime token/config internals directly from `claude_team`
|
|
- Keep current team launch flow extensible for provider/model selection
|
|
|
|
## Non-Goals
|
|
|
|
- No separate `Codex` installer
|
|
- No fake `Codex` download flow in the UI
|
|
- No separate `Codex` runtime version
|
|
- No full runtime abstraction layer right now
|
|
- No per-teammate model/provider implementation in this phase
|
|
|
|
## Architecture
|
|
|
|
### Runtime ownership
|
|
|
|
`claude-multimodel` owns:
|
|
|
|
- provider auth flows
|
|
- provider token storage
|
|
- provider auth verification
|
|
- provider model availability reporting
|
|
|
|
`claude_team` owns:
|
|
|
|
- UI rendering
|
|
- caching and refreshing status
|
|
- launch-time provider/model selection
|
|
- mapping runtime status into app-friendly DTOs
|
|
- reusing shared CLI probing helpers instead of duplicating binary/version logic
|
|
- ensuring per-process provider env/args are isolated and do not leak across parallel launches
|
|
- validating provider support for the concrete execution mode before spawn
|
|
|
|
### Service boundary in `claude_team`
|
|
|
|
Add a new main-process service:
|
|
|
|
- `src/main/services/runtime/ClaudeMultimodelBridgeService.ts`
|
|
|
|
Responsibilities:
|
|
|
|
- resolve runtime binary path
|
|
- get runtime version
|
|
- get provider auth status
|
|
- get provider model lists
|
|
- aggregate banner DTO
|
|
- trigger provider login/logout commands
|
|
|
|
This service should be separate from `CliInstallerService`.
|
|
Installer/update concerns and provider/auth concerns are different responsibilities.
|
|
|
|
However, the implementation should reuse existing low-level pieces where possible:
|
|
|
|
- `ClaudeBinaryResolver`
|
|
- existing terminal modal login pattern
|
|
- existing CLI version probing helpers, if they are extracted into a shared utility
|
|
|
|
But existing Claude-specific auth/model logic must not be reused as-is for provider rows:
|
|
|
|
- current installer auth probing is Anthropic-oriented
|
|
- current model parsing and display utilities are Claude-oriented
|
|
- provider rows must be driven by runtime provider data, not inferred from Claude-only helpers
|
|
|
|
The service should also enforce bounded status-check behavior:
|
|
|
|
- use timeouts for each runtime CLI command
|
|
- keep partial results if one command fails
|
|
- cache recent successful results briefly to avoid noisy repeated probes
|
|
|
|
## Required CLI Contract in `claude-multimodel`
|
|
|
|
The runtime should expose machine-readable commands.
|
|
|
|
### 1. Runtime version
|
|
|
|
Already available:
|
|
|
|
```bash
|
|
claude-multimodel --version
|
|
```
|
|
|
|
Used for:
|
|
|
|
- runtime version display in banner header
|
|
|
|
Version display rule:
|
|
|
|
- the app should normalize dev/build suffixes before rendering the banner header
|
|
- example:
|
|
- raw: `2.1.87-dev.20260401.t145625.sha38c09970 (Claude Code)`
|
|
- shown: `Claude 2.1.87`
|
|
|
|
### 2. Provider auth status
|
|
|
|
Add:
|
|
|
|
```bash
|
|
claude-multimodel auth status --json --provider all
|
|
```
|
|
|
|
Contract requirements:
|
|
|
|
- non-interactive only
|
|
- must never open a browser or prompt for user input
|
|
- must be side-effect free:
|
|
- no provider switching
|
|
- no token mutation unless the runtime explicitly performs a safe read-only refresh internally
|
|
- should return partial provider results when possible instead of failing the entire command on one provider-specific check
|
|
|
|
Example response:
|
|
|
|
```json
|
|
{
|
|
"schemaVersion": 1,
|
|
"providers": {
|
|
"anthropic": {
|
|
"supported": true,
|
|
"authenticated": true,
|
|
"authMethod": "oauth",
|
|
"verificationState": "verified",
|
|
"canLoginFromUi": true,
|
|
"capabilities": {
|
|
"teamLaunch": true,
|
|
"oneShot": true
|
|
}
|
|
},
|
|
"codex": {
|
|
"supported": true,
|
|
"authenticated": false,
|
|
"authMethod": null,
|
|
"verificationState": "verified",
|
|
"canLoginFromUi": true,
|
|
"capabilities": {
|
|
"teamLaunch": true,
|
|
"oneShot": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- no global `active` provider state belongs in this contract
|
|
- provider choice happens per launch request, not in global status
|
|
- `authenticated` means the runtime considers usable credentials/session state present for that provider
|
|
- `verificationState` must distinguish `verified` from `unknown` / `offline` / `error`
|
|
- `supported` means the current runtime build knows how to use that provider
|
|
- `capabilities` means the current runtime build knows which execution modes can use that provider
|
|
|
|
### 3. Provider model lists
|
|
|
|
Add:
|
|
|
|
```bash
|
|
claude-multimodel model list --json --provider all
|
|
```
|
|
|
|
Example response:
|
|
|
|
```json
|
|
{
|
|
"schemaVersion": 1,
|
|
"providers": {
|
|
"anthropic": {
|
|
"models": ["opus", "sonnet", "haiku"]
|
|
},
|
|
"codex": {
|
|
"models": ["gpt-5.3-codex", "gpt-5.4", "gpt-5.4-mini"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
This is intentionally separate from auth status so auth and capability failures can be handled independently.
|
|
|
|
Model listing should be available even when the provider is not currently authenticated, whenever the runtime can determine the model set statically.
|
|
|
|
### 4. Provider login
|
|
|
|
Add:
|
|
|
|
```bash
|
|
claude-multimodel auth login --provider anthropic
|
|
claude-multimodel auth login --provider codex
|
|
```
|
|
|
|
```bash
|
|
claude-multimodel auth logout --provider anthropic
|
|
claude-multimodel auth logout --provider codex
|
|
```
|
|
|
|
This allows `claude_team` to reuse runtime-managed login flows instead of implementing OAuth directly.
|
|
|
|
## Status Model in `claude_team`
|
|
|
|
Recommended DTO:
|
|
|
|
```ts
|
|
type ProviderId = 'anthropic' | 'codex';
|
|
|
|
interface ProviderStatus {
|
|
providerId: ProviderId;
|
|
displayName: string;
|
|
supported: boolean;
|
|
authenticated: boolean;
|
|
authMethod: 'oauth' | 'api_key' | 'external' | 'unknown' | null;
|
|
verificationState: 'verified' | 'unknown' | 'offline' | 'error';
|
|
statusMessage?: string | null;
|
|
models: string[];
|
|
canLoginFromUi: boolean;
|
|
capabilities: {
|
|
teamLaunch: boolean;
|
|
oneShot: boolean;
|
|
};
|
|
backend?: {
|
|
kind: string;
|
|
label: string;
|
|
endpointLabel?: string | null;
|
|
projectId?: string | null;
|
|
authMethodDetail?: string | null;
|
|
} | null;
|
|
}
|
|
|
|
interface ClaudeMultimodelDashboardStatus {
|
|
runtime: {
|
|
id: 'claude-multimodel';
|
|
installed: boolean;
|
|
version: string | null;
|
|
};
|
|
providers: ProviderStatus[];
|
|
}
|
|
```
|
|
|
|
## Dashboard Banner
|
|
|
|
One grouped banner should be shown.
|
|
It should replace the current dashboard runtime banner, not add a second top-level banner.
|
|
|
|
### Header
|
|
|
|
- runtime name/version, for example: `Claude 2.1.87`
|
|
- runtime auth-independent actions like `Extensions`
|
|
|
|
For `claude-multimodel` mode:
|
|
|
|
- keep the runtime version in the header
|
|
- hide runtime self-update UI
|
|
- hide binary path UI
|
|
|
|
### Provider rows
|
|
|
|
One row per provider:
|
|
|
|
- `Anthropic`
|
|
- `Codex`
|
|
|
|
Each row may show:
|
|
|
|
- authenticated state
|
|
- auth method
|
|
- verification state when status is uncertain
|
|
- model list if available
|
|
- backend diagnostics when the provider has internal backend resolution
|
|
- actions:
|
|
- `Login` when unauthenticated
|
|
- `Logout` when authenticated
|
|
- `Re-check` always
|
|
|
|
### Important UI rules
|
|
|
|
- Do not show a fake `Codex version`
|
|
- Do not show a separate `Codex installer`
|
|
- Do not show a fake `Download Codex` action
|
|
- Do not force a global provider choice from the banner
|
|
- If a provider has multiple internal backends, show them as provider diagnostics, not as separate provider rows
|
|
- Partial success must be visible:
|
|
- Anthropic ok, Codex missing
|
|
- Codex ok, Anthropic missing
|
|
|
|
## Launch Flow Changes
|
|
|
|
Current launch flow already supports a team-level `model`.
|
|
Current UI already has a provider affordance in [TeamModelSelector.tsx](../src/renderer/components/team/dialogs/TeamModelSelector.tsx). The remaining work is to keep provider/model normalization consistent across all launch surfaces.
|
|
|
|
Current code paths that must be kept in sync:
|
|
|
|
- shared types in [team.ts](../src/shared/types/team.ts)
|
|
- HTTP launch parsing in [teams.ts](../src/main/http/teams.ts)
|
|
- IPC launch/create validation in [teams.ts](../src/main/ipc/teams.ts)
|
|
- persisted draft metadata in [TeamMetaStore.ts](../src/main/services/team/TeamMetaStore.ts)
|
|
- scheduled one-shot config in [schedule.ts](../src/shared/types/schedule.ts)
|
|
- scheduled execution in [ScheduledTaskExecutor.ts](../src/main/services/schedule/ScheduledTaskExecutor.ts)
|
|
- provider/model UI helpers in [TeamModelSelector.tsx](../src/renderer/components/team/dialogs/TeamModelSelector.tsx)
|
|
- model display parsing in [modelParser.ts](../src/shared/utils/modelParser.ts)
|
|
- launch dialog state persistence in [LaunchTeamDialog.tsx](../src/renderer/components/team/dialogs/LaunchTeamDialog.tsx)
|
|
- create dialog state persistence in [CreateTeamDialog.tsx](../src/renderer/components/team/dialogs/CreateTeamDialog.tsx)
|
|
- saved draft restore in [teams.ts](../src/main/ipc/teams.ts)
|
|
- launch param persistence in the renderer store
|
|
- slash-command metadata in [slashCommands.ts](../src/shared/utils/slashCommands.ts)
|
|
|
|
Launch requests already carry provider selection. The remaining work is to keep request parsing, persistence, and runtime selection consistent. Future-compatible provider options can look like this:
|
|
|
|
```ts
|
|
interface TeamLaunchRequest {
|
|
providerId?: TeamProviderId;
|
|
model?: string;
|
|
providerOptions?: {
|
|
geminiBackendPreference?: 'auto' | 'api' | 'cli';
|
|
};
|
|
}
|
|
```
|
|
|
|
Provider selection must be applied only to the spawned child process environment/args.
|
|
It must not mutate a global app-wide runtime provider state.
|
|
|
|
This launch-time provider/model selection must be honored consistently across all spawn paths:
|
|
|
|
- manual team launch
|
|
- draft team launch that redirects into `createTeam`
|
|
- scheduled/background execution
|
|
- resume/retry/restart flows
|
|
- any other non-interactive process launch path that currently inherits team/model settings
|
|
|
|
Implementation rule:
|
|
|
|
- provider choice must be expressed via child-process-scoped args/env only
|
|
- conflicting provider env vars must be cleared for that child process
|
|
- one run using `codex` must not affect another run using `anthropic`
|
|
|
|
Future-compatible shape:
|
|
|
|
```ts
|
|
interface TeamLaunchRequest {
|
|
providerId?: TeamProviderId;
|
|
model?: string;
|
|
memberProviders?: Record<string, TeamProviderId>;
|
|
memberModels?: Record<string, string>;
|
|
}
|
|
```
|
|
|
|
This allows future per-teammate routing without redesigning the API again.
|
|
|
|
Launch-time preflight validation should fail fast before spawning the child process when possible:
|
|
|
|
- selected provider is unsupported by the current runtime build
|
|
- selected provider is clearly unauthenticated
|
|
- selected model is clearly incompatible with the selected provider
|
|
|
|
These checks should produce actionable errors for the user, while still treating cached banner model lists as advisory rather than authoritative.
|
|
|
|
The same provider/model fields must also be added to the data that currently persists launch intent:
|
|
|
|
- `TeamLaunchRequest`
|
|
- `TeamCreateRequest` for draft-team fallback
|
|
- `TeamMetaFile` in `team.meta.json`
|
|
- `ScheduleLaunchConfig`
|
|
|
|
Migration rule:
|
|
|
|
- when old persisted data has no `providerId`, treat it as `anthropic`
|
|
- new writes should persist `providerId` explicitly
|
|
|
|
UI persistence rule:
|
|
|
|
- provider selection must be persisted independently from model selection
|
|
- remembered model state must be namespaced by provider, or reset safely on provider switch
|
|
- a previously remembered Anthropic model must not be auto-applied to Codex, and vice versa
|
|
|
|
Launch source-of-truth rule:
|
|
|
|
- explicit values from the current launch request win
|
|
- persisted metadata is fallback only
|
|
- banner/provider status is informational and must never silently override a launch request
|
|
- provider-internal backend resolution may inform diagnostics, but it must not overwrite explicit launch-time provider options
|
|
|
|
Runtime observation rule:
|
|
|
|
- launch-time `providerId` / `model` are the requested starting configuration
|
|
- observed runtime message metadata may later reflect a different actual model after in-session commands such as `/model`
|
|
- the app must not conflate "requested at launch" with "currently observed in session"
|
|
|
|
## Edge Cases
|
|
|
|
### Provider auth combinations
|
|
|
|
Must support all of these without breaking the banner:
|
|
|
|
- Anthropic authenticated, Codex unauthenticated
|
|
- Codex authenticated, Anthropic unauthenticated
|
|
- both authenticated
|
|
- neither authenticated
|
|
|
|
All of these must remain first-class supported states in the banner.
|
|
|
|
The same rule extends to future providers with internal backends:
|
|
|
|
- one provider row may be authenticated while one backend path is degraded
|
|
- the banner should show provider-level health plus backend diagnostics without splitting into two pseudo-providers
|
|
|
|
### Provider supported, but not for this execution mode
|
|
|
|
A provider may be authenticated and generally supported, but still unavailable for a specific path:
|
|
|
|
- available for one-shot scheduler runs, but not Agent Teams
|
|
- available for Agent Teams, but not one-shot
|
|
|
|
The banner and preflight validation must not flatten these into a single boolean.
|
|
Capability checks must use the concrete execution mode being launched.
|
|
|
|
For providers with internal backends, capability checks may also depend on the resolved backend:
|
|
|
|
- provider supported, backend `api` unsupported for this path
|
|
- provider supported, backend `cli` supported for this path
|
|
|
|
That still remains one provider decision surface in `claude_team`.
|
|
|
|
### Runtime ok, provider verify uncertain
|
|
|
|
If network verification fails:
|
|
|
|
- do not downgrade directly to `authenticated = false`
|
|
- prefer `verificationState = unknown` or `offline`
|
|
|
|
### No global active provider
|
|
|
|
Because provider choice happens per launch:
|
|
|
|
- the status contract must not imply one provider is globally selected
|
|
- a user can keep both `Anthropic` and `Codex` signed in simultaneously
|
|
- the banner is informational, not a provider selector
|
|
|
|
### Provider selection must not leak between runs
|
|
|
|
If one team/process launches with `codex` and another launches with `anthropic`:
|
|
|
|
- this must not mutate the banner into a single globally active provider state
|
|
- launch-specific provider state should stay attached to the launched process/team metadata
|
|
- dashboard status should continue to reflect provider availability/auth only
|
|
- child process env must explicitly clear incompatible provider-selection variables before spawn
|
|
|
|
### Managed flags vs custom CLI args
|
|
|
|
`claude_team` already supports raw `extraCliArgs` / custom CLI args.
|
|
|
|
Those args must not be allowed to silently override app-managed launch intent such as:
|
|
|
|
- provider selection
|
|
- model selection
|
|
- permission mode defaults owned by the app
|
|
- any future provider-routing flags/env
|
|
|
|
The implementation should either:
|
|
|
|
- reject conflicting custom args with a validation error, or
|
|
- define a strict precedence rule where app-managed provider/model flags always win
|
|
|
|
but it must not allow ambiguous mixed configuration.
|
|
|
|
### Provider-specific model normalization
|
|
|
|
Current UI and launch code contain Claude-specific model assumptions, including:
|
|
|
|
- `limitContext`
|
|
- automatic `[1m]` suffixing
|
|
- defaulting to Claude-family model ids such as `opus[1m]`
|
|
|
|
These rules must become provider-aware:
|
|
|
|
- Anthropic may keep Claude-specific context/model normalization
|
|
- Codex must not inherit Claude-only suffix rules
|
|
- switching provider must not silently rewrite a selected model into an invalid format for that provider
|
|
|
|
### Provider-specific selector state
|
|
|
|
Current selector state is Anthropic-biased:
|
|
|
|
- provider UI is currently hardcoded to Anthropic
|
|
- model options are static Anthropic options
|
|
- launch/create dialogs remember one global last-selected model
|
|
|
|
The implementation must make selector state provider-aware:
|
|
|
|
- provider list must come from supported runtime providers, with unsupported placeholders still disabled
|
|
- model options must come from the selected provider, not a shared static list
|
|
- switching provider must either preserve a valid provider-local previous choice or clear to that provider's default
|
|
- the UI must not display a stale Anthropic label/model when `codex` is selected
|
|
|
|
### Resume and restart semantics
|
|
|
|
If a team/run is resumed, retried, or restarted later:
|
|
|
|
- the persisted launch-time `providerId` and `model` must remain the default for that resumed run
|
|
- changing banner status or current UI defaults must not silently rewrite old run configuration
|
|
- explicit user overrides during a new launch are allowed, but implicit fallback to a different provider is not
|
|
|
|
The same rule applies to edited schedules and stored drafts:
|
|
|
|
- opening an old schedule/draft in a newer UI must not silently rewrite provider/model until the user explicitly saves changes
|
|
|
|
If a running session changes model interactively after launch:
|
|
|
|
- launch metadata should remain the historical requested starting state
|
|
- observed session model should come from runtime output/log parsing
|
|
- resume should continue from the actual session state instead of blindly reimposing old defaults unless the user explicitly requests a fresh launch
|
|
|
|
### Draft-team launch fallback
|
|
|
|
`claude_team` can redirect a launch request into `createTeam` when only `team.meta.json` exists.
|
|
|
|
That fallback must preserve the same provider/model intent:
|
|
|
|
- `providerId` must survive the launch -> create redirect
|
|
- draft metadata must not drop provider selection
|
|
- create-time validation must match launch-time validation
|
|
|
|
### Models unavailable
|
|
|
|
If model listing fails but auth status succeeds:
|
|
|
|
- keep provider visible
|
|
- show auth state
|
|
- omit or gray out model list
|
|
|
|
If model listing succeeds for an unauthenticated provider:
|
|
|
|
- still show the model list
|
|
- do not block model visibility on login state
|
|
|
|
### Provider-specific model display parsing
|
|
|
|
Current shared model display utilities are Claude-oriented.
|
|
|
|
The integration must not assume:
|
|
|
|
- every model id starts with `claude-`
|
|
- every provider model can be parsed into Claude family/version semantics
|
|
|
|
For non-Claude providers, the UI should fall back to generic provider/model labels unless a provider-specific parser is added intentionally.
|
|
|
|
This also applies to in-session command output:
|
|
|
|
- `/model` command output or equivalent runtime messages may describe state transitions differently per provider
|
|
- the UI should not assume Anthropic-specific phrasing when interpreting provider/model changes
|
|
|
|
If model lists differ by execution mode in a future runtime build:
|
|
|
|
- the contract should evolve via `schemaVersion`
|
|
- old app versions should continue to degrade safely instead of assuming one global model set
|
|
|
|
If model lists are temporarily unavailable for the selected provider in the launch dialog:
|
|
|
|
- the UI should still allow safe fallback behavior for backward-compatible Anthropic flows
|
|
- Codex flows should avoid inventing a default model id that did not come from the runtime or explicit user choice
|
|
|
|
### Model list is advisory, not launch authority
|
|
|
|
Provider model lists in the banner are helpful capability hints only:
|
|
|
|
- the actual launch path must still validate provider/model compatibility at spawn time
|
|
- cached model lists must not be treated as proof that a launch will succeed
|
|
- auth changes, subscription changes, or runtime updates may change model availability between refresh and launch
|
|
|
|
### Older runtime build
|
|
|
|
If the runtime does not yet support the new JSON commands:
|
|
|
|
- show runtime status normally
|
|
- show provider section as unavailable
|
|
- include a message like `Provider status not supported by current claude-multimodel build`
|
|
|
|
### Login/logout refresh behavior
|
|
|
|
After a login or logout flow in the terminal modal:
|
|
|
|
- the app must invalidate cached provider status
|
|
- the banner must refresh automatically
|
|
- a canceled login must not be treated as auth failure
|
|
|
|
Refresh handling must also be race-safe:
|
|
|
|
- older async refresh results must not overwrite newer ones
|
|
- concurrent login/logout/re-check actions must not leave the banner in a stale mixed state
|
|
- provider rows should expose a temporary loading/pending state while a provider-specific action is in flight
|
|
|
|
### Running teams during auth changes
|
|
|
|
If the user logs in, logs out, or changes provider credentials while teams are already running:
|
|
|
|
- the banner should refresh to reflect the new provider status
|
|
- already-running teams must not be implicitly reconfigured by the dashboard refresh itself
|
|
- launch-time provider/model metadata for existing runs should remain attached to those runs
|
|
|
|
Provider status changes should also avoid leaking sensitive details into UI logs:
|
|
|
|
- no token values
|
|
- no raw OAuth payloads
|
|
- only high-level auth method / verification state / actionable error text
|
|
|
|
### Runtime missing
|
|
|
|
If `claude-multimodel` is missing or not executable:
|
|
|
|
- show runtime-level failure in the banner header
|
|
- provider rows should be disabled or shown as unavailable
|
|
- do not render stale provider state as if it were fresh
|
|
|
|
### Slow or hanging status commands
|
|
|
|
If one or more runtime CLI status commands are slow or hang:
|
|
|
|
- the dashboard must not block indefinitely
|
|
- show the last good known state when available
|
|
- mark uncertain sections as stale/unknown instead of replacing them with false negatives
|
|
|
|
### Mixed command support during rollout
|
|
|
|
During migration, some runtime builds may support:
|
|
|
|
- version probing
|
|
- auth status JSON
|
|
- but not model list JSON
|
|
|
|
The app should degrade gracefully per capability instead of requiring all commands to work at once.
|
|
|
|
### Provider-specific status degradation
|
|
|
|
If one provider status check succeeds and another degrades:
|
|
|
|
- keep the successful provider row fully usable
|
|
- mark only the failing provider row as `unknown` / `error`
|
|
- do not collapse the whole banner into a global failure state
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1. Runtime CLI contract
|
|
|
|
In `claude-multimodel`:
|
|
|
|
- add `auth status --json --provider all`
|
|
- add `model list --json --provider all`
|
|
- add `auth login --provider anthropic|codex`
|
|
- add `auth logout --provider anthropic|codex`
|
|
|
|
### Phase 2. Bridge service in `claude_team`
|
|
|
|
Add:
|
|
|
|
- `src/main/services/runtime/ClaudeMultimodelBridgeService.ts`
|
|
|
|
Implement:
|
|
|
|
- `getRuntimeVersion()`
|
|
- `getProviderAuthStatus()`
|
|
- `getProviderModels()`
|
|
- `getDashboardStatus()`
|
|
- `login(providerId)`
|
|
- `logout(providerId)`
|
|
|
|
The service should aggregate the banner DTO from multiple runtime CLI calls while keeping partial results usable.
|
|
|
|
### Phase 3. Banner integration
|
|
|
|
Refactor the dashboard CLI banner into a grouped runtime/provider banner:
|
|
|
|
- runtime header
|
|
- Anthropic provider row
|
|
- Codex provider row
|
|
|
|
This phase should also explicitly hide runtime path/update controls for `claude-multimodel` mode.
|
|
|
|
### Phase 4. Launch integration
|
|
|
|
Extend launch/create dialogs and IPC payloads:
|
|
|
|
- add `providerId`
|
|
- wire provider choice into spawned CLI args/env
|
|
- reuse the existing provider affordance in `TeamModelSelector` instead of creating a second provider selector
|
|
|
|
This phase must explicitly define the child-process env mapping for provider selection, including clearing conflicting provider flags.
|
|
It must also persist launch-time `providerId` alongside `model` in team/run metadata so existing runs remain inspectable after refresh.
|
|
It must update both the interactive team runtime path and the scheduler one-shot path.
|
|
|
|
Phase 4 should also explicitly hide or keep disabled unsupported providers in `TeamModelSelector` until their runtime support actually exists. In Phase 1/2/3, only `Anthropic` and `Codex` should move out of disabled state.
|
|
|
|
### Phase 5. Future teammate-level routing
|
|
|
|
Later extension:
|
|
|
|
- `memberProviders`
|
|
- `memberModels`
|
|
|
|
This phase should happen only after team-level provider/model selection is stable.
|
|
It will likely require both `claude_team` changes and runtime support in `claude-multimodel` for teammate-level routing.
|
|
|
|
## Why This Plan
|
|
|
|
This plan keeps the ownership boundary clean:
|
|
|
|
- `claude-multimodel` remains the source of truth for auth and provider capabilities
|
|
- `claude_team` remains a UI/orchestration layer
|
|
|
|
It also avoids the two bad extremes:
|
|
|
|
- no duplicated OAuth/token logic in `claude_team`
|
|
- no premature heavy runtime abstraction layer
|
|
|
|
This is the smallest architecture that is still robust enough for:
|
|
|
|
- multi-provider status
|
|
- launch-time provider selection
|
|
- future per-agent provider/model routing
|
|
- shared runtime ownership without duplicating auth logic in `claude_team`
|