Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ jobs:
shell: powershell
run: tests/windows-profiles.ps1

- name: Claude compatibility policy tests
shell: powershell
run: tests/claude-compat.Tests.ps1

- name: batch launcher is CRLF and BOM-free
shell: pwsh
run: |
Expand All @@ -80,3 +84,25 @@ jobs:
rem `echo` does not reset ERRORLEVEL in cmd, so the expected 1 would
rem otherwise leak out and fail the step.
exit /b 0

claude-compat:
strategy:
fail-fast: false
matrix:
include:
- release: '2.1.186'
experimental: false
- release: stable
experimental: false
- release: latest
experimental: true
continue-on-error: ${{ matrix.experimental }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Claude Code ${{ matrix.release }}
run: curl -fsSL https://claude.ai/install.sh | bash -s "${{ matrix.release }}"
- name: Check installed CLI capabilities
run: |
export PATH="$HOME/.local/bin:$PATH"
tests/claude-installed-compat.sh
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ Older installs that use one account migrate to `profiles/default` once. Migratio
not overwrite an existing profile. A running legacy proxy keeps its private
config until it exits. The next launch removes the retired secret files.

### Keep Claude Code compatible

`qbraid-code` supports Claude Code 2.1.186 or newer. It is tested through
2.1.238. The installer checks both the version and required HTTP MCP commands.

Set `QBRAID_CODE_CLAUDE_POLICY` before installation to control an incompatible
Claude Code installation.

| Value | Installer behavior |
|---|---|
| `prompt` | Ask before installing or upgrading. Fail without a terminal. |
| `upgrade` | Install Anthropic's stable channel without prompting. |
| `fail` | Stop without changing Claude Code. |
| `continue` | Keep the installed version and skip unavailable features. |

The installer never downgrades a newer or unrecognized version. If your version
cannot run `claude mcp login`, authenticate through Claude Code's `/mcp` menu.

## Start a session

Start an interactive session with the active organization and default model.
Expand Down
74 changes: 70 additions & 4 deletions doctor.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,68 @@ if (-not $token -and $settings['QBRAID_CODE_SECRET_BACKEND'] -eq 'credential-loc
} catch { }
}
$model = $settings['QBRAID_CODE_MODEL']
$claudeMinVersion = '2.1.186'
$claudeTestedMax = '2.1.238'

function ConvertFrom-ClaudeVersionString {
param([string]$Text)
if ($Text -match '(\d+\.\d+\.\d+)') { return $Matches[1] }
return $null
}

function Test-ClaudeMcpCommand {
param([string]$Command)
$help = (& claude mcp --help 2>$null | Out-String)
return $help -match "(?m)^\s+$([regex]::Escape($Command))(?:\s|$)"
}

function Test-ClaudeMcpHttp {
$help = (& claude mcp add --help 2>$null | Out-String)
return $help -match '(?s)--transport.*\bhttp\b'
}

function Test-ClaudeMcpUserScope {
$help = (& claude mcp add --help 2>$null | Out-String)
return $help -match '(?s)--scope.*\buser\b'
}

$claudePresent = $false
$claudeVersion = $null
$mcpAdd = $false
$mcpGet = $false
$mcpLogin = $false
$mcpHttp = $false
$mcpUserScope = $false
if (Get-Command claude -ErrorAction SilentlyContinue) {
$claudePresent = $true
$version = (& claude --version 2>$null)
if (-not $version) { $version = 'present' }
Write-Host "claude: $version"
$claudeVersion = ConvertFrom-ClaudeVersionString ($version | Out-String)
$mcpAdd = Test-ClaudeMcpCommand 'add'
$mcpGet = Test-ClaudeMcpCommand 'get'
$mcpLogin = Test-ClaudeMcpCommand 'login'
$mcpHttp = Test-ClaudeMcpHttp
$mcpUserScope = Test-ClaudeMcpUserScope
} else {
Write-Host 'claude: NOT INSTALLED'
}
if (-not $claudeVersion) {
Write-Host "claude-min: UNKNOWN (requires $claudeMinVersion+)"
Write-Host 'claude-tested: unknown'
} elseif ([version]$claudeVersion -lt [version]$claudeMinVersion) {
Write-Host "claude-min: FAIL (requires $claudeMinVersion+, found $claudeVersion)"
Write-Host 'claude-tested: unsupported'
} elseif ([version]$claudeVersion -gt [version]$claudeTestedMax) {
Write-Host "claude-min: PASS (requires $claudeMinVersion+)"
Write-Host "claude-tested: NEWER than tested $claudeTestedMax (not blocked)"
} else {
Write-Host "claude-min: PASS (requires $claudeMinVersion+)"
Write-Host "claude-tested: within tested range through $claudeTestedMax"
}
$claudePolicy = if ($env:QBRAID_CODE_CLAUDE_POLICY) { $env:QBRAID_CODE_CLAUDE_POLICY } else { 'prompt' }
Write-Host "claude-policy: $claudePolicy"
Write-Host "capabilities: mcp-add=$($mcpAdd.ToString().ToLower()) mcp-get=$($mcpGet.ToString().ToLower()) mcp-login=$($mcpLogin.ToString().ToLower()) mcp-http=$($mcpHttp.ToString().ToLower()) mcp-user-scope=$($mcpUserScope.ToString().ToLower())"

# Separate transport failure from rejection. Reporting "REJECTED" for a dropped
# connection sent people off to make a new key for no reason.
Expand Down Expand Up @@ -82,11 +136,23 @@ try {
Write-Host 'gateway: UNREACHABLE'
}

& claude mcp get qbraid *> $null
if ($LASTEXITCODE -eq 0) {
Write-Host "mcp: registered (run 'claude mcp login qbraid' if tools are missing)"
if (-not $claudePresent -or -not $mcpGet) {
Write-Host 'mcp: UNAVAILABLE - upgrade Claude Code or configure it through /mcp'
} else {
Write-Host 'mcp: NOT REGISTERED'
& claude mcp get qbraid *> $null
if ($LASTEXITCODE -eq 0) {
if ($mcpLogin) {
Write-Host "mcp: registered (run 'claude mcp login qbraid' if tools are missing)"
} else {
Write-Host 'mcp: registered (run /mcp inside Claude Code to authenticate)'
}
} else {
if ($mcpLogin) {
Write-Host 'mcp: NOT REGISTERED - re-run the installer'
} else {
Write-Host 'mcp: NOT REGISTERED - configure and authenticate through /mcp'
}
}
}

Write-Host "model: $model"
Expand Down
Loading
Loading