Skip to content
claudewheel.clients
Edit
On this page

Adapter registry mapping resolved launch selections to a client-specific argv, targeting the official claude binary or the miniclaude REPL client.

#claudewheel.clients

#claudewheel.clients

Client adapters: map resolved launch inputs to a client-specific argv.

claudewheel can launch different Claude-compatible clients. Each client is an "adapter" -- a function that turns the shared launch context (resolved binary inputs, model id, selections, session flags) into the concrete argv handed to os.execvpe. The seam lets claudewheel target the official claude binary or an alternative client like miniclaude without special-casing launch.py.

Adapters:

  • claude: the official Claude Code CLI. Preserves claudewheel's historical

argv exactly (default_flags + strict-mcp + permission + model + --disallowedTools + session/passthrough flags), with the binary chosen by the :class:~claudewheel.binaries.BinaryLocator.

  • miniclaude: the miniclaude REPL client. Builds miniclaude repl with a

mapped permission mode and mapped session flags. By-definition claude-only inputs that simply do not apply are ignored without error: the version selection (it names a claudewheel-managed claude binary, which a non-claude client never execs), the mcp selection ("strict" maps to claude's --strict-mcp-config; miniclaude has no equivalent), config.default_flags (raw claude CLI flags), and the DISALLOWED_TOOLS constant. Ignoring version/mcp here is what lets a plain --client miniclaude succeed even when a claude-only value is remembered in last_config or set as a config default; a contradictory, same-invocation explicit override (-s version=... / -s mcp=strict together with a non-claude --client) is rejected upstream in the CLI, not here.

Every hard error raised here is a :class:ValueError so the CLI launch sequence catches it and prints a clean, actionable message instead of a traceback.

#ClientContext

Everything an adapter needs to build a client argv.

:func:claudewheel.launch.resolve_launch_config assembles the shared pieces (profile env, cwd, gh token, resolved model id) and hands the rest to the selected adapter.

extra_flags is the claude-form session flags followed by the passthrough tail (session flags + passthrough); passthrough is that same tail on its own. The claude adapter appends extra_flags verbatim; the miniclaude adapter uses :meth:session_flags (the prefix with the passthrough tail removed) and rejects any passthrough outright.

#session_flags

python
def session_flags(self) -> list[str]

The session-flag prefix of extra_flags with the passthrough tail removed.

#build_claude_argv

python
def build_claude_argv(ctx: ClientContext) -> list[str]

Build the argv for the official claude CLI.

Byte-for-byte identical to claudewheel's historical argv assembly: [binary] + default_flags + strict-mcp + permission + model + --disallowedTools + extra_flags. The binary is the selected version's on-disk path (a missing version is an :class:OSError) or the locator's fallback symlink when no version is selected.

#build_miniclaude_argv

python
def build_miniclaude_argv(ctx: ClientContext) -> list[str]

Build the argv for the miniclaude REPL client.

Shape: [binary, "repl", "--profile", <profile>, "--model", <model id>, "--permission-mode", <mapped>] + <session flags>. --model and --permission-mode are included only when the corresponding selection is present. A missing profile, an unsupported session flag, and passthrough args are all HARD ERRORS -- never silent drops.

version and mcp selections are IGNORED, not rejected: a version names a claudewheel-managed claude binary and mcp "strict" maps to claude's --strict-mcp-config, so for a non-claude client they are by-definition-inapplicable inputs on the same footing as default_flags and DISALLOWED_TOOLS. This is what lets --client miniclaude succeed when such a value is merely remembered/configured. A contradictory explicit override passed in the same invocation is rejected upstream in the CLI (claudewheel.cli), where the selection's provenance is known.

#_miniclaude_session_flags

python
def _miniclaude_session_flags(ctx: ClientContext) -> list[str]

Translate claude-form session flags into miniclaude equivalents.

--continue -> --continue-session; --resume <id> -> --resume <id>. A bare --resume (claude's session picker), --print/-p, and any passthrough args are HARD ERRORS: miniclaude has no session picker, no print mode, and no generic passthrough.

#resolve_default_client

python
def resolve_default_client(config: dict[str, Any]) -> str

Return the configured default_client, validated against the registry.

Reads config["default_client"] (falling back to :data:DEFAULT_CLIENT when the key is absent). An unknown value is a HARD ERROR (:class:ValueError) -- never a silent fallback to "claude" -- so a typo in config.json fails loudly instead of quietly launching the wrong client.

#client_available

python
def client_available(name: str, locator: BinaryLocator, clients_config: dict[str, Any]) -> bool

Report whether name's launch binary is resolvable right now.

Mirrors each adapter's own binary resolution so the picker's availability marking matches what an actual launch would find:

  • claude: the :class:~claudewheel.binaries.BinaryLocator fallback

symlink (what build_claude_argv execs when no version is selected).

  • miniclaude: the configured clients.miniclaude.binary or a PATH

miniclaude (what build_miniclaude_argv resolves).

A client with no known probe is reported available (True): we cannot prove it missing, so we never mislabel a freshly added adapter as "not installed".

#build_client_choices

python
def build_client_choices(locator: BinaryLocator, clients_config: dict[str, Any], default_client: str) -> tuple[list[tuple[str, str]], str]

Build the (options, initial_key) pair for the client-selection step.

Options are the :data:CLIENT_ADAPTERS registry entries in registry order ("claude" first), as (key, label) pairs for :func:claudewheel.ui.run_selection. The key is always the bare client name; unavailable clients get a " (not installed)" label suffix rather than being hidden -- selecting one still launches and fails with the adapter's own hard-error message. initial_key is default_client, so the cursor starts on the configured default.

#resolve_client

python
def resolve_client(explicit_client: str | None, prompt: Callable[[], str | None]) -> str | None

Resolve the launch client: explicit CLI flag wins, else prompt.

explicit_client is the --client value when the user passed it, or None when they did not. When it is set, it is returned verbatim and prompt is NOT called (explicit wins, the TUI step is skipped). Otherwise prompt (a zero-arg callable that runs the interactive picker) is invoked and its result returned -- a client name, or None if the user cancelled.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • selfdoc Static Site Generator that builds a project's documentation site directly from its source code, so the docs can never drift from the code they describe, with SEO/AEO, first-class blog, search, and cross-project linking built in
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search