On this page
Segment model, SegmentBar, and option discovery logic.
#claudewheel.segment
#claudewheel.segment
Segment and SegmentBar dataclasses, option discovery, and cross-segment constraints.
#DiscoveryResult
Structured result from a discovery function.
#DiscoveryEntry
Registry entry mapping a discovery type to its function.
#_deduplicate
def _deduplicate(items: list[str]) -> list[str]Remove duplicates preserving first occurrence order.
#SegmentState
Manages option collections with cache-invalidating mutation methods.
#options
def options(self) -> list[str]Return the computed option list, rebuilding from collections if invalidated.
#set_discovered
def set_discovered(self, vals: list[str], *, verify_fn: Callable[[str], bool] | None=None) -> NoneReplace discovered values, optionally verifying old values before dropping them.
#add_pinned
def add_pinned(self, val: str) -> NoneAdd a value to the pinned collection if not already present.
#remove_pinned
def remove_pinned(self, val: str) -> NoneRemove a value from the pinned collection, ignoring if absent.
#set_defaults
def set_defaults(self, vals: list[str]) -> NoneReplace the defaults collection with the given values.
#add_ephemeral
def add_ephemeral(self, val: str) -> NoneAdd a value to the ephemeral collection if not already present.
#set_installed
def set_installed(self, vals: set[str]) -> NoneReplace the installed set with the given values.
#has_installed
def has_installed(self) -> boolTrue when at least one value is marked as installed.
#mark_installed
def mark_installed(self, val: str) -> NoneMark a single value as installed.
#set_metadata
def set_metadata(self, meta: dict[str, dict[str, Any]]) -> NoneReplace all metadata with the given mapping.
#update_metadata
def update_metadata(self, partial: dict[str, dict[str, Any]]) -> NoneMerge partial metadata into the existing metadata mapping.
#source_of
def source_of(self, val: str) -> str | NoneReturn the collection name containing val, or None if not found.
#is_installed
def is_installed(self, val: str) -> boolTrue when val is in the installed set.
#set_authenticated
def set_authenticated(self, vals: set[str]) -> NoneSet the authenticated values and activate auth status tracking.
#set_managed
def set_managed(self, vals: set[str]) -> NoneRecord the "managed" (externally-managed) values.
A managed value is neither authenticated nor unauthenticated: cw cannot verify its auth because Claude Code owns it (the "default" profile, ~/.claude). Managed values are excluded from the unauthenticated rendering/interception paths.
#has_auth_status
def has_auth_status(self) -> boolTrue when auth status tracking has been activated.
#is_authenticated
def is_authenticated(self, val: str) -> boolTrue when val is in the authenticated set.
#is_managed
def is_managed(self, val: str) -> boolTrue when val is externally managed (e.g. the vanilla default).
#Segment
A single segment in the TUI bar with options, selection state, and search.
#options
def options(self) -> list[str]Delegate to state.options for the computed option list.
#display_options
def display_options(self) -> list[str]Options visible in the UI: real options + virtual "+" for creatable segments.
#selected_idx
def selected_idx(self) -> intComputed index of selected_value in display_options, or -1 if unselected.
#value
def value(self) -> str | NoneReturn the selected value if it is a real option, or None otherwise.
#filtered_options
def filtered_options(self) -> list[str]Return options filtered by search_buffer using fuzzy matching.
Filters against self.options (not display_options), so "+" is excluded from fuzzy search. This is intentional.
#cycle
def cycle(self, direction: int) -> NoneMove selection up (+1) or down (-1) through display_options.
The ring has n+1 positions: [None, 0, 1, ..., n-1] where None is the blank/unselected state and n = len(display_options). With wrap=True, cycling continuously rotates through all positions including blank. With wrap=False, blank is reachable from EITHER end of the option list (UP from first OR DOWN from last), but going past blank in either direction stays at blank rather than continuing to the other end.
#is_on_plus
def is_on_plus(self) -> boolTrue if the current selection is the '+' creation sentinel.
#select_value
def select_value(self, val: str) -> boolSelect an option by its string value. Returns True if found.
#_Segment_init_wrapper
def _Segment_init_wrapper(self: Segment, *args: Any, options: Any=None, **kwargs: Any) -> NoneTranslate the options= kwarg to _init_options= for backward compat.
#SegmentBar
Ordered collection of segments with focus tracking and navigation.
#focused
def focused(self) -> SegmentReturn the currently focused segment, or raise if the bar is empty.
#move_focus
def move_focus(self, direction: int) -> NoneMove focus left (-1) or right (+1), wrapping around the segment list.
#get_selections
def get_selections(self) -> dict[str, str | None]Return a dict mapping each segment key to its selected value.
#version_sort_key
def version_sort_key(version: str) -> list[int]Split a version string on '.' and convert parts to ints for numeric sorting.
#fetch_npm_versions
def fetch_npm_versions(state: dict[str, Any], count: int=15) -> list[str]Fetch recent Claude Code versions from npm, with 1-hour cache in state.
#_discover_directory_listing
def _discover_directory_listing(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultDiscover options from a directory of files (e.g., installed versions).
#_discover_npm_and_local
def _discover_npm_and_local(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultDiscover versions from npm registry + locally installed files.
#_discover_npm_and_local_cached
def _discover_npm_and_local_cached(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultFast path for npm_and_local: use cached npm versions only if warm.
#_discover_directory_scan
def _discover_directory_scan(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultDiscover directories by scanning parent directories.
Recent dirs from state are used as hints: validated (must exist on disk), emitted first in the result, and pruned back to state (stale entries removed). Static values from options.json are NOT included -- they are handled by SegmentState.defaults via the defaults collection.
#_discover_profiles
def _discover_profiles(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultDiscover Claude Code profiles via ProfileStore enumeration.
Profile identity comes solely from the store (profile dirs + tokens); config_dir is never persisted, so metadata carries only auth-presence fields. A corrupt tokens.json raises TokenStoreError, which propagates so discovery fails loudly rather than silently omitting profiles.
#_discover_gh_accounts
def _discover_gh_accounts(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultDiscover GitHub accounts from gh CLI auth status.
#_discover_state_field
def _discover_state_field(config: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> DiscoveryResultDiscover options by merging state-tracked values with static defaults.
#_parse_static_values
def _parse_static_values(config: dict[str, Any]) -> list[str]Extract plain string values from an options_def entry, stripping requires dicts.
#_parse_requires
def _parse_requires(config: dict[str, Any]) -> dict[str, dict[str, str]]Extract requires constraints from dict-style values in an options_def entry.
#run_slow_discovery_via_registry
def run_slow_discovery_via_registry(options_def: dict[str, Any], state: dict[str, Any], ws: 'Workspace') -> dict[str, DiscoveryResult]Run only slow discovery types via the registry.
Mutates state (e.g. fetch_npm_versions writes npm_versions_cache). Callers running this in a background thread should pass a deep copy of the shared state dict and merge results back on the main thread.
#populate_segment_state
def populate_segment_state(seg: 'Segment', options_def_entry: dict[str, Any], state: dict[str, Any], ws: 'Workspace', *, skip_slow: bool=True) -> NonePopulate a segment's state from discovery and static config.
Looks up the discovery config, calls the registry function (unless slow and skip_slow is True), and writes results to seg.state.
#_update_auth_from_metadata
def _update_auth_from_metadata(seg: 'Segment') -> NoneCompute the authenticated and managed sets from segment metadata.
Ternary classification:
managed=True-> the value is externally managed (Claude Code owns it,
e.g. the vanilla default). cw cannot verify its auth, so it is neither authenticated NOR unauthenticated -- it goes in the managed set and is excluded from the unauthenticated (dim/intercept) paths.
- otherwise a value is authenticated if its metadata has
has_token=True
or has_credentials=True, else unauthenticated.
Auth tracking is only activated when at least one metadata entry carries any of these fields, keeping the feature invisible to segments that don't use it.
#build_segment_bar
def build_segment_bar(cfg: 'AppConfigStore', *, skip_slow: bool=False) -> SegmentBarConstruct the segment bar from config, applying discovery and last-state restore.
#merge_slow_results
def merge_slow_results(bar: SegmentBar, results: dict[str, DiscoveryResult], state: dict[str, Any], options_def: dict[str, Any] | None=None) -> NoneMerge background discovery results into the live segment bar.
For each segment with new options in results, update its discovered list via SegmentState, update the installed set, and restore the previous selection (falling back to last_config from state).
When options_def is provided, staleness verify callbacks from the discovery registry are wired through so values that still exist on disk are not prematurely dropped.
#evaluate_requires
def evaluate_requires(bar: SegmentBar) -> NoneRecompute unavailable sets based on cross-segment requirements.
#_satisfies_constraint
def _satisfies_constraint(value: str | None, constraint: str) -> boolCheck if a value satisfies a version constraint like '>=2.1.110'.