@@ -85,8 +85,14 @@ def config_group():
8585)
8686@click .option (
8787 "--provider" ,
88- type = click .Choice (['openai-compatible' , 'anthropic' , 'bedrock' , 'azure-openai' ], case_sensitive = False ),
89- help = "LLM provider type (default: openai-compatible)"
88+ type = click .Choice (
89+ ['openai-compatible' , 'anthropic' , 'bedrock' , 'azure-openai' , 'claude-code' , 'codex' ],
90+ case_sensitive = False ,
91+ ),
92+ help = (
93+ "LLM provider type (default: openai-compatible). "
94+ "Use 'claude-code' or 'codex' to run on a CLI subscription instead of an API key."
95+ ),
9096)
9197@click .option (
9298 "--aws-region" ,
@@ -127,24 +133,33 @@ def config_set(
127133 • Linux: Secret Service (GNOME Keyring, KWallet)
128134
129135 Examples:
130-
136+
131137 \b
132- # Set all configuration
138+ # Set all configuration (API mode)
133139 $ codewiki config set --api-key sk-abc123 --base-url https://api.anthropic.com \\
134140 --main-model claude-sonnet-4 --cluster-model claude-sonnet-4 --fallback-model glm-4p5
135-
141+
142+ \b
143+ # Subscription mode (Claude Code) — no API key needed,
144+ # authenticate via 'claude login' on the host first
145+ $ codewiki config set --provider claude-code --main-model claude-sonnet-4-5
146+
147+ \b
148+ # Subscription mode (Codex)
149+ $ codewiki config set --provider codex --main-model gpt-5.2-codex
150+
136151 \b
137152 # Update only API key
138153 $ codewiki config set --api-key sk-new-key
139-
154+
140155 \b
141156 # Set max tokens for LLM response
142157 $ codewiki config set --max-tokens 16384
143-
158+
144159 \b
145160 # Set all max token settings
146161 $ codewiki config set --max-tokens 32768 --max-token-per-module 40000 --max-token-per-leaf-module 20000
147-
162+
148163 \b
149164 # Set max depth for hierarchical decomposition
150165 $ codewiki config set --max-depth 3
@@ -354,26 +369,36 @@ def config_show(output_json: bool):
354369 click .echo ("━" * 40 )
355370 click .echo ()
356371
372+ from codewiki .src .be .backend import is_caw_provider
373+ caw_mode = bool (config ) and is_caw_provider (config .provider )
374+
357375 click .secho ("Credentials" , fg = "cyan" , bold = True )
358- if api_key :
376+ if caw_mode :
377+ cli_name = "claude" if config .provider == "claude-code" else "codex"
378+ click .secho (
379+ f" Subscription mode: authenticate via '{ cli_name } login' (no API key needed)" ,
380+ fg = "cyan" ,
381+ )
382+ elif api_key :
359383 storage = "system keychain" if manager .keyring_available else "encrypted file"
360384 click .echo (f" API Key: { mask_api_key (api_key )} (in { storage } )" )
361385 else :
362386 click .secho (" API Key: Not set" , fg = "yellow" )
363-
387+
364388 click .echo ()
365389 click .secho ("API Settings" , fg = "cyan" , bold = True )
366390 if config :
367- click .echo (f" Base URL: { config .base_url or 'Not set' } " )
368- click .echo (f" Main Model: { config .main_model or 'Not set' } " )
369- click .echo (f" Cluster Model: { config .cluster_model or 'Not set' } " )
370- click .echo (f" Fallback Model: { config .fallback_model or 'Not set' } " )
371391 click .echo (f" Provider: { config .provider } " )
372- if config .provider == "bedrock" :
373- click .echo (f" AWS Region: { config .aws_region } " )
374- elif config .provider == "azure-openai" :
375- click .echo (f" API Version: { config .api_version } " )
376- click .echo (f" Azure Deployment: { config .azure_deployment or 'Not set' } " )
392+ click .echo (f" Main Model: { config .main_model or 'Not set' } " )
393+ if not caw_mode :
394+ click .echo (f" Base URL: { config .base_url or 'Not set' } " )
395+ click .echo (f" Cluster Model: { config .cluster_model or 'Not set' } " )
396+ click .echo (f" Fallback Model: { config .fallback_model or 'Not set' } " )
397+ if config .provider == "bedrock" :
398+ click .echo (f" AWS Region: { config .aws_region } " )
399+ elif config .provider == "azure-openai" :
400+ click .echo (f" API Version: { config .api_version } " )
401+ click .echo (f" Azure Deployment: { config .azure_deployment or 'Not set' } " )
377402 else :
378403 click .secho (" Not configured" , fg = "yellow" )
379404
@@ -479,75 +504,129 @@ def config_validate(quick: bool, verbose: bool):
479504 else :
480505 click .secho ("✓ Configuration file exists" , fg = "green" )
481506
482- # Step 2: Check API key
507+ # Load config early so we know the provider for the rest of the checks.
508+ config = manager .get_config ()
509+ from codewiki .src .be .backend import is_caw_provider
510+ caw_mode = bool (config ) and is_caw_provider (config .provider )
511+
512+ # Step 2: Check API key (skipped for subscription providers)
483513 if verbose :
484514 click .echo ()
485515 click .echo ("[2/5] Checking API key..." )
486- storage = "system keychain" if manager .keyring_available else "encrypted file"
487- click .echo (f" Storage: { storage } " )
488-
489- api_key = manager .get_api_key ()
490- if not api_key :
491- click .secho ("✗ API key missing" , fg = "red" )
492- click .echo ()
493- click .echo ("Error: API key not set. Run 'codewiki config set --api-key <key>'" )
494- sys .exit (EXIT_CONFIG_ERROR )
495-
496- if verbose :
497- click .secho (f" ✓ API key retrieved" , fg = "green" )
498- click .secho (f" ✓ Length: { len (api_key )} characters" , fg = "green" )
516+
517+ if caw_mode :
518+ if verbose :
519+ click .secho (" ✓ API key not required (subscription mode)" , fg = "green" )
520+ else :
521+ click .secho ("✓ API key not required (subscription mode)" , fg = "green" )
499522 else :
500- click .secho ("✓ API key present (stored in keychain)" , fg = "green" )
501-
502- # Step 3: Check base URL
503- config = manager .get_config ()
523+ if verbose :
524+ storage = "system keychain" if manager .keyring_available else "encrypted file"
525+ click .echo (f" Storage: { storage } " )
526+
527+ api_key = manager .get_api_key ()
528+ if not api_key :
529+ click .secho ("✗ API key missing" , fg = "red" )
530+ click .echo ()
531+ click .echo ("Error: API key not set. Run 'codewiki config set --api-key <key>'" )
532+ sys .exit (EXIT_CONFIG_ERROR )
533+
534+ if verbose :
535+ click .secho (f" ✓ API key retrieved" , fg = "green" )
536+ click .secho (f" ✓ Length: { len (api_key )} characters" , fg = "green" )
537+ else :
538+ click .secho ("✓ API key present (stored in keychain)" , fg = "green" )
539+
540+ # Step 3: Check base URL (skipped for subscription providers)
504541 if verbose :
505542 click .echo ()
506543 click .echo ("[3/5] Checking base URL..." )
507- click .echo (f" URL: { config .base_url } " )
508-
509- if not config .base_url :
510- click .secho ("✗ Base URL not set" , fg = "red" )
511- sys .exit (EXIT_CONFIG_ERROR )
512-
513- try :
514- validate_url (config .base_url )
544+
545+ if caw_mode :
515546 if verbose :
516- click .secho (" ✓ Valid HTTPS URL" , fg = "green" )
547+ click .secho (" ✓ Base URL not required (subscription mode) " , fg = "green" )
517548 else :
518- click .secho (f"✓ Base URL valid: { config .base_url } " , fg = "green" )
519- except ConfigurationError as e :
520- click .secho (f"✗ Invalid base URL: { e .message } " , fg = "red" )
521- sys .exit (EXIT_CONFIG_ERROR )
549+ click .secho ("✓ Base URL not required (subscription mode)" , fg = "green" )
550+ else :
551+ if verbose :
552+ click .echo (f" URL: { config .base_url } " )
553+
554+ if not config .base_url :
555+ click .secho ("✗ Base URL not set" , fg = "red" )
556+ sys .exit (EXIT_CONFIG_ERROR )
557+
558+ try :
559+ validate_url (config .base_url )
560+ if verbose :
561+ click .secho (" ✓ Valid HTTPS URL" , fg = "green" )
562+ else :
563+ click .secho (f"✓ Base URL valid: { config .base_url } " , fg = "green" )
564+ except ConfigurationError as e :
565+ click .secho (f"✗ Invalid base URL: { e .message } " , fg = "red" )
566+ sys .exit (EXIT_CONFIG_ERROR )
522567
523568 # Step 4: Check models
524569 if verbose :
525570 click .echo ()
526571 click .echo ("[4/5] Checking model configuration..." )
527572 click .echo (f" Main model: { config .main_model } " )
528- click .echo (f" Cluster model: { config .cluster_model } " )
529- click .echo (f" Fallback model: { config .fallback_model } " )
530-
531- if not config .main_model or not config .cluster_model or not config .fallback_model :
532- click .secho ("✗ Models not configured" , fg = "red" )
533- sys .exit (EXIT_CONFIG_ERROR )
534-
535- if verbose :
536- click .secho (" ✓ Models configured" , fg = "green" )
573+ if not caw_mode :
574+ click .echo (f" Cluster model: { config .cluster_model } " )
575+ click .echo (f" Fallback model: { config .fallback_model } " )
576+
577+ if caw_mode :
578+ if not config .main_model :
579+ click .secho ("✗ Main model not configured" , fg = "red" )
580+ sys .exit (EXIT_CONFIG_ERROR )
581+ if verbose :
582+ click .secho (" ✓ Main model configured" , fg = "green" )
583+ else :
584+ click .secho (f"✓ Main model configured: { config .main_model } " , fg = "green" )
537585 else :
538- click .secho (f"✓ Main model configured: { config .main_model } " , fg = "green" )
539- click .secho (f"✓ Cluster model configured: { config .cluster_model } " , fg = "green" )
540- click .secho (f"✓ Fallback model configured: { config .fallback_model } " , fg = "green" )
541-
542- # Warn about non-top-tier cluster model
543- if not is_top_tier_model (config .cluster_model ):
544- click .secho (
545- "⚠️ Cluster model is not top-tier. Consider using claude-sonnet-4 or gpt-4." ,
546- fg = "yellow"
547- )
548-
586+ if not config .main_model or not config .cluster_model or not config .fallback_model :
587+ click .secho ("✗ Models not configured" , fg = "red" )
588+ sys .exit (EXIT_CONFIG_ERROR )
589+
590+ if verbose :
591+ click .secho (" ✓ Models configured" , fg = "green" )
592+ else :
593+ click .secho (f"✓ Main model configured: { config .main_model } " , fg = "green" )
594+ click .secho (f"✓ Cluster model configured: { config .cluster_model } " , fg = "green" )
595+ click .secho (f"✓ Fallback model configured: { config .fallback_model } " , fg = "green" )
596+
597+ # Warn about non-top-tier cluster model
598+ if not is_top_tier_model (config .cluster_model ):
599+ click .secho (
600+ "⚠️ Cluster model is not top-tier. Consider using claude-sonnet-4 or gpt-4." ,
601+ fg = "yellow"
602+ )
603+
549604 # Step 5: API connectivity test (unless --quick)
550- if not quick :
605+ if caw_mode :
606+ if verbose :
607+ click .echo ()
608+ click .echo ("[5/5] Checking CLI availability..." )
609+
610+ import shutil
611+ cli_name = "claude" if config .provider == "claude-code" else "codex"
612+ cli_path = shutil .which (cli_name )
613+ if not cli_path :
614+ click .secho (f"✗ { cli_name } CLI not found in PATH" , fg = "red" )
615+ click .echo (
616+ f"\n Install the { cli_name } CLI and run '{ cli_name } login' "
617+ f"to authenticate, then re-run this command."
618+ )
619+ sys .exit (EXIT_CONFIG_ERROR )
620+
621+ if verbose :
622+ click .secho (f" ✓ { cli_name } CLI found at { cli_path } " , fg = "green" )
623+ click .secho (
624+ f" ↳ Ensure '{ cli_name } login' has been run on this host." ,
625+ fg = "cyan" ,
626+ )
627+ else :
628+ click .secho (f"✓ { cli_name } CLI available (run '{ cli_name } login' if not yet authenticated)" , fg = "green" )
629+ elif not quick :
551630 if verbose :
552631 click .echo ()
553632 click .echo ("[5/5] Testing API connectivity..." )
0 commit comments