Skip to content

Commit 21490c5

Browse files
authored
feat!: remove legacy --ai, --ai-commands-dir, and --ai-skills flags at 0.10.0
1 parent 62db68d commit 21490c5

21 files changed

Lines changed: 150 additions & 288 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
<!-- insert new changelog below this comment -->
44

5+
## [0.10.0] - Unreleased
6+
7+
### Breaking Changes
8+
9+
- **Removed legacy `--ai`, `--ai-commands-dir`, and `--ai-skills` flags from `specify init`.**
10+
Use `--integration <name>`, `--integration-options="--commands-dir <dir>"`, and
11+
`--integration-options="--skills"` respectively.
12+
513
## [0.9.4] - 2026-06-04
614

715
### Changed

src/specify_cli/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@
8282
)
8383
from ._agent_config import (
8484
AGENT_CONFIG as AGENT_CONFIG,
85-
AI_ASSISTANT_ALIASES as AI_ASSISTANT_ALIASES,
86-
AI_ASSISTANT_HELP as AI_ASSISTANT_HELP,
8785
DEFAULT_INIT_INTEGRATION as DEFAULT_INIT_INTEGRATION,
8886
SCRIPT_TYPE_CHOICES as SCRIPT_TYPE_CHOICES,
8987
)

src/specify_cli/commands/init.py

Lines changed: 16 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from __future__ import annotations
33

44
import os
5-
import shlex
65
import shutil
76
import sys
87
from pathlib import Path
@@ -14,8 +13,6 @@
1413

1514
from .._agent_config import (
1615
AGENT_CONFIG,
17-
AI_ASSISTANT_ALIASES,
18-
AI_ASSISTANT_HELP,
1916
DEFAULT_INIT_INTEGRATION,
2017
SCRIPT_TYPE_CHOICES,
2118
)
@@ -28,31 +25,6 @@
2825
from .._console import StepTracker, console, select_with_arrows, show_banner
2926
from .._utils import check_tool, init_git_repo, is_git_repo
3027

31-
def _build_integration_equivalent(
32-
integration_key: str,
33-
ai_commands_dir: str | None = None,
34-
) -> str:
35-
parts = [f"--integration {integration_key}"]
36-
if integration_key == "generic" and ai_commands_dir:
37-
parts.append(
38-
f'--integration-options="--commands-dir {shlex.quote(ai_commands_dir)}"'
39-
)
40-
return " ".join(parts)
41-
42-
43-
def _build_ai_deprecation_warning(
44-
integration_key: str,
45-
ai_commands_dir: str | None = None,
46-
) -> str:
47-
replacement = _build_integration_equivalent(
48-
integration_key,
49-
ai_commands_dir=ai_commands_dir,
50-
)
51-
return (
52-
"[bold]--ai[/bold] is deprecated and will no longer be available in version 0.10.0 or later.\n\n"
53-
f"Use [bold]{replacement}[/bold] instead."
54-
)
55-
5628

5729
def _stdin_is_interactive() -> bool:
5830
return sys.stdin.isatty()
@@ -97,8 +69,6 @@ def register(app: typer.Typer) -> None:
9769
@app.command()
9870
def init(
9971
project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"),
100-
ai_assistant: str = typer.Option(None, "--ai", help=AI_ASSISTANT_HELP),
101-
ai_commands_dir: str = typer.Option(None, "--ai-commands-dir", help="Directory for agent command files (required with --ai generic, e.g. .myagent/commands/)"),
10272
script_type: str = typer.Option(None, "--script", help="Script type to use: sh or ps"),
10373
ignore_agent_tools: bool = typer.Option(False, "--ignore-agent-tools", help="Skip checks for coding agent tools like Claude Code"),
10474
no_git: bool = typer.Option(False, "--no-git", help="Skip git repository initialization"),
@@ -107,11 +77,10 @@ def init(
10777
skip_tls: bool = typer.Option(False, "--skip-tls", help="Deprecated (no-op). Previously: skip SSL/TLS verification.", hidden=True),
10878
debug: bool = typer.Option(False, "--debug", help="Deprecated. Previously: show verbose diagnostic output; currently only prints additional diagnostic details on failure.", hidden=True),
10979
github_token: str = typer.Option(None, "--github-token", help="Deprecated (no-op). Previously: GitHub token for API requests.", hidden=True),
110-
ai_skills: bool = typer.Option(False, "--ai-skills", help="Install Prompt.MD templates as agent skills (requires --ai)"),
11180
offline: bool = typer.Option(False, "--offline", help="Deprecated (no-op). All scaffolding now uses bundled assets.", hidden=True),
11281
preset: str = typer.Option(None, "--preset", help="Install a preset during initialization (by preset ID)"),
11382
branch_numbering: str = typer.Option(None, "--branch-numbering", help="Branch numbering strategy: 'sequential' (001, 002, …, 1000, … — expands past 999 automatically) or 'timestamp' (YYYYMMDD-HHMMSS)"),
114-
integration: str = typer.Option(None, "--integration", help="Use the new integration system (e.g. --integration copilot). Mutually exclusive with --ai."),
83+
integration: str = typer.Option(None, "--integration", help="AI coding agent integration to use (e.g. --integration copilot). See 'specify check' for available integrations."),
11584
integration_options: str = typer.Option(None, "--integration-options", help='Options for the integration (e.g. --integration-options="--commands-dir .myagent/cmds")'),
11685
):
11786
"""
@@ -163,27 +132,6 @@ def init(
163132
from ..integration_runtime import with_integration_setting as _with_integration_setting
164133

165134
show_banner()
166-
ai_deprecation_warning: str | None = None
167-
168-
if ai_assistant and ai_assistant.startswith("--"):
169-
console.print(f"[red]Error:[/red] Invalid value for --ai: '{ai_assistant}'")
170-
console.print("[yellow]Hint:[/yellow] Did you forget to provide a value for --ai?")
171-
console.print("[yellow]Example:[/yellow] specify init --integration claude --here")
172-
console.print(f"[yellow]Available agents:[/yellow] {', '.join(AGENT_CONFIG.keys())}")
173-
raise typer.Exit(1)
174-
175-
if ai_commands_dir and ai_commands_dir.startswith("--"):
176-
console.print(f"[red]Error:[/red] Invalid value for --ai-commands-dir: '{ai_commands_dir}'")
177-
console.print("[yellow]Hint:[/yellow] Did you forget to provide a value for --ai-commands-dir?")
178-
console.print("[yellow]Example:[/yellow] specify init --integration generic --integration-options=\"--commands-dir .myagent/commands/\"")
179-
raise typer.Exit(1)
180-
181-
if ai_assistant:
182-
ai_assistant = AI_ASSISTANT_ALIASES.get(ai_assistant, ai_assistant)
183-
184-
if integration and ai_assistant:
185-
console.print("[red]Error:[/red] --integration and --ai are mutually exclusive")
186-
raise typer.Exit(1)
187135

188136
from ..integrations import INTEGRATION_REGISTRY, get_integration
189137
if integration:
@@ -193,35 +141,6 @@ def init(
193141
available = ", ".join(sorted(INTEGRATION_REGISTRY))
194142
console.print(f"[yellow]Available integrations:[/yellow] {available}")
195143
raise typer.Exit(1)
196-
ai_assistant = integration
197-
elif ai_assistant:
198-
resolved_integration = get_integration(ai_assistant)
199-
if not resolved_integration:
200-
console.print(f"[red]Error:[/red] Unknown agent '{ai_assistant}'. Choose from: {', '.join(sorted(INTEGRATION_REGISTRY))}")
201-
raise typer.Exit(1)
202-
ai_deprecation_warning = _build_ai_deprecation_warning(
203-
resolved_integration.key,
204-
ai_commands_dir=ai_commands_dir,
205-
)
206-
207-
if ai_assistant or integration:
208-
if ai_skills:
209-
from ..integrations.base import SkillsIntegration as _SkillsCheck
210-
if isinstance(resolved_integration, _SkillsCheck):
211-
console.print(
212-
"[dim]Note: --ai-skills is not needed; "
213-
"skills are the default for this integration.[/dim]"
214-
)
215-
else:
216-
console.print(
217-
"[dim]Note: --ai-skills has no effect with "
218-
f"{resolved_integration.key}; this integration uses commands, not skills.[/dim]"
219-
)
220-
if ai_commands_dir and resolved_integration.key != "generic":
221-
console.print(
222-
"[dim]Note: --ai-commands-dir is deprecated; "
223-
'use [bold]--integration generic --integration-options="--commands-dir <dir>"[/bold] instead.[/dim]'
224-
)
225144

226145
if no_git:
227146
console.print(
@@ -242,11 +161,6 @@ def init(
242161
console.print("[red]Error:[/red] Must specify either a project name, use '.' for current directory, or use --here flag")
243162
raise typer.Exit(1)
244163

245-
if ai_skills and not ai_assistant:
246-
console.print("[red]Error:[/red] --ai-skills requires --ai to be specified")
247-
console.print("[yellow]Usage:[/yellow] specify init <project> --ai <agent> --ai-skills")
248-
raise typer.Exit(1)
249-
250164
BRANCH_NUMBERING_CHOICES = {"sequential", "timestamp"}
251165
if branch_numbering and branch_numbering not in BRANCH_NUMBERING_CHOICES:
252166
console.print(f"[red]Error:[/red] Invalid --branch-numbering value '{branch_numbering}'. Choose from: {', '.join(sorted(BRANCH_NUMBERING_CHOICES))}")
@@ -295,11 +209,11 @@ def init(
295209
console.print(error_panel)
296210
raise typer.Exit(1)
297211

298-
if ai_assistant:
299-
if ai_assistant not in AGENT_CONFIG:
300-
console.print(f"[red]Error:[/red] Invalid AI assistant '{ai_assistant}'. Choose from: {', '.join(AGENT_CONFIG.keys())}")
212+
if integration:
213+
if integration not in AGENT_CONFIG:
214+
console.print(f"[red]Error:[/red] Invalid integration '{integration}'. Choose from: {', '.join(AGENT_CONFIG.keys())}")
301215
raise typer.Exit(1)
302-
selected_ai = ai_assistant
216+
selected_ai = integration
303217
elif not _stdin_is_interactive():
304218
console.print(
305219
f"[dim]Non-interactive session detected: defaulting to '{DEFAULT_INIT_INTEGRATION}'. "
@@ -314,17 +228,16 @@ def init(
314228
DEFAULT_INIT_INTEGRATION,
315229
)
316230

317-
if not ai_assistant:
231+
if not integration:
318232
resolved_integration = get_integration(selected_ai)
319233
if not resolved_integration:
320234
console.print(f"[red]Error:[/red] Unknown agent '{selected_ai}'")
321235
raise typer.Exit(1)
322236

323237
if selected_ai == "generic" and not integration_options:
324-
if not ai_commands_dir:
325-
console.print("[red]Error:[/red] --ai-commands-dir is required when using --ai generic or --integration generic")
326-
console.print('[dim]Example: specify init my-project --integration generic --integration-options="--commands-dir .myagent/commands/"[/dim]')
327-
raise typer.Exit(1)
238+
console.print("[red]Error:[/red] --integration generic requires --integration-options with --commands-dir")
239+
console.print('[dim]Example: specify init my-project --integration generic --integration-options="--commands-dir .myagent/commands/"[/dim]')
240+
raise typer.Exit(1)
328241

329242
current_dir = Path.cwd()
330243

@@ -414,10 +327,6 @@ def init(
414327
)
415328

416329
integration_parsed_options: dict[str, Any] = {}
417-
if ai_commands_dir:
418-
integration_parsed_options["commands_dir"] = ai_commands_dir
419-
if ai_skills:
420-
integration_parsed_options["skills"] = True
421330
if integration_options:
422331
extra = _parse_integration_options(resolved_integration, integration_options)
423332
if extra:
@@ -675,7 +584,7 @@ def init(
675584

676585
agent_config = AGENT_CONFIG.get(selected_ai)
677586
if agent_config:
678-
agent_folder = ai_commands_dir if selected_ai == "generic" else agent_config["folder"]
587+
agent_folder = agent_config["folder"]
679588
if agent_folder:
680589
security_notice = Panel(
681590
f"Some agents may store credentials, auth tokens, or other identifying and private artifacts in the agent folder within your project.\n"
@@ -687,16 +596,6 @@ def init(
687596
console.print()
688597
console.print(security_notice)
689598

690-
if ai_deprecation_warning:
691-
deprecation_notice = Panel(
692-
ai_deprecation_warning,
693-
title="[bold red]Deprecation Warning[/bold red]",
694-
border_style="red",
695-
padding=(1, 2),
696-
)
697-
console.print()
698-
console.print(deprecation_notice)
699-
700599
if git_default_notice:
701600
default_change_notice = Panel(
702601
"The git extension is currently enabled by default during [bold]specify init[/bold].\n"
@@ -720,24 +619,24 @@ def init(
720619
from ..integrations.base import SkillsIntegration as _SkillsInt
721620
_is_skills_integration = isinstance(resolved_integration, _SkillsInt) or getattr(resolved_integration, "_skills_mode", False)
722621

723-
codex_skill_mode = selected_ai == "codex" and (ai_skills or _is_skills_integration)
724-
claude_skill_mode = selected_ai == "claude" and (ai_skills or _is_skills_integration)
622+
codex_skill_mode = selected_ai == "codex" and _is_skills_integration
623+
claude_skill_mode = selected_ai == "claude" and _is_skills_integration
725624
kimi_skill_mode = selected_ai == "kimi"
726625
agy_skill_mode = selected_ai == "agy" and _is_skills_integration
727626
trae_skill_mode = selected_ai == "trae"
728-
cursor_agent_skill_mode = selected_ai == "cursor-agent" and (ai_skills or _is_skills_integration)
627+
cursor_agent_skill_mode = selected_ai == "cursor-agent" and _is_skills_integration
729628
copilot_skill_mode = selected_ai == "copilot" and _is_skills_integration
730629
devin_skill_mode = selected_ai == "devin"
731630
cline_skill_mode = selected_ai == "cline"
732631
native_skill_mode = codex_skill_mode or claude_skill_mode or kimi_skill_mode or agy_skill_mode or trae_skill_mode or cursor_agent_skill_mode or copilot_skill_mode or devin_skill_mode
733632

734-
if codex_skill_mode and not ai_skills:
633+
if codex_skill_mode:
735634
steps_lines.append(f"{step_num}. Start Codex in this project directory; spec-kit skills were installed to [cyan].agents/skills[/cyan]")
736635
step_num += 1
737-
if claude_skill_mode and not ai_skills:
636+
if claude_skill_mode:
738637
steps_lines.append(f"{step_num}. Start Claude in this project directory; spec-kit skills were installed to [cyan].claude/skills[/cyan]")
739638
step_num += 1
740-
if cursor_agent_skill_mode and not ai_skills:
639+
if cursor_agent_skill_mode:
741640
steps_lines.append(f"{step_num}. Start Cursor Agent in this project directory; spec-kit skills were installed to [cyan].cursor/skills[/cyan]")
742641
step_num += 1
743642
if devin_skill_mode:

0 commit comments

Comments
 (0)