Links:
Architecture: docs/Architecture/Overview.md
Modules: ClaudeClient.cs, ClaudeCliMetadataReader.cs, ClaudeCliMetadata.cs
Source of truth: local claude CLI behavior + upstream anthropics/claude-code tags and settings layout
The SDK package version mirrors the targeted Claude Code CLI version in its first three numeric components and uses the fourth component for an SDK hotfix. ClaudeCliCompatibility.TargetVersion exposes the exact compatible CLI target without starting a process. GetCliUpdateStatus() separately reports the latest version discovered from upstream.
Expose runtime Claude Code CLI metadata to SDK consumers:
- installed
claudeversion - default model configured in local Claude config
- SDK-known Claude model aliases/constants
- update availability status vs latest upstream tagged Claude Code version
The repository's upstream sync workflow separately tracks source changes in anthropics/claude-code.
ClaudeClient.GetCliMetadata()public API.ClaudeClient.GetCliUpdateStatus()public API.- Reading version from
claude --version. - Reading default model from Claude settings discovery (
.claude/settings.local.json,.claude/settings.json,~/.claude/settings.json) with SDK fallback aliassonnet. - Reading latest upstream tagged version from
https://github.com/anthropics/claude-code.git. - Returning
claude updatein update status when a newer upstream tag exists. - Installing/updating the SDK-pinned CLI in the SDK-owned per-user installation root.
- Remote model discovery over Anthropic APIs.
- Mutating user Claude config files.
- Replacing Claude Code CLI model selection logic.
- Mutating a separately detected global or project-local Claude installation.
- Metadata read is read-only and does not mutate local Claude state.
- SDK option and metadata decisions are based on real Claude Code CLI behavior, not any separate SDK surface.
- Update check failures (for example missing
gitor network access) must return actionable status messages and never silently fail. - Version/update probes must drain subprocess stdout and stderr concurrently so CLI metadata reads cannot deadlock on buffered process output.
- Metadata subprocesses use the same configured environment policy as SDK execution, and their runtime/output bounds are configured by
ClaudeOptions.CliMetadataProbeTimeoutandClaudeOptions.CliMetadataMaximumOutputCharacters. - A timeout kills the process tree and confirms root-process exit. Output is drained concurrently with bounded capture; exceeding either stream's cap fails the probe instead of parsing partial output.
- The upstream sync watcher must raise a repository issue when
anthropics/claude-codemoves ahead of the pinned submodule SHA.
ClaudeClient.InstallOrUpdateCliAsync(CliInstallationOptions, CancellationToken) installs exactly ClaudeCliCompatibility.TargetVersion through an explicitly configured npm or Bun package manager. The public API always writes under LocalApplicationData/ManagedCode/ManagedCode.ClaudeCodeSharpSDK/cli; callers cannot choose another installation root or provide command arguments. npm is launched as the configured absolute Node executable plus the validated npm-cli.js entrypoint, and Bun is launched directly with SDK-owned literal arguments.
The options require the package-manager executable, npm entrypoint when applicable, a minimal allowlisted environment, install and termination timeouts, a per-root lock wait, and metadata/output limits. Provider credentials and arbitrary environment variables are rejected. Progress reports only lifecycle stage and stdout/stderr character counts; it never returns package-manager output text. Installed is emitted only after the bounded package manifest matches the exact target and the normal CLI resolver returns a verified CliLaunchCommand. After root exit, cleanup waits within the configured bound for natural stdout/stderr EOF before aborting readers; failure to confirm EOF or reader cleanup remains an unconfirmed cleanup error. Cancellation, nonzero exit, output overflow, timeout, version mismatch, and unconfirmed cleanup fail the stream.
Pass CliInstallationResult.LaunchCommand to ClaudeOptions.LaunchCommand when constructing the MEAI client. This preserves safe literal prefix arguments such as node.exe plus the installed JavaScript entrypoint on Windows.
The root lock serializes install/update operations across processes. An ownership marker prevents reuse of a nonempty directory that was not created by this SDK. The test assembly uses the internal local-application-data-root seam to run real npm child processes inside tests/.sandbox; the public API has no root override.
flowchart LR
Client["ClaudeClient.GetCliMetadata()"] --> Version["claude --version"]
Client --> Update["ClaudeClient.GetCliUpdateStatus()"]
Client --> Config[".claude/settings.local.json /.claude/settings.json / ~/.claude/settings.json"]
Update --> Git["git ls-remote --tags anthropics/claude-code"]
Version --> Metadata["ClaudeCliMetadata"]
Git --> UpdateStatus["ClaudeCliUpdateStatus"]
Config --> Metadata
- Unit parsing/update-check coverage: ClaudeCliMetadataReaderTests.cs
- CLI arg behavior: ClaudeExecTests.cs
- Isolated install/update process behavior: CliInstallationTests.cs