@@ -945,7 +945,19 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
945945 }
946946 return zip_path , metadata
947947
948- def download_and_extract_template (project_path : Path , ai_assistant : str , script_type : str , is_current_dir : bool = False , * , verbose : bool = True , tracker : StepTracker | None = None , client : httpx .Client = None , debug : bool = False , github_token : str = None ) -> Path :
948+ def download_and_extract_template (
949+ project_path : Path ,
950+ ai_assistant : str ,
951+ script_type : str ,
952+ is_current_dir : bool = False ,
953+ * ,
954+ skip_legacy_codex_prompts : bool = False ,
955+ verbose : bool = True ,
956+ tracker : StepTracker | None = None ,
957+ client : httpx .Client = None ,
958+ debug : bool = False ,
959+ github_token : str = None ,
960+ ) -> Path :
949961 """Download the latest release and extract it to create a new project.
950962 Returns project_path. Uses tracker if provided (with keys: fetch, download, extract, cleanup)
951963 """
@@ -1016,6 +1028,10 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
10161028 console .print ("[cyan]Found nested directory structure[/cyan]" )
10171029
10181030 for item in source_dir .iterdir ():
1031+ # Codex skills mode should not materialize legacy prompt files
1032+ # from older template archives.
1033+ if skip_legacy_codex_prompts and ai_assistant == "codex" and item .name == ".codex" :
1034+ continue
10191035 dest_path = project_path / item .name
10201036 if item .is_dir ():
10211037 if dest_path .exists ():
@@ -1066,6 +1082,11 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
10661082 elif verbose :
10671083 console .print ("[cyan]Flattened nested directory structure[/cyan]" )
10681084
1085+ if skip_legacy_codex_prompts and ai_assistant == "codex" :
1086+ legacy_codex_dir = project_path / ".codex"
1087+ if legacy_codex_dir .is_dir ():
1088+ shutil .rmtree (legacy_codex_dir , ignore_errors = True )
1089+
10691090 except Exception as e :
10701091 if tracker :
10711092 tracker .error ("extract" , str (e ))
@@ -1712,8 +1733,18 @@ def init(
17121733 local_ssl_context = ssl_context if verify else False
17131734 local_client = httpx .Client (verify = local_ssl_context )
17141735
1715- download_and_extract_template (project_path , selected_ai , selected_script , here , verbose = False , tracker = tracker , client = local_client , debug = debug , github_token = github_token )
1716-
1736+ download_and_extract_template (
1737+ project_path ,
1738+ selected_ai ,
1739+ selected_script ,
1740+ here ,
1741+ skip_legacy_codex_prompts = (selected_ai == "codex" and ai_skills ),
1742+ verbose = False ,
1743+ tracker = tracker ,
1744+ client = local_client ,
1745+ debug = debug ,
1746+ github_token = github_token ,
1747+ )
17171748 # For generic agent, rename placeholder directory to user-specified path
17181749 if selected_ai == "generic" and ai_commands_dir :
17191750 placeholder_dir = project_path / ".speckit" / "commands"
@@ -1733,16 +1764,25 @@ def init(
17331764 if ai_skills :
17341765 if selected_ai in NATIVE_SKILLS_AGENTS :
17351766 skills_dir = _get_skills_dir (project_path , selected_ai )
1736- if not _has_bundled_skills (project_path , selected_ai ):
1737- raise RuntimeError (
1738- f"Expected bundled agent skills in { skills_dir .relative_to (project_path )} , "
1739- "but none were found. Re-run with an up-to-date template."
1740- )
1741- if tracker :
1742- tracker .start ("ai-skills" )
1743- tracker .complete ("ai-skills" , f"bundled skills → { skills_dir .relative_to (project_path )} " )
1767+ bundled_found = _has_bundled_skills (project_path , selected_ai )
1768+ if bundled_found :
1769+ if tracker :
1770+ tracker .start ("ai-skills" )
1771+ tracker .complete ("ai-skills" , f"bundled skills → { skills_dir .relative_to (project_path )} " )
1772+ else :
1773+ console .print (f"[green]✓[/green] Using bundled agent skills in { skills_dir .relative_to (project_path )} /" )
17441774 else :
1745- console .print (f"[green]✓[/green] Using bundled agent skills in { skills_dir .relative_to (project_path )} /" )
1775+ # Compatibility fallback: convert command templates to skills
1776+ # when an older template archive does not include native skills.
1777+ # This keeps `specify init --here --ai codex --ai-skills` usable
1778+ # in repos that already contain unrelated skills under .agents/skills.
1779+ fallback_ok = install_ai_skills (project_path , selected_ai , tracker = tracker )
1780+ if not fallback_ok :
1781+ raise RuntimeError (
1782+ f"Expected bundled agent skills in { skills_dir .relative_to (project_path )} , "
1783+ "but none were found and fallback conversion failed. "
1784+ "Re-run with an up-to-date template."
1785+ )
17461786 else :
17471787 skills_ok = install_ai_skills (project_path , selected_ai , tracker = tracker )
17481788
0 commit comments