From 8b9ba0722c4fa773a97146a46cbdb3fb3ffd5dc1 Mon Sep 17 00:00:00 2001 From: Manfred Riem <15701806+mnriem@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:46:40 -0600 Subject: [PATCH] Add generic agent support with customizable command directories - Add --ai generic option for unsupported AI agents (bring your own agent) - Require --ai-commands-dir to specify where agent reads commands from - Generate Markdown commands with $ARGUMENTS format (compatible with most agents) - Rebuild CHANGELOG from GitHub releases (last 10 releases) - Align version to 0.1.3 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 8 + .../scripts/create-github-release.sh | 2 + .../scripts/create-release-packages.ps1 | 8 +- .../scripts/create-release-packages.sh | 7 +- AGENTS.md | 1 + CHANGELOG.md | 315 ++---------------- README.md | 7 +- pyproject.toml | 2 +- scripts/bash/update-agent-context.sh | 5 +- scripts/powershell/update-agent-context.ps1 | 7 +- src/specify_cli/__init__.py | 55 ++- tests/test_ai_skills.py | 2 +- 12 files changed, 110 insertions(+), 309 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1890587c2f..30f28f3210 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,4 +58,12 @@ jobs: run: | chmod +x .github/workflows/scripts/update-version.sh .github/workflows/scripts/update-version.sh ${{ steps.get_tag.outputs.new_version }} + - name: Commit version bump to main + if: steps.check_release.outputs.exists == 'false' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add pyproject.toml + git diff --cached --quiet || git commit -m "chore: bump version to ${{ steps.get_tag.outputs.new_version }} [skip ci]" + git push diff --git a/.github/workflows/scripts/create-github-release.sh b/.github/workflows/scripts/create-github-release.sh index 56f1bac85d..a122daf8e0 100644 --- a/.github/workflows/scripts/create-github-release.sh +++ b/.github/workflows/scripts/create-github-release.sh @@ -52,5 +52,7 @@ gh release create "$VERSION" \ .genreleases/spec-kit-template-agy-ps-"$VERSION".zip \ .genreleases/spec-kit-template-bob-sh-"$VERSION".zip \ .genreleases/spec-kit-template-bob-ps-"$VERSION".zip \ + .genreleases/spec-kit-template-generic-sh-"$VERSION".zip \ + .genreleases/spec-kit-template-generic-ps-"$VERSION".zip \ --title "Spec Kit Templates - $VERSION_NO_V" \ --notes-file release_notes.md diff --git a/.github/workflows/scripts/create-release-packages.ps1 b/.github/workflows/scripts/create-release-packages.ps1 index a59df6e13f..5953ca91a2 100644 --- a/.github/workflows/scripts/create-release-packages.ps1 +++ b/.github/workflows/scripts/create-release-packages.ps1 @@ -14,7 +14,7 @@ .PARAMETER Agents Comma or space separated subset of agents to build (default: all) - Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, q, bob, qoder + Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, q, bob, qoder, generic .PARAMETER Scripts Comma or space separated subset of script types to build (default: both) @@ -347,6 +347,10 @@ function Build-Variant { $cmdDir = Join-Path $baseDir ".qoder/commands" Generate-Commands -Agent 'qoder' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script } + 'generic' { + $cmdDir = Join-Path $baseDir ".speckit/commands" + Generate-Commands -Agent 'generic' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } } # Create zip archive @@ -356,7 +360,7 @@ function Build-Variant { } # Define all agents and scripts -$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'q', 'bob', 'qoder') +$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'q', 'bob', 'qoder', 'generic') $AllScripts = @('sh', 'ps') function Normalize-List { diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index a825bd7bb9..1ea1482a8f 100755 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -6,7 +6,7 @@ set -euo pipefail # Usage: .github/workflows/scripts/create-release-packages.sh # Version argument should include leading 'v'. # Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built. -# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp shai bob (default: all) +# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp shai bob generic (default: all) # SCRIPTS : space or comma separated subset of: sh ps (default: both) # Examples: # AGENTS=claude SCRIPTS=sh $0 v0.2.0 @@ -221,13 +221,16 @@ build_variant() { bob) mkdir -p "$base_dir/.bob/commands" generate_commands bob md "\$ARGUMENTS" "$base_dir/.bob/commands" "$script" ;; + generic) + mkdir -p "$base_dir/.speckit/commands" + generate_commands generic md "\$ARGUMENTS" "$base_dir/.speckit/commands" "$script" ;; esac ( cd "$base_dir" && zip -r "../spec-kit-template-${agent}-${script}-${NEW_VERSION}.zip" . ) echo "Created $GENRELEASES_DIR/spec-kit-template-${agent}-${script}-${NEW_VERSION}.zip" } # Determine agent list -ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai q agy bob qoder) +ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai q agy bob qoder generic) ALL_SCRIPTS=(sh ps) norm_list() { diff --git a/AGENTS.md b/AGENTS.md index d7360487b8..15137bc92b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,6 +48,7 @@ Specify supports multiple AI agents by generating agent-specific command files a | **Amp** | `.agents/commands/` | Markdown | `amp` | Amp CLI | | **SHAI** | `.shai/commands/` | Markdown | `shai` | SHAI CLI | | **IBM Bob** | `.bob/commands/` | Markdown | N/A (IDE-based) | IBM Bob IDE | +| **Generic** | User-specified via `--ai-commands-dir` | Markdown | N/A | Bring your own agent | ### Step-by-Step Integration Guide diff --git a/CHANGELOG.md b/CHANGELOG.md index ab4198beb7..dd0d528e47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,318 +2,59 @@ - All notable changes to the Specify CLI and templates are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.1.2] - 2026-02-20 - -### Fixed - -- **Python 3.14 / Homebrew compatibility**: Added explicit `click>=8.1` dependency so the resolver always selects a Click version compatible with Python 3.14 and avoids errors such as `TypeError: ParamType.get_metavar() got an unexpected keyword argument 'ctx'` when an older Click would otherwise be used. Note that broader uv/Homebrew environment isolation or `sys.path` bleed issues (see [#1631](https://github.com/github/spec-kit/issues/1631)) may still require environment-level workarounds. - -## [0.1.1] - 2026-02-13 - -### Added - -- **Agent Skills Installation**: New `--ai-skills` CLI option to install Prompt.MD templates as agent skills following [agentskills.io specification](https://agentskills.io/specification) - - Skills are installed to agent-specific directories (e.g., `.claude/skills/`, `.gemini/skills/`, `.github/skills/`) - - Codex uses `.agents/skills/` following Codex agent directory conventions - - Default fallback directory is `.agents/skills/` for agents without a specific mapping - - Requires `--ai` flag to be specified - - Converts all 9 spec-kit command templates (specify, plan, tasks, implement, analyze, clarify, constitution, checklist, taskstoissues) to properly formatted SKILL.md files - - **New projects**: command files are not installed when `--ai-skills` is used (skills replace commands) - - **Existing repos** (`--here`): pre-existing command files are preserved — no breaking changes - - `pyyaml` dependency (already present) used for YAML frontmatter parsing -- **Unit tests** for `install_ai_skills`, `_get_skills_dir`, and `--ai-skills` CLI validation (51 test cases covering all 18 supported agents) - -## [0.1.0] - 2026-01-28 - -### Added - -- **Extension System**: Introduced modular extension architecture for Spec Kit - - Extensions are self-contained packages that add commands and functionality without bloating core - - Extension manifest schema (`extension.yml`) with validation - - Extension registry (`.specify/extensions/.registry`) for tracking installed extensions - - Extension manager module (`src/specify_cli/extensions.py`) for installation/removal - - New CLI commands: - - `specify extension list` - List installed extensions - - `specify extension add` - Install extension from local directory or URL - - `specify extension remove` - Uninstall extension - - `specify extension search` - Search extension catalog - - `specify extension info` - Show detailed extension information - - Semantic versioning compatibility checks - - Support for extension configuration files - - Command registration system for AI agents (Claude support initially) - - Added dependencies: `pyyaml>=6.0`, `packaging>=23.0` - -- **Extension Catalog**: Extension discovery and distribution system - - Central catalog (`extensions/catalog.json`) for published extensions - - Extension catalog manager (`ExtensionCatalog` class) with: - - Catalog fetching from GitHub - - 1-hour local caching for performance - - Search by query, tag, author, or verification status - - Extension info retrieval - - Catalog cache stored in `.specify/extensions/.cache/` - - Search and info commands with rich console output - - Added 9 catalog-specific unit tests (100% pass rate) - -- **Jira Extension**: First official extension for Jira integration - - Extension ID: `jira` - - Version: 1.0.0 - - Commands: - - `/speckit.jira.specstoissues` - Create Jira hierarchy from spec and tasks - - `/speckit.jira.discover-fields` - Discover Jira custom fields - - `/speckit.jira.sync-status` - Sync task completion status - - Comprehensive documentation (README, usage guide, examples) - - MIT licensed - -- **Hook System**: Extension lifecycle hooks for automation - - `HookExecutor` class for managing extension hooks - - Hooks registered in `.specify/extensions.yml` - - Hook registration during extension installation - - Hook unregistration during extension removal - - Support for optional and mandatory hooks - - Hook execution messages for AI agent integration - - Condition support for conditional hook execution (placeholder) - -- **Extension Management**: Advanced extension management commands - - `specify extension update` - Check and update extensions to latest version - - `specify extension enable` - Enable a disabled extension - - `specify extension disable` - Disable extension without removing it - - Version comparison with catalog - - Update notifications - - Preserve configuration during updates - -- **Multi-Agent Support**: Extensions now work with all supported AI agents (Phase 6) - - Automatic detection and registration for all agents in project - - Support for 16+ AI agents (Claude, Gemini, Copilot, Cursor, Qwen, and more) - - Agent-specific command formats (Markdown and TOML) - - Automatic argument placeholder conversion ($ARGUMENTS → {{args}}) - - Commands registered for all detected agents during installation - - Multi-agent command unregistration on extension removal - - `CommandRegistrar.register_commands_for_agent()` method - - `CommandRegistrar.register_commands_for_all_agents()` method - -- **Configuration Layers**: Full configuration cascade system (Phase 6) - - **Layer 1**: Defaults from extension manifest (`extension.yml`) - - **Layer 2**: Project config (`.specify/extensions/{ext-id}/{ext-id}-config.yml`) - - **Layer 3**: Local config (`.specify/extensions/{ext-id}/local-config.yml`, gitignored) - - **Layer 4**: Environment variables (`SPECKIT_{EXT_ID}_{KEY}` pattern) - - Recursive config merging with proper precedence - - `ConfigManager` class for programmatic config access - - `get_config()`, `get_value()`, `has_value()` methods - - Support for nested configuration paths with dot-notation - -- **Hook Condition Evaluation**: Smart hook execution based on runtime conditions (Phase 6) - - Config conditions: `config.key.path is set`, `config.key == 'value'`, `config.key != 'value'` - - Environment conditions: `env.VAR is set`, `env.VAR == 'value'`, `env.VAR != 'value'` - - Automatic filtering of hooks based on condition evaluation - - Safe fallback behavior on evaluation errors - - Case-insensitive pattern matching - -- **Hook Integration**: Agent-level hook checking and execution (Phase 6) - - `check_hooks_for_event()` method for AI agents to query hooks after core commands - - Condition-aware hook filtering before execution - - `enable_hooks()` and `disable_hooks()` methods per extension - - Formatted hook messages for agent display - - `execute_hook()` method for hook execution information - -- **Documentation Suite**: Comprehensive documentation for users and developers - - **EXTENSION-USER-GUIDE.md**: Complete user guide with installation, usage, configuration, and troubleshooting - - **EXTENSION-API-REFERENCE.md**: Technical API reference with manifest schema, Python API, and CLI commands - - **EXTENSION-PUBLISHING-GUIDE.md**: Publishing guide for extension authors - - **RFC-EXTENSION-SYSTEM.md**: Extension architecture design document - -- **Extension Template**: Starter template in `extensions/template/` for creating new extensions - - Fully commented `extension.yml` manifest template - - Example command file with detailed explanations - - Configuration template with all options - - Complete project structure (README, LICENSE, CHANGELOG, .gitignore) - - EXAMPLE-README.md showing final documentation format - -- **Unit Tests**: Comprehensive test suite with 39 tests covering all extension system components - - Test coverage: 83% of extension module code - - Test dependencies: `pytest>=7.0`, `pytest-cov>=4.0` - - Configured pytest in `pyproject.toml` - -### Changed - -- Version bumped to 0.1.0 (minor release for new feature) - -## [0.0.22] - 2025-11-07 - -- Support for VS Code/Copilot agents, and moving away from prompts to proper agents with hand-offs. -- Move to use `AGENTS.md` for Copilot workloads, since it's already supported out-of-the-box. -- Adds support for the version command. ([#486](https://github.com/github/spec-kit/issues/486)) -- Fixes potential bug with the `create-new-feature.ps1` script that ignores existing feature branches when determining next feature number ([#975](https://github.com/github/spec-kit/issues/975)) -- Add graceful fallback and logging for GitHub API rate-limiting during template fetch ([#970](https://github.com/github/spec-kit/issues/970)) - -## [0.0.21] - 2025-10-21 - -- Fixes [#975](https://github.com/github/spec-kit/issues/975) (thank you [@fgalarraga](https://github.com/fgalarraga)). -- Adds support for Amp CLI. -- Adds support for VS Code hand-offs and moves prompts to be full-fledged chat modes. -- Adds support for `version` command (addresses [#811](https://github.com/github/spec-kit/issues/811) and [#486](https://github.com/github/spec-kit/issues/486), thank you [@mcasalaina](https://github.com/mcasalaina) and [@dentity007](https://github.com/dentity007)). -- Adds support for rendering the rate limit errors from the CLI when encountered ([#970](https://github.com/github/spec-kit/issues/970), thank you [@psmman](https://github.com/psmman)). - -## [0.0.20] - 2025-10-14 - -### Added - -- **Intelligent Branch Naming**: `create-new-feature` scripts now support `--short-name` parameter for custom branch names - - When `--short-name` provided: Uses the custom name directly (cleaned and formatted) - - When omitted: Automatically generates meaningful names using stop word filtering and length-based filtering - - Filters out common stop words (I, want, to, the, for, etc.) - - Removes words shorter than 3 characters (unless they're uppercase acronyms) - - Takes 3-4 most meaningful words from the description - - **Enforces GitHub's 244-byte branch name limit** with automatic truncation and warnings - - Examples: - - "I want to create user authentication" → `001-create-user-authentication` - - "Implement OAuth2 integration for API" → `001-implement-oauth2-integration-api` - - "Fix payment processing bug" → `001-fix-payment-processing` - - Very long descriptions are automatically truncated at word boundaries to stay within limits - - Designed for AI agents to provide semantic short names while maintaining standalone usability - -### Changed - -- Enhanced help documentation for `create-new-feature.sh` and `create-new-feature.ps1` scripts with examples -- Branch names now validated against GitHub's 244-byte limit with automatic truncation if needed - -## [0.0.19] - 2025-10-10 - -### Added - -- Support for CodeBuddy (thank you to [@lispking](https://github.com/lispking) for the contribution). -- You can now see Git-sourced errors in the Specify CLI. - -### Changed - -- Fixed the path to the constitution in `plan.md` (thank you to [@lyzno1](https://github.com/lyzno1) for spotting). -- Fixed backslash escapes in generated TOML files for Gemini (thank you to [@hsin19](https://github.com/hsin19) for the contribution). -- Implementation command now ensures that the correct ignore files are added (thank you to [@sigent-amazon](https://github.com/sigent-amazon) for the contribution). - -## [0.0.18] - 2025-10-06 +## [0.1.3] - Unreleased ### Added -- Support for using `.` as a shorthand for current directory in `specify init .` command, equivalent to `--here` flag but more intuitive for users. -- Use the `/speckit.` command prefix to easily discover Spec Kit-related commands. -- Refactor the prompts and templates to simplify their capabilities and how they are tracked. No more polluting things with tests when they are not needed. -- Ensure that tasks are created per user story (simplifies testing and validation). -- Add support for Visual Studio Code prompt shortcuts and automatic script execution. +- **Generic Agent Support**: Added `--ai generic` option for unsupported AI agents ("bring your own agent") + - Requires `--ai-commands-dir ` to specify where the agent reads commands from + - Generates Markdown commands with `$ARGUMENTS` format (compatible with most agents) + - Example: `specify init my-project --ai generic --ai-commands-dir .myagent/commands/` + - Enables users to start with Spec Kit immediately while their agent awaits formal support -### Changed +## [0.0.102] - 2026-02-20 -- All command files now prefixed with `speckit.` (e.g., `speckit.specify.md`, `speckit.plan.md`) for better discoverability and differentiation in IDE/CLI command palettes and file explorers +- fix: include 'src/**' path in release workflow triggers (#1646) -## [0.0.17] - 2025-09-22 +## [0.0.101] - 2026-02-19 -### Added - -- New `/clarify` command template to surface up to 5 targeted clarification questions for an existing spec and persist answers into a Clarifications section in the spec. -- New `/analyze` command template providing a non-destructive cross-artifact discrepancy and alignment report (spec, clarifications, plan, tasks, constitution) inserted after `/tasks` and before `/implement`. - - Note: Constitution rules are explicitly treated as non-negotiable; any conflict is a CRITICAL finding requiring artifact remediation, not weakening of principles. - -## [0.0.16] - 2025-09-22 - -### Added - -- `--force` flag for `init` command to bypass confirmation when using `--here` in a non-empty directory and proceed with merging/overwriting files. - -## [0.0.15] - 2025-09-21 - -### Added - -- Support for Roo Code. - -## [0.0.14] - 2025-09-21 +- chore(deps): bump github/codeql-action from 3 to 4 (#1635) -### Changed +## [0.0.100] - 2026-02-19 -- Error messages are now shown consistently. +- Add pytest and Python linting (ruff) to CI (#1637) +- feat: add pull request template for better contribution guidelines (#1634) -## [0.0.13] - 2025-09-21 +## [0.0.99] - 2026-02-19 -### Added - -- Support for Kilo Code. Thank you [@shahrukhkhan489](https://github.com/shahrukhkhan489) with [#394](https://github.com/github/spec-kit/pull/394). -- Support for Auggie CLI. Thank you [@hungthai1401](https://github.com/hungthai1401) with [#137](https://github.com/github/spec-kit/pull/137). -- Agent folder security notice displayed after project provisioning completion, warning users that some agents may store credentials or auth tokens in their agent folders and recommending adding relevant folders to `.gitignore` to prevent accidental credential leakage. - -### Changed - -- Warning displayed to ensure that folks are aware that they might need to add their agent folder to `.gitignore`. -- Cleaned up the `check` command output. - -## [0.0.12] - 2025-09-21 - -### Changed - -- Added additional context for OpenAI Codex users - they need to set an additional environment variable, as described in [#417](https://github.com/github/spec-kit/issues/417). - -## [0.0.11] - 2025-09-20 - -### Added +- Feat/ai skills (#1632) -- Codex CLI support (thank you [@honjo-hiroaki-gtt](https://github.com/honjo-hiroaki-gtt) for the contribution in [#14](https://github.com/github/spec-kit/pull/14)) -- Codex-aware context update tooling (Bash and PowerShell) so feature plans refresh `AGENTS.md` alongside existing assistants without manual edits. +## [0.0.98] - 2026-02-19 -## [0.0.10] - 2025-09-20 +- chore(deps): bump actions/stale from 9 to 10 (#1623) +- feat: add dependabot configuration for pip and GitHub Actions updates (#1622) -### Fixed +## [0.0.97] - 2026-02-18 -- Addressed [#378](https://github.com/github/spec-kit/issues/378) where a GitHub token may be attached to the request when it was empty. +- Remove Maintainers section from README.md (#1618) -## [0.0.9] - 2025-09-19 +## [0.0.96] - 2026-02-17 -### Changed +- fix: typo in plan-template.md (#1446) -- Improved agent selector UI with cyan highlighting for agent keys and gray parentheses for full names - -## [0.0.8] - 2025-09-19 - -### Added - -- Windsurf IDE support as additional AI assistant option (thank you [@raedkit](https://github.com/raedkit) for the work in [#151](https://github.com/github/spec-kit/pull/151)) -- GitHub token support for API requests to handle corporate environments and rate limiting (contributed by [@zryfish](https://github.com/@zryfish) in [#243](https://github.com/github/spec-kit/pull/243)) - -### Changed - -- Updated README with Windsurf examples and GitHub token usage -- Enhanced release workflow to include Windsurf templates - -## [0.0.7] - 2025-09-18 - -### Changed - -- Updated command instructions in the CLI. -- Cleaned up the code to not render agent-specific information when it's generic. - -## [0.0.6] - 2025-09-17 - -### Added - -- opencode support as additional AI assistant option - -## [0.0.5] - 2025-09-17 - -### Added - -- Qwen Code support as additional AI assistant option - -## [0.0.4] - 2025-09-14 - -### Added +## [0.0.95] - 2026-02-12 -- SOCKS proxy support for corporate environments via `httpx[socks]` dependency +- Feat: add a new agent: Google Anti Gravity (#1220) -### Fixed +## [0.0.94] - 2026-02-11 -N/A +- Add stale workflow for 180-day inactive issues and PRs (#1594) -### Changed +## [0.0.93] - 2026-02-10 -N/A +- Add modular extension system (#1551) diff --git a/README.md b/README.md index f1ead5c05f..e3333c24ec 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c | [SHAI (OVHcloud)](https://github.com/ovh/shai) | ✅ | | | [Windsurf](https://windsurf.com/) | ✅ | | | [Antigravity (agy)](https://agy.ai/) | ✅ | | +| Generic | ✅ | Bring your own agent — use `--ai generic --ai-commands-dir ` for unsupported agents | ## 🔧 Specify CLI Reference @@ -179,7 +180,8 @@ The `specify` command supports the following options: | Argument/Option | Type | Description | | ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` | Argument | Name for your new project directory (optional if using `--here`, or use `.` for current directory) | -| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, `shai`, `q`, `agy`, `bob`, or `qoder` | +| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, `shai`, `q`, `agy`, `bob`, `qoder`, or `generic` (requires `--ai-commands-dir`) | +| `--ai-commands-dir` | Option | Directory for agent command files (required with `--ai generic`, e.g. `.myagent/commands/`) | | `--script` | Option | Script variant to use: `sh` (bash/zsh) or `ps` (PowerShell) | | `--ignore-agent-tools` | Flag | Skip checks for AI agent tools like Claude Code | | `--no-git` | Flag | Skip git repository initialization | @@ -217,6 +219,9 @@ specify init my-project --ai shai # Initialize with IBM Bob support specify init my-project --ai bob +# Initialize with an unsupported agent (generic / bring your own agent) +specify init my-project --ai generic --ai-commands-dir .myagent/commands/ + # Initialize with PowerShell scripts (Windows/cross-platform) specify init my-project --ai copilot --script ps diff --git a/pyproject.toml b/pyproject.toml index 73b50738bc..b1e87c5168 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "specify-cli" -version = "0.1.2" +version = "0.1.3" description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)." requires-python = ">=3.11" dependencies = [ diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index 40db5e30af..d55accf927 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -637,9 +637,12 @@ update_specific_agent() { bob) update_agent_file "$BOB_FILE" "IBM Bob" ;; + generic) + log_info "Generic agent: no predefined context file. Use the agent-specific update script for your agent." + ;; *) log_error "Unknown agent type '$agent_type'" - log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|shai|q|agy|bob|qoder" + log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|shai|q|agy|bob|qoder|generic" exit 1 ;; esac diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index eb46b5bece..d495dbf54d 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -25,7 +25,7 @@ Relies on common helper functions in common.ps1 #> param( [Parameter(Position=0)] - [ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','q','agy','bob','qoder')] + [ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','q','agy','bob','qoder','generic')] [string]$AgentType ) @@ -390,7 +390,8 @@ function Update-SpecificAgent { 'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' } 'agy' { Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity' } 'bob' { Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob' } - default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qoder'; return $false } + 'generic' { Write-Info 'Generic agent: no predefined context file. Use the agent-specific update script for your agent.' } + default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qoder|generic'; return $false } } } @@ -427,7 +428,7 @@ function Print-Summary { if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" } if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" } Write-Host '' - Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qoder]' + Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qoder|generic]' } function Main { diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 3794933211..d2f7c44178 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -233,6 +233,12 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) "install_url": None, # IDE-based "requires_cli": False, }, + "generic": { + "name": "Generic (bring your own agent)", + "folder": None, # Set dynamically via --ai-commands-dir + "install_url": None, + "requires_cli": False, + }, } SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"} @@ -1188,7 +1194,8 @@ def install_ai_skills(project_path: Path, selected_ai: str, tracker: StepTracker @app.command() def init( project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"), - ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, shai, q, agy, bob, or qoder "), + ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, shai, q, agy, bob, qoder, or generic (requires --ai-commands-dir)"), + ai_commands_dir: str = typer.Option(None, "--ai-commands-dir", help="Directory for agent command files (required with --ai generic, e.g. .myagent/commands/)"), script_type: str = typer.Option(None, "--script", help="Script type to use: sh or ps"), ignore_agent_tools: bool = typer.Option(False, "--ignore-agent-tools", help="Skip checks for AI agent tools like Claude Code"), no_git: bool = typer.Option(False, "--no-git", help="Skip git repository initialization"), @@ -1224,6 +1231,7 @@ def init( specify init --here --force # Skip confirmation when current directory not empty specify init my-project --ai claude --ai-skills # Install agent skills specify init --here --ai gemini --ai-skills + specify init my-project --ai generic --ai-commands-dir .myagent/commands/ # Unsupported agent """ show_banner() @@ -1308,6 +1316,16 @@ def init( "copilot" ) + # Validate --ai-commands-dir usage + if selected_ai == "generic": + if not ai_commands_dir: + console.print("[red]Error:[/red] --ai-commands-dir is required when using --ai generic") + console.print("[dim]Example: specify init my-project --ai generic --ai-commands-dir .myagent/commands/[/dim]") + raise typer.Exit(1) + elif ai_commands_dir: + console.print(f"[red]Error:[/red] --ai-commands-dir can only be used with --ai generic (not '{selected_ai}')") + raise typer.Exit(1) + if not ignore_agent_tools: agent_config = AGENT_CONFIG.get(selected_ai) if agent_config and agent_config["requires_cli"]: @@ -1383,6 +1401,18 @@ def init( download_and_extract_template(project_path, selected_ai, selected_script, here, verbose=False, tracker=tracker, client=local_client, debug=debug, github_token=github_token) + # For generic agent, rename placeholder directory to user-specified path + if selected_ai == "generic" and ai_commands_dir: + placeholder_dir = project_path / ".speckit" / "commands" + target_dir = project_path / ai_commands_dir + if placeholder_dir.is_dir(): + target_dir.parent.mkdir(parents=True, exist_ok=True) + shutil.move(str(placeholder_dir), str(target_dir)) + # Clean up empty .speckit dir if it's now empty + speckit_dir = project_path / ".speckit" + if speckit_dir.is_dir() and not any(speckit_dir.iterdir()): + speckit_dir.rmdir() + ensure_executable_scripts(project_path, tracker=tracker) ensure_constitution_from_template(project_path, tracker=tracker) @@ -1468,16 +1498,17 @@ def init( # Agent folder security notice agent_config = AGENT_CONFIG.get(selected_ai) if agent_config: - agent_folder = agent_config["folder"] - security_notice = Panel( - f"Some agents may store credentials, auth tokens, or other identifying and private artifacts in the agent folder within your project.\n" - f"Consider adding [cyan]{agent_folder}[/cyan] (or parts of it) to [cyan].gitignore[/cyan] to prevent accidental credential leakage.", - title="[yellow]Agent Folder Security[/yellow]", - border_style="yellow", - padding=(1, 2) - ) - console.print() - console.print(security_notice) + agent_folder = ai_commands_dir if selected_ai == "generic" else agent_config["folder"] + if agent_folder: + security_notice = Panel( + f"Some agents may store credentials, auth tokens, or other identifying and private artifacts in the agent folder within your project.\n" + f"Consider adding [cyan]{agent_folder}[/cyan] (or parts of it) to [cyan].gitignore[/cyan] to prevent accidental credential leakage.", + title="[yellow]Agent Folder Security[/yellow]", + border_style="yellow", + padding=(1, 2) + ) + console.print() + console.print(security_notice) steps_lines = [] if not here: @@ -1535,6 +1566,8 @@ def check(): agent_results = {} for agent_key, agent_config in AGENT_CONFIG.items(): + if agent_key == "generic": + continue # Generic is not a real agent to check agent_name = agent_config["name"] requires_cli = agent_config["requires_cli"] diff --git a/tests/test_ai_skills.py b/tests/test_ai_skills.py index b86b4a470a..d4c607b643 100644 --- a/tests/test_ai_skills.py +++ b/tests/test_ai_skills.py @@ -380,7 +380,7 @@ def test_non_md_commands_dir_falls_back(self, project_dir): # .toml commands should be untouched assert (cmds_dir / "speckit.specify.toml").exists() - @pytest.mark.parametrize("agent_key", list(AGENT_CONFIG.keys())) + @pytest.mark.parametrize("agent_key", [k for k in AGENT_CONFIG.keys() if k != "generic"]) def test_skills_install_for_all_agents(self, temp_dir, agent_key): """install_ai_skills should produce skills for every configured agent.""" proj = temp_dir / f"proj-{agent_key}"