diff --git a/docs/installation.md b/docs/installation.md index fa777a6978..b68a65d241 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -147,14 +147,15 @@ After initialization, you should see the following commands available in your co - `/speckit.checklist` - Generate quality checklists - `/speckit.constitution` - Create or update project principles - `/speckit.converge` - Assess codebase against artifacts and append remaining tasks -- `/speckit.taskstoissues` - Convert tasks to issues (moving to the bundled `github` extension as +- `/speckit.taskstoissues` - Convert tasks to issues (deprecated; warns on invocation; replaced by the bundled `github` extension's `/speckit.github.taskstoissues`; install it with `specify extension add github`) The `generic` integration also registers extension commands in its configured `--commands-dir`. Installing `github` makes `/speckit.github.taskstoissues` available there as a command file, or as `/speckit-github-taskstoissues` when `--skills` is enabled. The core `/speckit.taskstoissues` (or -`/speckit-taskstoissues` with `--skills`) remains available. +`/speckit-taskstoissues` with `--skills`) remains available during migration, warns on invocation, +and will be removed in a future minor release. See the [GitHub extension's installation notes](https://github.com/github/spec-kit/blob/main/extensions/github/README.md#installation). Scripts are installed into a variant subdirectory matching the chosen script type: diff --git a/docs/reference/agentic-sdd.md b/docs/reference/agentic-sdd.md index 984c782c28..ea60858f30 100644 --- a/docs/reference/agentic-sdd.md +++ b/docs/reference/agentic-sdd.md @@ -30,7 +30,7 @@ skills by default. | `/speckit.tasks` | `speckit-tasks` | Break the plan into actionable tasks | | `/speckit.implement` | `speckit-implement` | Execute the tasks | | `/speckit.converge` | `speckit-converge` | Assess implementation against the artifacts and append remaining work | -| `/speckit.taskstoissues` | `speckit-taskstoissues` | Optionally convert tasks into GitHub issues | +| `/speckit.taskstoissues` | `speckit-taskstoissues` | **Deprecated core command**; use the `github` extension for GitHub issues | | `/speckit.clarify` | `speckit-clarify` | Resolve ambiguity before planning (optional quality gate; formerly `/quizme`) | | `/speckit.analyze` | `speckit-analyze` | Check artifact consistency after tasks and before implementation (optional quality gate) | | `/speckit.checklist` | `speckit-checklist` | Generate requirements-quality checklists (optional quality gate) | @@ -158,13 +158,24 @@ It first prints a severity-graded findings summary, then resolves to one of two - **Converged** — no gaps found. `tasks.md` is left byte-for-byte unchanged and you'll see a clean result like `✅ Converged — the implementation satisfies the spec, plan, and tasks.` You're done; proceed to review or open a PR. - **Tasks appended** — gaps found. Converge appends them as new tasks under a Convergence section in `tasks.md` and tells you how many. Run `/speckit.implement` again to complete them, then `/speckit.converge` once more. Each pass finds fewer items; repeat until it reports converged. -## `/speckit.taskstoissues` +## `/speckit.taskstoissues` (deprecated core command) -Optionally converts an existing `tasks.md` into actionable GitHub issues. Run it -after generating tasks when you want to track execution in GitHub: +The core command is deprecated and will be removed in a future minor release. +It warns when invoked, then continues its existing workflow without installing +or enabling the extension automatically. + +The recommended extension command optionally converts an existing `tasks.md` +into actionable GitHub issues. Install the extension from your project root: + +```bash +specify extension add github +``` + +Then invoke it in your agent after generating tasks when you want to track +execution in GitHub: ```text -/speckit.taskstoissues +/speckit.github.taskstoissues ``` This command requires a GitHub `origin` remote and access to the GitHub MCP tools @@ -173,4 +184,4 @@ identified by that remote and checks existing task IDs to avoid duplicates. It is not required to implement tasks or converge on a feature. > [!NOTE] -> GitHub issue tracking is moving out of core into the bundled, opt-in [`github` extension](https://github.com/github/spec-kit/blob/main/extensions/github/README.md). `/speckit.taskstoissues` still works and is unchanged. Install its namespaced replacement with `specify extension add github`; the `generic` integration registers it under its configured command directory in commands or skills mode. See the [installation and migration notes](https://github.com/github/spec-kit/blob/main/extensions/github/README.md#installation). +> GitHub issue tracking uses the bundled, opt-in [`github` extension](https://github.com/github/spec-kit/blob/main/extensions/github/README.md). Its recommended command is `/speckit.github.taskstoissues` (slash-hyphen integrations: `/speckit-github-taskstoissues`; Codex, ZCode, and Command Code skills: `$speckit-github-taskstoissues`; Kimi: `/skill:speckit-github-taskstoissues`); the deprecated core `/speckit.taskstoissues` remains available during migration. The `generic` integration registers the extension under its configured command directory in commands or skills mode. See the [installation and migration notes](https://github.com/github/spec-kit/blob/main/extensions/github/README.md#installation) for all integration-specific invocation syntaxes. diff --git a/docs/reference/extensions.md b/docs/reference/extensions.md index cca791833c..e39ff9d697 100644 --- a/docs/reference/extensions.md +++ b/docs/reference/extensions.md @@ -30,7 +30,7 @@ specify extension add | `--force` | Overwrite if the extension is already installed | | `--priority `| Resolution priority (default: 10; lower = higher precedence) | -Installs an extension from the catalog, a URL, or a local directory. Extension commands are registered with the active AI coding agent integration. For `generic`, invocations use the configured `--commands-dir`: flat command files by default, or `speckit-/SKILL.md` with `--skills`. The core `speckit.taskstoissues` command remains available alongside the GitHub extension's namespaced replacement during migration. +Installs an extension from the catalog, a URL, or a local directory. Extension commands are registered with the active AI coding agent integration. For `generic`, invocations use the configured `--commands-dir`: flat command files by default, or `speckit-/SKILL.md` with `--skills`. The deprecated core `speckit.taskstoissues` command remains available during migration and will be removed in a future minor release. It warns on invocation and continues its existing workflow without installing or enabling the extension automatically. For GitHub issue tracking, run `specify extension add github` and use the recommended `/speckit.github.taskstoissues` command (slash-hyphen integrations: `/speckit-github-taskstoissues`; Codex, ZCode, and Command Code skills: `$speckit-github-taskstoissues`; Kimi: `/skill:speckit-github-taskstoissues`). If a generic integration refresh cannot produce every extension invocation (for example, because a command or skill is user-modified or its source is missing), it warns and restores that extension's prior registered artifacts. Other extensions can still refresh. diff --git a/docs/reference/integrations.md b/docs/reference/integrations.md index 4bbbb4704e..1e816d49ff 100644 --- a/docs/reference/integrations.md +++ b/docs/reference/integrations.md @@ -336,9 +336,14 @@ Once `generic` is the active integration, `specify extension add` registers extension commands in its configured `--commands-dir` (as command files or skills according to `--skills`). `specify extension remove` removes unchanged extension-owned artifacts while leaving core commands, user files, and edited -extension files intact. The core `speckit.taskstoissues` command remains -available; installing the GitHub extension adds the namespaced replacement -without deprecating or removing the core command. +extension files intact. The deprecated core `speckit.taskstoissues` command +remains available, warns on invocation, and will be removed in a future minor +release. To migrate, run `specify extension add github` and use the recommended +`/speckit.github.taskstoissues` command for dot-command integrations. Slash-hyphen +integrations use `/speckit-github-taskstoissues`; Codex, ZCode, and Command Code +skills use `$speckit-github-taskstoissues`; Kimi uses +`/skill:speckit-github-taskstoissues`. The core command continues its existing +workflow and does not install or enable the extension automatically. ## Scaffold a New Integration diff --git a/extensions/catalog.json b/extensions/catalog.json index 91c0140dba..bc3b6cb021 100644 --- a/extensions/catalog.json +++ b/extensions/catalog.json @@ -66,7 +66,7 @@ "github": { "name": "GitHub Integration", "id": "github", - "version": "1.0.1", + "version": "1.0.2", "description": "GitHub platform integration for Spec Kit - create GitHub issues from a feature's task list", "author": "spec-kit-core", "repository": "https://github.com/github/spec-kit", diff --git a/extensions/github/README.md b/extensions/github/README.md index ade406599b..8aaf46a5c3 100644 --- a/extensions/github/README.md +++ b/extensions/github/README.md @@ -24,7 +24,8 @@ The `generic` (bring your own agent) integration registers this command under its configured `--commands-dir` in both commands and skills layouts. Installing `github` creates `speckit.github.taskstoissues.md` in commands mode or `speckit-github-taskstoissues/SKILL.md` in skills mode. The core -`speckit.taskstoissues` command remains available and unchanged. See +`speckit.taskstoissues` command is deprecated but remains available during migration. +Use this extension's recommended command instead. See [integration-specific options](../../docs/reference/integrations.md#integration-specific-options). ## Removal @@ -37,9 +38,9 @@ specify extension remove github | Command | Description | | ------------------------------ | -------------------------------------------------------------------- | -| `speckit.github.taskstoissues` | Convert tasks from `tasks.md` into dependency-ordered GitHub issues. | +| `speckit.github.taskstoissues` | Recommended: convert tasks from `tasks.md` into dependency-ordered GitHub issues. | -> NOTE: The command ID above is canonical. Invoke it using the syntax for your integration: `/speckit.github.taskstoissues` for dot-command integrations; `/speckit-github-taskstoissues` for hyphen/skills integrations (including Forge and Cline); `$speckit-github-taskstoissues` for Codex, ZCode, or Command Code in skills mode; or `/skill:speckit-github-taskstoissues` for Kimi. +> NOTE: The command ID above is canonical. Invoke it using the syntax for your integration: `/speckit.github.taskstoissues` for dot-command integrations; `/speckit-github-taskstoissues` for slash-hyphen integrations (including Forge and Cline); `$speckit-github-taskstoissues` for Codex, ZCode, or Command Code in skills mode; or `/skill:speckit-github-taskstoissues` for Kimi. ### What the command does @@ -81,9 +82,21 @@ Prerequisite errors name the Spec Kit command without assuming an integration's Spec Kit is moving GitHub issue tracking out of core in three stages: -1. **Now** — this extension is available, and the core `/speckit.taskstoissues` command remains available and unchanged. Nothing breaks if you do nothing. -2. **Next** — the core command is deprecated once the replacement has been available for a release. -3. **Later** — the core command is removed in a minor release. +1. **Initial stage (completed)** — this extension shipped with the core `/speckit.taskstoissues` command still available. +2. **Next (current stage)** — the replacement has been available for at least one release, so the core command is now deprecated. It displays a migration warning and continues its existing workflow. It does not install or enable the extension automatically or run the replacement command. +3. **Later** — the core command will be removed in a future minor release. + +For existing projects, upgrading the CLI alone does not refresh the generated +core command files. After upgrading the CLI, run this from the project root: + +```bash +specify integration upgrade +``` + +Replace `` with the installed integration key, or omit it to upgrade the +default integration. This refreshes the core command with the deprecation +warning. If locally modified files block the upgrade, inspect those changes +before deciding whether to overwrite them. See [Upgrade an Integration](../../docs/reference/integrations.md#upgrade-an-integration). To migrate, install the extension and use the namespaced command instead: @@ -93,10 +106,42 @@ specify extension add github The `generic` integration supports this migration in both commands and skills layouts under its configured `--commands-dir`. The core command remains -available until a separate deprecation and removal decision. +available during this deprecation period until the removal stage. -| Before | After | +| Deprecated core command | Recommended extension command | | ------------------------- | --------------------------------- | | `/speckit.taskstoissues` | `/speckit.github.taskstoissues` | -Behavior is unchanged: the same feature resolution, the same `plan.md` and `tasks.md` prerequisites, the same remote validation, the same deduplication across open and closed issues, the same issue titles, and the same hook contract. This extension does **not** register `speckit.taskstoissues` as an alias, so the two commands coexist without shadowing each other while the core command still exists. +Apart from the core command's deprecation warning, conversion behavior is unchanged: the same feature resolution, the same `plan.md` and `tasks.md` prerequisites, the same remote validation, the same deduplication across open and closed issues, the same issue titles, and the same hook contract. This extension does **not** register `speckit.taskstoissues` as an alias, so the two commands coexist without shadowing each other while the core command still exists. + +### Presets and dependent extensions + +Before the core command is removed, audit references to `speckit.taskstoissues` +in presets, extension prompts, workflow steps, handoffs, and project automation. +For GitHub issue conversion, use the canonical `speckit.github.taskstoissues` +command ID and render it with the agent-specific syntax under [Commands](#commands). +Replace `__SPECKIT_COMMAND_TASKSTOISSUES__` cross-command references with +`__SPECKIT_COMMAND_GITHUB_TASKSTOISSUES__` where template rendering is supported. +Document `specify extension add github` as a setup prerequisite; the deprecation +warning does not install this dependency. + +If an extension proposal or external dependency declaration uses +`requires.commands: [speckit.taskstoissues]`, update its target to +`speckit.github.taskstoissues`. `requires.commands` is not an enforced dependency +field in the current extension manifest API, so do not rely on that declaration +to install or check the GitHub extension. Follow the supported requirements in +the [extension API reference](../EXTENSION-API-REFERENCE.md#extension-manifest). + +Preset command overrides are separate from command references: an override of +`speckit.taskstoissues` does not automatically customize the namespaced GitHub +command. Review and port any needed customization, then verify the installed +command in a sample project before retiring the old override. A preset that +uses another issue tracker should retain its own provider-specific workflow +rather than redirecting it to the GitHub command. Existing overrides may also +hide the core deprecation warning, so communicate the migration to their users. + +Keep the `before_taskstoissues` and `after_taskstoissues` hook keys unchanged; +both commands consume them. Only update a hook's command reference if it invokes +the deprecated command. Do not invoke both core and replacement commands for +the same conversion, since that also runs their hooks twice. Publish and test +updated preset/extension versions before the later core-removal release. diff --git a/extensions/github/extension.yml b/extensions/github/extension.yml index 2e13c434ba..c6df8f19a1 100644 --- a/extensions/github/extension.yml +++ b/extensions/github/extension.yml @@ -3,7 +3,7 @@ schema_version: "1.0" extension: id: github name: "GitHub Integration" - version: "1.0.1" + version: "1.0.2" description: "GitHub platform integration for Spec Kit - create GitHub issues from a feature's task list" author: spec-kit-core repository: https://github.com/github/spec-kit diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 68ea5e4985..de09603b4f 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -380,7 +380,7 @@ def _print_cli_warning( "clarify": "Structured clarification workflow for underspecified requirements.", "constitution": "Create or update project governing principles and development guidelines.", "checklist": "Generate custom quality checklists for validating requirements completeness and clarity.", - "taskstoissues": "Convert tasks from tasks.md into GitHub issues.", + "taskstoissues": "Deprecated: Convert tasks from tasks.md into GitHub issues.", } diff --git a/templates/commands/taskstoissues.md b/templates/commands/taskstoissues.md index f982448906..dea7e7cfe5 100644 --- a/templates/commands/taskstoissues.md +++ b/templates/commands/taskstoissues.md @@ -1,5 +1,5 @@ --- -description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts. +description: "Deprecated: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts." tools: ['github/github-mcp-server/list_issues', 'github/github-mcp-server/issue_write'] scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks @@ -7,6 +7,14 @@ scripts: py: scripts/python/check_prerequisites.py --json --require-tasks --include-tasks --- +## Deprecation Notice + +You **MUST display the following concise warning first**, as the first step of this command and before the User Input and Pre-Execution Checks sections below: + +> ⚠️ `__SPECKIT_COMMAND_TASKSTOISSUES__` is deprecated and will be removed in a future minor release. Use the bundled `github` extension instead: run `specify extension add github`, then invoke `__SPECKIT_COMMAND_GITHUB_TASKSTOISSUES__`. + +Continue with the existing workflow unchanged. Do not install or enable the extension automatically, do not stop, and do not run the replacement command. + ## User Input ```text diff --git a/tests/extensions/github/test_github_extension.py b/tests/extensions/github/test_github_extension.py index 498abaf36d..718c1c8421 100644 --- a/tests/extensions/github/test_github_extension.py +++ b/tests/extensions/github/test_github_extension.py @@ -158,7 +158,7 @@ def test_manifest_validates(self): m = ExtensionManifest(EXT_DIR / "extension.yml") assert m.id == "github" - assert m.version == "1.0.1" + assert m.version == "1.0.2" assert [c["name"] for c in m.commands] == [COMMAND_NAME] def test_manifest_command_files_exist(self): @@ -598,17 +598,24 @@ def test_preserves_deduplication_and_pagination(self): # Four-digit and longer task IDs must still match. assert r"\bT\d{3,}\b" in body - def test_body_differs_from_core_only_in_the_script_invocation(self): + def test_body_differs_from_core_only_in_deprecation_and_script_invocation(self): """Behaviour parity, enforced as a diff rather than as spot checks. - Everything except the ``scripts:`` frontmatter and the two lines that - read the new ``TASKS`` value must match the core command verbatim, so - the two cannot silently drift while both exist. + Apart from core-only deprecation metadata and notice, everything except + the ``scripts:`` frontmatter and the two lines that read the new ``TASKS`` + value must match verbatim, so the two cannot silently drift while both exist. """ import difflib - core = CORE_COMMAND.read_text(encoding="utf-8").splitlines() + core_text = CORE_COMMAND.read_text(encoding="utf-8") + before_notice, notice_and_workflow = core_text.split("## Deprecation Notice\n", 1) + _, workflow = notice_and_workflow.split("## User Input", 1) + core = (before_notice + "## User Input" + workflow).splitlines() ext = COMMAND_FILE.read_text(encoding="utf-8").splitlines() + core_description = yaml.safe_load(core[1])["description"] + ext_description = yaml.safe_load(ext[1])["description"] + assert core_description == "Deprecated: " + ext_description + core[1] = ext[1] changed = [ line for line in difflib.unified_diff(core, ext, n=0) diff --git a/tests/extensions/github/test_taskstoissues_deprecation.py b/tests/extensions/github/test_taskstoissues_deprecation.py new file mode 100644 index 0000000000..b18324863b --- /dev/null +++ b/tests/extensions/github/test_taskstoissues_deprecation.py @@ -0,0 +1,99 @@ +"""Text contracts for the core command's deprecation transition.""" + +from pathlib import Path + +import pytest +import yaml + + +ROOT = Path(__file__).resolve().parents[3] +CORE = ROOT / "templates/commands/taskstoissues.md" +EXTENSION = ROOT / "extensions/github/commands/speckit.github.taskstoissues.md" + + +def test_core_deprecation_warning_and_continuation(): + text = CORE.read_text(encoding="utf-8") + assert "## Deprecation Notice" in text + assert "## Pre-Execution Checks" in text + notice = text.split("## Deprecation Notice\n", 1)[1].split("## User Input", 1)[0] + assert text.index("## Deprecation Notice") < text.index("## User Input") < text.index("## Pre-Execution Checks") + for phrase in ( + "MUST display the following concise warning first", + "`__SPECKIT_COMMAND_TASKSTOISSUES__` is deprecated", + "will be removed in a future minor release", + "bundled `github` extension", + "specify extension add github", + "__SPECKIT_COMMAND_GITHUB_TASKSTOISSUES__", + "Continue with the existing workflow unchanged", + "Do not install or enable the extension automatically", + "do not stop", + "do not run the replacement command", + ): + assert phrase in notice + + +def test_core_frontmatter_preserves_execution_metadata(): + metadata = yaml.safe_load(CORE.read_text(encoding="utf-8").split("---", 2)[1]) + assert metadata["description"].startswith("Deprecated: ") + assert metadata["tools"] == [ + "github/github-mcp-server/list_issues", + "github/github-mcp-server/issue_write", + ] + assert metadata["scripts"] == { + "sh": "scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks", + "ps": "scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks", + "py": "scripts/python/check_prerequisites.py --json --require-tasks --include-tasks", + } + + +def test_recommended_extension_is_not_deprecated(): + text = EXTENSION.read_text(encoding="utf-8") + assert "## Deprecation Notice" not in text + assert "future minor release" not in text + assert not yaml.safe_load(text.split("---", 2)[1])["description"].startswith("Deprecated:") + + +@pytest.mark.parametrize("command", [CORE, EXTENSION], ids=["core", "github"]) +def test_taskstoissues_hooks_and_safety_contracts_remain(command): + text = command.read_text(encoding="utf-8") + assert "hooks.before_taskstoissues" in text + assert "hooks.after_taskstoissues" in text + assert "ONLY PROCEED TO NEXT STEPS IF THE REMOTE IS A GITHUB URL" in text + assert "**Fetch existing issues for deduplication**" in text + assert "**Skip** any task whose ID is already present" in text + assert "Only create issues for tasks that do not yet have a matching issue." in text + assert "UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL" in text + + +@pytest.mark.parametrize( + ("integration_key", "core_invocation", "replacement_invocation"), + [ + ("opencode", "/speckit.taskstoissues", "/speckit.github.taskstoissues"), + ("agy", "/speckit-taskstoissues", "/speckit-github-taskstoissues"), + ], +) +def test_rendered_core_warning_uses_integration_invocations( + tmp_path, integration_key, core_invocation, replacement_invocation +): + from specify_cli.integrations import get_integration + from specify_cli.integrations.manifest import IntegrationManifest + + integration = get_integration(integration_key) + created = integration.setup( + tmp_path, IntegrationManifest(integration_key, tmp_path), script_type="sh" + ) + command = next( + path for path in created + if path.name == "speckit.taskstoissues.md" + or path.parent.name == "speckit-taskstoissues" + ) + text = command.read_text(encoding="utf-8") + assert "## Deprecation Notice" in text + assert "## Pre-Execution Checks" in text + notice = text.split("## Deprecation Notice", 1)[1].split("## User Input", 1)[0] + assert f"`{core_invocation}` is deprecated" in notice + assert f"invoke `{replacement_invocation}`" in notice + assert "__SPECKIT_COMMAND_" not in notice + assert "specify extension add github" in notice + assert "Continue with the existing workflow unchanged" in notice + assert "Do not install or enable the extension automatically" in notice