@@ -316,8 +316,10 @@ def navigate(clone_dir: Path, extra_env: dict[str, str] = {}) -> None:
316316 os .execv (shell , [shell ])
317317
318318
319- def resume (clone_dir : Path , extra_env : dict [str , str ] = {}) -> None :
319+ def resume (clone_dir : Path , extra_env : dict [str , str ] | None = None ,
320+ model : str = "claude-opus-4-7" ) -> None :
320321 """Trust, chdir, and exec claude --resume — replacing this process."""
322+ extra_env = extra_env or {}
321323 trust_project (clone_dir )
322324 os .chdir (str (clone_dir ))
323325 settings = load_luv_settings (clone_dir )
@@ -330,7 +332,7 @@ def resume(clone_dir: Path, extra_env: dict[str, str] = {}) -> None:
330332 base = docker_compose_base (clone_dir , compose_file , project )
331333 r = subprocess .run (base + ["exec" , "-it" ] + docker_env_flags (extra_env ) + ["dev-environment" ,
332334 "claude" , "--dangerously-skip-permissions" ,
333- "--model" , "claude-opus-4-7" ,
335+ "--model" , model ,
334336 "--effort" , "max" , "--resume" ,
335337 "--remote-control" ,
336338 "--remote-control-session-name-prefix" , clone_dir .name ])
@@ -343,21 +345,23 @@ def resume(clone_dir: Path, extra_env: dict[str, str] = {}) -> None:
343345 die ("'claude' not found in PATH" )
344346 os .environ .update (extra_env )
345347 os .execv (claude_bin , [claude_bin , "--dangerously-skip-permissions" ,
346- "--model" , "claude-opus-4-7" , "--effort" , "max" , "--resume" ,
348+ "--model" , model , "--effort" , "max" , "--resume" ,
347349 "--remote-control" ,
348350 "--remote-control-session-name-prefix" , clone_dir .name ])
349351
350352
351353def launch (clone_dir : Path , prompt : str | None , plan_mode : bool = False ,
352- non_interactive : bool = False , extra_env : dict [str , str ] = {}) -> None :
354+ non_interactive : bool = False , extra_env : dict [str , str ] | None = None ,
355+ model : str = "claude-opus-4-7" ) -> None :
353356 """Trust, resolve claude, chdir, and exec — replacing this process."""
357+ extra_env = extra_env or {}
354358 trust_project (clone_dir )
355359 os .chdir (str (clone_dir ))
356360 settings = load_luv_settings (clone_dir )
357361 compose_file = (settings or {}).get ("compose_file" )
358362
359363 common_flags = ["--dangerously-skip-permissions" ,
360- "--model" , "claude-opus-4-7" ,
364+ "--model" , model ,
361365 "--effort" , "max" ,
362366 "--remote-control" ,
363367 "--remote-control-session-name-prefix" , clone_dir .name ]
@@ -504,8 +508,9 @@ def find_latest_clone(repo: str) -> Path | None:
504508 return best
505509
506510
507- def open_existing (org : str , repo : str , number : int , prompt : str | None , nav_mode : bool = False , resume_mode : bool = False , plan_mode : bool = False , non_interactive : bool = False , extra_env : dict [str , str ] = {} ) -> None :
511+ def open_existing (org : str , repo : str , number : int , prompt : str | None , nav_mode : bool = False , resume_mode : bool = False , plan_mode : bool = False , non_interactive : bool = False , extra_env : dict [str , str ] | None = None , model : str = "claude-opus-4-7" ) -> None :
508512 """Open an existing work folder or remote branch by number."""
513+ extra_env = extra_env or {}
509514 clone_dir = PRS_DIR / f"{ repo } -{ number } "
510515
511516 # 1. Local folder takes priority
@@ -515,9 +520,9 @@ def open_existing(org: str, repo: str, number: int, prompt: str | None, nav_mode
515520 if nav_mode :
516521 navigate (clone_dir , extra_env = extra_env )
517522 elif resume_mode :
518- resume (clone_dir , extra_env = extra_env )
523+ resume (clone_dir , extra_env = extra_env , model = model )
519524 else :
520- launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env )
525+ launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env , model = model )
521526 return # unreachable
522527
523528 # 2. Check remote branch luv-{number}
@@ -542,13 +547,14 @@ def open_existing(org: str, repo: str, number: int, prompt: str | None, nav_mode
542547 if nav_mode :
543548 navigate (clone_dir , extra_env = extra_env )
544549 elif resume_mode :
545- resume (clone_dir , extra_env = extra_env )
550+ resume (clone_dir , extra_env = extra_env , model = model )
546551 else :
547- launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env )
552+ launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env , model = model )
548553
549554
550- def open_pr (org : str , repo : str , number : int , prompt : str | None , nav_mode : bool = False , resume_mode : bool = False , plan_mode : bool = False , non_interactive : bool = False , extra_env : dict [str , str ] = {} ) -> None :
555+ def open_pr (org : str , repo : str , number : int , prompt : str | None , nav_mode : bool = False , resume_mode : bool = False , plan_mode : bool = False , non_interactive : bool = False , extra_env : dict [str , str ] | None = None , model : str = "claude-opus-4-7" ) -> None :
551556 """Open any GitHub PR by org/repo/number, cloning if needed."""
557+ extra_env = extra_env or {}
552558 clone_dir = PRS_DIR / f"{ repo } -{ number } "
553559
554560 if clone_dir .exists ():
@@ -557,9 +563,9 @@ def open_pr(org: str, repo: str, number: int, prompt: str | None, nav_mode: bool
557563 if nav_mode :
558564 navigate (clone_dir , extra_env = extra_env )
559565 elif resume_mode :
560- resume (clone_dir , extra_env = extra_env )
566+ resume (clone_dir , extra_env = extra_env , model = model )
561567 else :
562- launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env )
568+ launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env , model = model )
563569 return # unreachable
564570
565571 # Resolve the actual branch name via GitHub API
@@ -584,9 +590,9 @@ def open_pr(org: str, repo: str, number: int, prompt: str | None, nav_mode: bool
584590 if nav_mode :
585591 navigate (clone_dir , extra_env = extra_env )
586592 elif resume_mode :
587- resume (clone_dir , extra_env = extra_env )
593+ resume (clone_dir , extra_env = extra_env , model = model )
588594 else :
589- launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env )
595+ launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env , model = model )
590596
591597
592598def main () -> None :
@@ -599,6 +605,20 @@ def main() -> None:
599605 force = "-f" in args or "--force" in args
600606 safe = "--safe" in args
601607 env_mode = "-e" in args
608+
609+ # -m takes a value, so extract it before the boolean-flag strip below
610+ model = "claude-opus-4-7"
611+ if args .count ("-m" ) > 1 :
612+ die ("-m may only be provided once" )
613+ if "-m" in args :
614+ idx = args .index ("-m" )
615+ if idx + 1 >= len (args ):
616+ die ("-m requires a model name" )
617+ model = args [idx + 1 ].strip ()
618+ if not model or model .startswith ("-" ):
619+ die ("-m requires a model name" )
620+ args = args [:idx ] + args [idx + 2 :]
621+
602622 args = [a for a in args if a not in ("-n" , "-r" , "-e" , "-f" , "--force" , "-p" , "-nit" , "--safe" )]
603623 extra_env = collect_luv_env () if env_mode else {}
604624
@@ -611,6 +631,7 @@ def main() -> None:
611631 -r resume: resume the last Claude session in the work folder
612632 -p launch Claude in plan permission mode (default: bypassPermissions)
613633 -nit non-interactive: run claude -p <prompt> and exit (no REPL)
634+ -m MODEL claude model to use (default: claude-opus-4-7)
614635 -e env: pass LUV_* environment variables (with prefix stripped) into the session
615636 -f, --force (with --clean) skip safety checks and delete all work folders
616637 --safe (with --clean -f) only delete folders older than 24h
@@ -656,7 +677,7 @@ def main() -> None:
656677 die (f"cannot parse PR URL: { url } " )
657678 org , repo , number = m .group (1 ), m .group (2 ), int (m .group (3 ))
658679 prompt = " " .join (args [2 :]) or None
659- open_pr (org , repo , number , prompt , nav_mode , resume_mode , plan_mode , non_interactive , extra_env = extra_env )
680+ open_pr (org , repo , number , prompt , nav_mode , resume_mode , plan_mode , non_interactive , extra_env = extra_env , model = model )
660681 return
661682
662683 raw = args [0 ].rstrip ("/" )
@@ -676,14 +697,14 @@ def main() -> None:
676697 die (f"expected a PR number after -pr, got '{ args [idx + 1 ]} '" )
677698 prompt_parts = [a for i , a in enumerate (args ) if i not in (0 , idx , idx + 1 )]
678699 prompt = " " .join (prompt_parts ) or None
679- open_pr (resolve_org (explicit_org ), repo , number , prompt , nav_mode , resume_mode , plan_mode , non_interactive , extra_env = extra_env )
700+ open_pr (resolve_org (explicit_org ), repo , number , prompt , nav_mode , resume_mode , plan_mode , non_interactive , extra_env = extra_env , model = model )
680701 return
681702
682703 # Detect optional numeric second argument
683704 if len (args ) > 1 and args [1 ].isdigit ():
684705 number = int (args [1 ])
685706 prompt = " " .join (args [2 :]) or None
686- open_existing (resolve_org (explicit_org ), repo , number , prompt , nav_mode , resume_mode , plan_mode , non_interactive , extra_env = extra_env )
707+ open_existing (resolve_org (explicit_org ), repo , number , prompt , nav_mode , resume_mode , plan_mode , non_interactive , extra_env = extra_env , model = model )
687708 return
688709
689710 org = resolve_org (explicit_org )
@@ -698,7 +719,7 @@ def main() -> None:
698719 if nav_mode :
699720 navigate (clone_dir , extra_env = extra_env )
700721 else :
701- resume (clone_dir , extra_env = extra_env )
722+ resume (clone_dir , extra_env = extra_env , model = model )
702723 return
703724
704725 # 1. Verify repo exists
@@ -750,6 +771,6 @@ def _latest(endpoint: str) -> int:
750771 if nav_mode :
751772 navigate (clone_dir , extra_env = extra_env )
752773 elif resume_mode :
753- resume (clone_dir , extra_env = extra_env )
774+ resume (clone_dir , extra_env = extra_env , model = model )
754775 else :
755- launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env )
776+ launch (clone_dir , prompt , plan_mode = plan_mode , non_interactive = non_interactive , extra_env = extra_env , model = model )
0 commit comments