Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot]
5b5f812b44 chore: bump version to 0.8.8 2026-05-11 17:05:34 +00:00
21 changed files with 218 additions and 956 deletions

View File

@@ -2,23 +2,6 @@
<!-- insert new changelog below this comment -->
## [0.8.9] - 2026-05-12
### Changed
- docs: revamp landing page with four-pillar card layout (#2531)
- feat(extensions): update governance ecosystem extensions to latest versions (#2514)
- Add changelog extension (#2177)
- Add install directory to docfx.json file references (#2522)
- feat(catalog): add BrownKit (brownkit) community extension (#2510) (#2520)
- fix(kiro-cli): replace literal $ARGUMENTS with prose fallback (#2482)
- Preset: Add game-narrative-writing preset to community catalog (#2454)
- docs: clarify CLI upgrade discovery (#2519)
- fix: make template metadata line breaks markdownlint-safe (#2505)
- refactor(catalogs): extract integration catalog config loading (#2497)
- test(presets): silence expected UserWarnings in self-test composition… (#2373)
- chore: release 0.8.8, begin 0.8.9.dev0 development (#2516)
## [0.8.8] - 2026-05-11
### Changed

View File

@@ -208,7 +208,6 @@ The following community-contributed extensions are available in [`catalog.commun
| Blueprint | Stay code-literate in AI-driven development: review a complete code blueprint for every task from spec artifacts before /speckit.implement runs | `docs` | Read+Write | [spec-kit-blueprint](https://github.com/chordpli/spec-kit-blueprint) |
| Branch Convention | Configurable branch and folder naming conventions for /specify with presets and custom patterns | `process` | Read+Write | [spec-kit-branch-convention](https://github.com/Quratulain-bilal/spec-kit-branch-convention) |
| Brownfield Bootstrap | Bootstrap spec-kit for existing codebases — auto-discover architecture and adopt SDD incrementally | `process` | Read+Write | [spec-kit-brownfield](https://github.com/Quratulain-bilal/spec-kit-brownfield) |
| BrownKit | Evidence-driven capability discovery, security and QA risk assessment for existing codebases | `process` | Read+Write | [BrownKit](https://github.com/MaksimShevtsov/BrownKit) |
| Bugfix Workflow | Structured bugfix workflow — capture bugs, trace to spec artifacts, and patch specs surgically | `process` | Read+Write | [spec-kit-bugfix](https://github.com/Quratulain-bilal/spec-kit-bugfix) |
| Canon | Adds canon-driven (baseline-driven) workflows: spec-first, code-first, spec-drift. Requires Canon Core preset installation. | `process` | Read+Write | [spec-kit-canon](https://github.com/maximiliamus/spec-kit-canon/tree/master/extension) |
| Catalog CI | Automated validation for spec-kit community catalog entries — structure, URLs, diffs, and linting | `process` | Read-only | [spec-kit-catalog-ci](https://github.com/Quratulain-bilal/spec-kit-catalog-ci) |
@@ -266,12 +265,11 @@ The following community-contributed extensions are available in [`catalog.commun
| Security Review | Full-project secure-by-design security audits plus staged, branch/PR, plan, task, follow-up, and apply reviews | `code` | Read+Write | [spec-kit-security-review](https://github.com/DyanGalih/spec-kit-security-review) |
| SFSpeckit | Enterprise Salesforce SDLC with 18 commands for the full SDD lifecycle. | `process` | Read+Write | [spec-kit-sf](https://github.com/ysumanth06/spec-kit-sf) |
| Ship Release Extension | Automates release pipeline: pre-flight checks, branch sync, changelog generation, CI verification, and PR creation | `process` | Read+Write | [spec-kit-ship](https://github.com/arunt14/spec-kit-ship) |
| Spec Changelog | Auto-generate changelogs and release notes from spec git history and requirement diffs | `docs` | Read-only | [spec-kit-changelog](https://github.com/Quratulain-bilal/spec-kit-changelog) |
| Spec Reference Loader | Reads the ## References section from the feature spec and loads only the listed docs into context | `docs` | Read-only | [spec-kit-spec-reference-loader](https://github.com/KevinBrown5280/spec-kit-spec-reference-loader) |
| Spec Critique Extension | Dual-lens critical review of spec and plan from product strategy and engineering risk perspectives | `docs` | Read-only | [spec-kit-critique](https://github.com/arunt14/spec-kit-critique) |
| Spec Diagram | Auto-generate Mermaid diagrams of SDD workflow state, feature progress, and task dependencies | `visibility` | Read-only | [spec-kit-diagram-](https://github.com/Quratulain-bilal/spec-kit-diagram-) |
| Spec Kit Schedule | Optimal multi-agent task scheduling via CP-SAT — DAG precedence, hallucination-aware caps, file-conflict avoidance, stochastic durations, replanning, and interactive HTML output | `process` | Read+Write | [spec-kit-schedule](https://github.com/jfranc38/spec-kit-schedule) |
| Spec Orchestrator | Cross-feature orchestration — track state, select tasks, and detect conflicts across parallel specs | `process` | Read-only | [spec-kit-orchestrator](https://github.com/Quratulain-bilal/spec-kit-orchestrator) |
| Spec Reference Loader | Reads the ## References section from the feature spec and loads only the listed docs into context | `docs` | Read-only | [spec-kit-spec-reference-loader](https://github.com/KevinBrown5280/spec-kit-spec-reference-loader) |
| Spec Refine | Update specs in-place, propagate changes to plan and tasks, and diff impact across artifacts | `process` | Read+Write | [spec-kit-refine](https://github.com/Quratulain-bilal/spec-kit-refine) |
| Spec Scope | Effort estimation and scope tracking — estimate work, detect creep, and budget time per phase | `process` | Read-only | [spec-kit-scope-](https://github.com/Quratulain-bilal/spec-kit-scope-) |
| Spec Sync | Detect and resolve drift between specs and implementation. AI-assisted resolution with human approval | `docs` | Read+Write | [spec-kit-sync](https://github.com/bgervin/spec-kit-sync) |

View File

@@ -16,7 +16,6 @@ The following community-contributed presets customize how Spec Kit behaves — o
| Cross-Platform Governance | Adds Bash/PowerShell parity, dry-run/WhatIf parity, Unix man-page expectations, PowerShell comment-based help, and Verb-Noun Cmdlet discipline | 8 templates, 3 commands | — | [spec-kit-preset-cross-platform-governance](https://github.com/hindermath/spec-kit-preset-cross-platform-governance) |
| Explicit Task Dependencies | Adds explicit `(depends on T###)` dependency declarations and an Execution Wave DAG to tasks.md for parallel scheduling | 1 template, 1 command | — | [spec-kit-preset-explicit-task-dependencies](https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies) |
| Fiction Book Writing | It adapts the Spec-Driven Development workflow for storytelling to create books or audiobooks (with annotations) in 12 languages: features become story elements, specs become story briefs, plans become story structures, and tasks become scene-by-scene writing tasks. Supports single and multi-POV, all major plot structure frameworks, and two style modes: an author voice sample or humanized AI prose. Supports interactive elements like brainstorming, interview, roleplay and extras like statistics, cover builder and bio command. Export with templates for KDP, D2D etc. | 22 templates, 27 commands, 2 scripts | — | [speckit-preset-fiction-book-writing](https://github.com/adaumann/speckit-preset-fiction-book-writing) |
| Game Narrative Writing | Spec-Driven Development for interactive game narrative pre-production for video games. Authors write in a portable generic format, Twine/Sugarcube (.twee) or Ink (.ink). Covers choice-IF, visual novels, and branching dialogue. Supports Tier 1 mechanic hooks (flag, counter, inventory, timer, trust, currency, npc_state, ending_condition), multi-ending design, series carry-over variable registry, and NPC-focused character architecture. | 22 templates, 36 commands, 2 scripts | — | [speckit-preset-game-narrative-writing](https://github.com/adaumann/speckit-preset-game-narrative-writing) |
| iSAQB Architecture Governance | Adds general iSAQB/CPSA-F and arc42 architecture governance: goals, context, building blocks, runtime and deployment views, quality scenarios, ADRs, risks, and technical debt | 13 templates, 3 commands | — | [spec-kit-preset-isaqb-architecture-governance](https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance) |
| Jira Issue Tracking | Overrides `speckit.taskstoissues` to create Jira epics, stories, and tasks instead of GitHub Issues via Atlassian MCP tools | 1 command | — | [spec-kit-preset-jira](https://github.com/luno/spec-kit-preset-jira) |
| Model Driven Engineering | Focuses on streamlined commands, app repository support, cross-spec support, and capability-aware project memory for model-driven engineering workflows | 6 templates, 11 commands | MDE extension | [spec-kit-preset-mde](https://github.com/AI-MDE/spec-kit-preset-mde) |

View File

@@ -1,46 +0,0 @@
# What is Spec-Driven Development?
Spec-Driven Development **flips the script** on traditional software development. For decades, code has been king — specifications were just scaffolding we built and discarded once the "real work" of coding began. Spec-Driven Development changes this: **specifications become executable**, directly generating working implementations rather than just guiding them.
## Core Philosophy
Spec-Driven Development is a structured process that emphasizes:
- **Intent-driven development** where specifications define the "*what*" before the "*how*"
- **Rich specification creation** using guardrails and organizational principles
- **Multi-step refinement** rather than one-shot code generation from prompts
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
## Development Phases
| Phase | Focus | Key Activities |
|-------|-------|----------------|
| **0-to-1 Development** ("Greenfield") | Generate from scratch | <ul><li>Start with high-level requirements</li><li>Generate specifications</li><li>Plan implementation steps</li><li>Build production-ready applications</li></ul> |
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
## Experimental Goals
Our research and experimentation focus on:
### Technology Independence
- Create applications using diverse technology stacks
- Validate the hypothesis that Spec-Driven Development is a process not tied to specific technologies, programming languages, or frameworks
### Enterprise Constraints
- Demonstrate mission-critical application development
- Incorporate organizational constraints (cloud providers, tech stacks, engineering practices)
- Support enterprise design systems and compliance requirements
### User-Centric Development
- Build applications for different user cohorts and preferences
- Support various development approaches (from vibe-coding to AI-native development)
### Creative & Iterative Processes
- Validate the concept of parallel implementation exploration
- Provide robust iterative feature development workflows
- Extend processes to handle upgrades and modernization tasks

View File

@@ -6,9 +6,7 @@
"*.md",
"toc.yml",
"community/*.md",
"concepts/*.md",
"reference/*.md",
"install/*.md"
"reference/*.md"
]
},
{
@@ -51,8 +49,7 @@
"fileMetadataFiles": [],
"template": [
"default",
"modern",
"template"
"modern"
],
"postProcessors": [],
"markdownEngineName": "markdig",
@@ -70,11 +67,6 @@
"repo": "https://github.com/github/spec-kit",
"branch": "main"
}
},
"fileMetadata": {
"_layout": {
"index.md": "landing"
}
}
}
}

View File

@@ -1,152 +1,67 @@
<div class="landing-hero">
# Spec Kit
# GitHub Spec Kit
*Build high-quality software faster.*
**Define what to build before building it — with any AI coding agent.**
**An effort to allow organizations to focus on product scenarios rather than writing undifferentiated code with the help of Spec-Driven Development.**
Spec Kit is a toolkit for [Spec-Driven Development](concepts/sdd.md) (SDD), a methodology that puts specifications at the center of AI-assisted software development. Instead of jumping straight to code, you describe *what* to build, refine it through structured phases, and let your AI coding agent implement it.
## What is Spec-Driven Development?
<a href="installation.md" class="btn btn-primary btn-lg">Install Spec Kit</a>&nbsp;
<a href="quickstart.md" class="btn btn-outline-primary btn-lg">Quick Start</a>
Spec-Driven Development **flips the script** on traditional software development. For decades, code has been king — specifications were just scaffolding we built and discarded once the "real work" of coding began. Spec-Driven Development changes this: **specifications become executable**, directly generating working implementations rather than just guiding them.
</div>
## Getting Started
---
- [Installation Guide](installation.md)
- [Quick Start Guide](quickstart.md)
- [Upgrade Guide](upgrade.md)
- [Local Development](local-development.md)
<div class="pillar-grid">
## Core Philosophy
<div class="pillar-card">
Spec-Driven Development is a structured process that emphasizes:
### Spec-driven by default
- **Intent-driven development** where specifications define the "*what*" before the "*how*"
- **Rich specification creation** using guardrails and organizational principles
- **Multi-step refinement** rather than one-shot code generation from prompts
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
The core SDD process ships ready to use: **Spec → Plan → Tasks → Implement**.
## Development Phases
Define what to build before building it. Rich templates, quality checklists, and cross-artifact analysis come out of the box. Each phase produces a Markdown artifact that feeds the next — giving your AI coding agent structured context instead of ad-hoc prompts.
| Phase | Focus | Key Activities |
|-------|-------|----------------|
| **0-to-1 Development** ("Greenfield") | Generate from scratch | <ul><li>Start with high-level requirements</li><li>Generate specifications</li><li>Plan implementation steps</li><li>Build production-ready applications</li></ul> |
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
<a href="quickstart.md" class="pillar-link">Walk through the workflow →</a>
## Experimental Goals
</div>
Our research and experimentation focus on:
<div class="pillar-card">
### Technology Independence
### Use any coding agent
- Create applications using diverse technology stacks
- Validate the hypothesis that Spec-Driven Development is a process not tied to specific technologies, programming languages, or frameworks
<span class="pillar-stat">30 integrations</span> — Copilot, Gemini, Codex, Windsurf, Claude, Forge, Kiro, and more. Switch freely between agents with a single command. No lock-in.
### Enterprise Constraints
Run `specify init` with your agent of choice and Spec Kit sets up the right command files, context rules, and directory structures automatically. If your agent isn't listed, the `generic` integration is an escape hatch for any tool.
- Demonstrate mission-critical application development
- Incorporate organizational constraints (cloud providers, tech stacks, engineering practices)
- Support enterprise design systems and compliance requirements
<a href="reference/integrations.md" class="pillar-link">See all integrations →</a>
### User-Centric Development
</div>
- Build applications for different user cohorts and preferences
- Support various development approaches (from vibe-coding to AI-native development)
<div class="pillar-card">
### Creative & Iterative Processes
### Make it your own
- Validate the concept of parallel implementation exploration
- Provide robust iterative feature development workflows
- Extend processes to handle upgrades and modernization tasks
<span class="pillar-stat">91 community extensions</span> (50+ authors), <span class="pillar-stat">18 presets</span>, and growing — including entirely different SDD processes:
## Contributing
- **AIDE** — 7-step AI-driven engineering lifecycle
- **Canon** — baseline-driven workflows (spec-first, code-first, spec-drift)
- **Product Forge** — product-management-oriented SDD
- **FX→.NET** — end-to-end .NET Framework migration across 7 phases
- **MAQA** — multi-agent orchestration with quality assurance gates
Please see our [Contributing Guide](https://github.com/github/spec-kit/blob/main/CONTRIBUTING.md) for information on how to contribute to this project.
Tune the core process with presets, extend it with extensions, orchestrate it with workflows, or replace it entirely. Build and publish your own.
## Support
<a href="community/presets.md" class="pillar-link">Browse community presets →</a>
</div>
<div class="pillar-card">
### Integrate into your organization
Works offline, behind firewalls, and on **Windows, macOS, and Linux**. Host your own extension and preset catalogs so your organization controls what gets installed.
Community extensions like CI Guard and Architecture Guard add compliance gates and governance that fit the way your team already works.
<a href="installation.md" class="pillar-link">Installation guide →</a>&nbsp;&nbsp;
<a href="reference/extensions.md" class="pillar-link">Extensions reference →</a>
</div>
</div>
---
<div class="community-section">
## Built by the community
**200+ contributors** power the Spec Kit ecosystem — from core integrations to entirely new development processes. Anyone can create and publish an extension, preset, or workflow.
<div class="stats-grid">
<div class="stat-item">
<span class="stat-number">96K+</span>
<span class="stat-label">GitHub stars</span>
</div>
<div class="stat-item">
<span class="stat-number">200+</span>
<span class="stat-label">Contributors</span>
</div>
<div class="stat-item">
<span class="stat-number">30</span>
<span class="stat-label">Integrations</span>
</div>
<div class="stat-item">
<span class="stat-number">91</span>
<span class="stat-label">Extensions</span>
</div>
<div class="stat-item">
<span class="stat-number">18</span>
<span class="stat-label">Presets</span>
</div>
<div class="stat-item">
<span class="stat-number">4</span>
<span class="stat-label">Friends projects</span>
</div>
</div>
<a href="community/presets.md">Presets</a> · <a href="community/walkthroughs.md">Walkthroughs</a> · <a href="community/friends.md">Friends</a>
</div>
---
## Explore the docs
<div class="nav-cards">
<a href="quickstart.md" class="nav-card">
<strong>Getting Started</strong>
<span>Install, configure, and run your first SDD workflow</span>
</a>
<a href="reference/overview.md" class="nav-card">
<strong>Reference</strong>
<span>Core commands, integrations, extensions, presets, and workflows</span>
</a>
<a href="community/presets.md" class="nav-card">
<strong>Community</strong>
<span>Presets, walkthroughs, and friend projects</span>
</a>
<a href="local-development.md" class="nav-card">
<strong>Development</strong>
<span>Contribute to Spec Kit</span>
</a>
<a href="concepts/sdd.md" class="nav-card">
<strong>What is SDD?</strong>
<span>The philosophy behind Spec-Driven Development</span>
</a>
</div>
---
<div class="footer-cta">
```bash
uvx --from git+https://github.com/github/spec-kit.git
specify init my-project --integration copilot
```
Ready to start? Follow the [Quick Start Guide](quickstart.md).
</div>
For support, please check our [Support Guide](https://github.com/github/spec-kit/blob/main/SUPPORT.md) or open an issue on GitHub.

View File

@@ -23,7 +23,7 @@ The Specify CLI supports a wide range of AI coding agents. When you run `specify
| [Junie](https://junie.jetbrains.com/) | `junie` | |
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | `kilocode` | |
| [Kimi Code](https://code.kimi.com/) | `kimi` | Skills-based integration; supports `--migrate-legacy` for dotted→hyphenated directory migration |
| [Kiro CLI](https://kiro.dev/docs/cli/) | `kiro-cli` | Kiro CLI does not substitute `$ARGUMENTS` in file-based prompts, so Spec Kit ships a prose fallback at render time (see [Manage prompts](https://kiro.dev/docs/cli/chat/manage-prompts/) and issue [#1926](https://github.com/github/spec-kit/issues/1926)). Alias: `--integration kiro` |
| [Kiro CLI](https://kiro.dev/docs/cli/) | `kiro-cli` | Alias: `--integration kiro` |
| [Lingma](https://lingma.aliyun.com/) | `lingma` | Skills-based integration; skills are installed automatically |
| [Mistral Vibe](https://github.com/mistralai/mistral-vibe) | `vibe` | |
| [opencode](https://opencode.ai/) | `opencode` | |
@@ -65,8 +65,6 @@ Installing an additional integration does not change the default integration. Us
> **Note:** All integration management commands require a project already initialized with `specify init`. To start a new project with a specific agent, use `specify init <project> --integration <key>` instead.
**Version note:** Controlled multi-install support was introduced in Spec Kit 0.8.5. If `specify integration install <key>` says another integration is already installed and only suggests `switch` or `uninstall`, check your local CLI with `specify version` and upgrade it. Running a one-shot command such as `uvx --from git+https://github.com/github/spec-kit.git specify ...` uses a temporary copy for that command only; it does not update the persistent `specify` executable on your `PATH`.
## Uninstall an Integration
```bash

View File

@@ -1,264 +0,0 @@
/* Spec Kit landing page — GitHub Primer colors */
:root {
/* GitHub Primer palette */
--gh-blue: #0969da;
--gh-green: #1a7f37;
--gh-purple: #8250df;
--gh-coral: #cf222e;
--gh-orange: #bf8700;
--gh-blue-subtle: #ddf4ff;
--gh-green-subtle: #dafbe1;
--gh-purple-subtle: #fbefff;
--gh-coral-subtle: #ffebe9;
}
[data-bs-theme="dark"] {
--gh-blue: #58a6ff;
--gh-green: #3fb950;
--gh-purple: #bc8cff;
--gh-coral: #f85149;
--gh-orange: #d29922;
--gh-blue-subtle: #0d1d30;
--gh-green-subtle: #0d1d14;
--gh-purple-subtle: #1c0d2e;
--gh-coral-subtle: #2d0f0d;
}
/* Override Bootstrap primary with GitHub blue */
body[data-layout="landing"] {
--bs-primary: var(--gh-blue);
--bs-primary-rgb: 9, 105, 218;
--bs-link-color: var(--gh-blue);
--bs-link-hover-color: var(--gh-blue);
}
[data-bs-theme="dark"] body[data-layout="landing"],
body[data-layout="landing"][data-bs-theme="dark"] {
--bs-primary-rgb: 88, 166, 255;
}
/* Hero section */
.landing-hero {
text-align: center;
padding: 3rem 0 1.5rem;
}
.landing-hero h1 {
font-size: 2.6rem;
font-weight: 800;
margin-bottom: 0.5rem;
background: linear-gradient(135deg, var(--gh-blue), var(--gh-purple));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.landing-hero p {
font-size: 1.15rem;
max-width: 640px;
margin: 0 auto 1.5rem;
opacity: 0.85;
}
.landing-hero .btn-primary {
background-color: var(--gh-blue);
border-color: var(--gh-blue);
color: #fff;
}
.landing-hero .btn-primary:hover {
background-color: #0860ca;
border-color: #0860ca;
}
.landing-hero .btn-outline-primary {
color: var(--gh-blue);
border-color: var(--gh-blue);
}
.landing-hero .btn-outline-primary:hover {
background-color: var(--gh-blue);
border-color: var(--gh-blue);
color: #fff;
}
/* Pillar cards grid */
.pillar-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin: 2rem 0;
}
@media (max-width: 768px) {
.pillar-grid {
grid-template-columns: 1fr;
}
}
.pillar-card {
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
padding: 1.5rem;
background: var(--bs-body-bg);
transition: box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out;
border-top: 3px solid transparent;
}
/* Each pillar gets a distinct GitHub color accent */
.pillar-card:nth-child(1) { border-top-color: var(--gh-green); }
.pillar-card:nth-child(2) { border-top-color: var(--gh-blue); }
.pillar-card:nth-child(3) { border-top-color: var(--gh-purple); }
.pillar-card:nth-child(4) { border-top-color: var(--gh-coral); }
.pillar-card:nth-child(1):hover { box-shadow: 0 4px 16px rgba(26, 127, 55, 0.12); }
.pillar-card:nth-child(2):hover { box-shadow: 0 4px 16px rgba(9, 105, 218, 0.12); }
.pillar-card:nth-child(3):hover { box-shadow: 0 4px 16px rgba(130, 80, 223, 0.12); }
.pillar-card:nth-child(4):hover { box-shadow: 0 4px 16px rgba(207, 34, 46, 0.12); }
[data-bs-theme="dark"] .pillar-card:nth-child(1):hover { box-shadow: 0 4px 16px rgba(63, 185, 80, 0.15); }
[data-bs-theme="dark"] .pillar-card:nth-child(2):hover { box-shadow: 0 4px 16px rgba(88, 166, 255, 0.15); }
[data-bs-theme="dark"] .pillar-card:nth-child(3):hover { box-shadow: 0 4px 16px rgba(188, 140, 255, 0.15); }
[data-bs-theme="dark"] .pillar-card:nth-child(4):hover { box-shadow: 0 4px 16px rgba(248, 81, 73, 0.15); }
.pillar-card h3 {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 0.75rem;
}
/* Pillar headings pick up their card's accent color */
.pillar-card:nth-child(1) h3 { color: var(--gh-green); }
.pillar-card:nth-child(2) h3 { color: var(--gh-blue); }
.pillar-card:nth-child(3) h3 { color: var(--gh-purple); }
.pillar-card:nth-child(4) h3 { color: var(--gh-coral); }
.pillar-card .pillar-stat {
font-weight: 600;
color: var(--gh-blue);
}
.pillar-card:nth-child(3) .pillar-stat {
color: var(--gh-purple);
}
.pillar-card p:last-child {
margin-bottom: 0;
}
.pillar-card ul {
padding-left: 1.2rem;
margin-bottom: 0.5rem;
}
.pillar-card .pillar-link {
display: inline-block;
margin-top: 0.5rem;
font-size: 0.9rem;
font-weight: 500;
}
.pillar-card:nth-child(1) .pillar-link { color: var(--gh-blue); }
.pillar-card:nth-child(2) .pillar-link { color: var(--gh-green); }
.pillar-card:nth-child(3) .pillar-link { color: var(--gh-purple); }
.pillar-card:nth-child(4) .pillar-link { color: var(--gh-coral); }
/* Community stats section */
.community-section {
text-align: center;
padding: 2rem 0;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin: 1.5rem auto;
max-width: 700px;
}
@media (max-width: 576px) {
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
}
.stat-item {
padding: 1rem;
}
.stat-item .stat-number {
display: block;
font-size: 1.8rem;
font-weight: 700;
color: var(--gh-blue);
line-height: 1.2;
}
.stat-item .stat-label {
display: block;
font-size: 0.85rem;
opacity: 0.75;
margin-top: 0.25rem;
}
/* Nav cards */
.nav-cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin: 1.5rem 0;
}
@media (max-width: 576px) {
.nav-cards {
grid-template-columns: 1fr;
}
}
.nav-card {
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
padding: 1rem 1.25rem;
text-decoration: none;
color: inherit;
transition: box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out;
display: block;
border-left: 3px solid var(--gh-blue);
}
.nav-card:hover {
border-color: var(--gh-blue);
border-left-color: var(--gh-blue);
box-shadow: 0 2px 8px rgba(9, 105, 218, 0.1);
text-decoration: none;
color: inherit;
}
[data-bs-theme="dark"] .nav-card:hover {
box-shadow: 0 2px 8px rgba(88, 166, 255, 0.12);
}
.nav-card strong {
display: block;
margin-bottom: 0.25rem;
color: var(--gh-blue);
}
.nav-card span {
font-size: 0.9rem;
opacity: 0.75;
}
/* Footer CTA */
.footer-cta {
text-align: center;
padding: 2rem 0 1rem;
}
.footer-cta code {
font-size: 1.05rem;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
}

View File

@@ -30,12 +30,6 @@
- name: Workflows
href: reference/workflows.md
# Concepts
- name: Concepts
items:
- name: What is SDD?
href: concepts/sdd.md
# Development workflows
- name: Development
items:

View File

@@ -19,12 +19,6 @@
The CLI tool (`specify`) is separate from your project files. Upgrade it to get the latest features and bug fixes.
Before upgrading, you can check whether a newer released version is available:
```bash
specify self check
```
### If you installed with `uv tool install`
Upgrade to a specific release (check [Releases](https://github.com/github/spec-kit/releases) for the latest tag):
@@ -41,8 +35,6 @@ Specify the desired release tag:
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init --here --integration copilot
```
`uvx` runs a temporary copy of Spec Kit for that single command. It does not update a persistent `specify` installed with `uv tool install`, `pipx`, or another tool manager. If a newer feature works through `uvx` but your local `specify` still reports an older version, upgrade the persistent CLI with the command that matches your install method.
### If you installed with `pipx`
Upgrade to a specific release:
@@ -57,7 +49,7 @@ pipx install --force git+https://github.com/github/spec-kit.git@vX.Y.Z
specify check
```
This shows installed tools and confirms the CLI is working. Use `specify version` to confirm which persistent CLI version is currently on your `PATH`.
This shows installed tools and confirms the CLI is working.
---

View File

@@ -1,6 +1,6 @@
{
"schema_version": "1.0",
"updated_at": "2026-05-12T21:40:51Z",
"updated_at": "2026-05-07T20:05:00Z",
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json",
"extensions": {
"aide": {
@@ -174,8 +174,8 @@
"id": "architecture-guard",
"description": "Continuous architecture governance for AI-assisted development. Reviews specs, plans, and code for architecture drift, producing structured refactor tasks and evolution proposals.",
"author": "DyanGalih",
"version": "1.8.4",
"download_url": "https://github.com/DyanGalih/spec-kit-architecture-guard/archive/refs/tags/v1.8.4.zip",
"version": "1.8.0",
"download_url": "https://github.com/DyanGalih/spec-kit-architecture-guard/archive/refs/tags/v1.8.0.zip",
"repository": "https://github.com/DyanGalih/spec-kit-architecture-guard",
"homepage": "https://github.com/DyanGalih/spec-kit-architecture-guard",
"documentation": "https://github.com/DyanGalih/spec-kit-architecture-guard/blob/main/README.md",
@@ -185,8 +185,8 @@
"speckit_version": ">=0.1.0"
},
"provides": {
"commands": 10,
"hooks": 3
"commands": 6,
"hooks": 0
},
"tags": [
"architecture",
@@ -200,7 +200,7 @@
"downloads": 0,
"stars": 0,
"created_at": "2026-05-05T07:26:00Z",
"updated_at": "2026-05-11T14:58:00Z"
"updated_at": "2026-05-07T15:37:14Z"
},
"archive": {
"name": "Archive Extension",
@@ -368,38 +368,6 @@
"created_at": "2026-04-10T00:00:00Z",
"updated_at": "2026-04-10T00:00:00Z"
},
"brownkit": {
"name": "BrownKit \u2014 Brownfield Discovery for Spec-Kit",
"id": "brownkit",
"description": "Evidence-driven capability discovery, security and QA risk assessment for existing codebases.",
"author": "Maksim Shautsou",
"version": "1.0.1",
"download_url": "https://github.com/MaksimShevtsov/BrownKit/archive/refs/tags/v1.0.1.zip",
"repository": "https://github.com/MaksimShevtsov/BrownKit",
"homepage": "https://github.com/MaksimShevtsov/BrownKit",
"documentation": "https://github.com/MaksimShevtsov/BrownKit/blob/main/README.md",
"changelog": "https://github.com/MaksimShevtsov/BrownKit/blob/main/CHANGELOG.md",
"license": "MIT",
"requires": {
"speckit_version": ">=0.1.0"
},
"provides": {
"commands": 10,
"hooks": 5
},
"tags": [
"brownfield",
"discovery",
"security",
"qa",
"capabilities"
],
"verified": false,
"downloads": 0,
"stars": 0,
"created_at": "2026-05-10T00:00:00Z",
"updated_at": "2026-05-10T00:00:00Z"
},
"bugfix": {
"name": "Bugfix Workflow",
"id": "bugfix",
@@ -499,38 +467,6 @@
"created_at": "2026-04-16T00:00:00Z",
"updated_at": "2026-04-16T00:00:00Z"
},
"changelog": {
"name": "Spec Changelog",
"id": "changelog",
"description": "Auto-generate changelogs and release notes from spec git history and requirement diffs.",
"author": "Quratulain-bilal",
"version": "1.0.0",
"download_url": "https://github.com/Quratulain-bilal/spec-kit-changelog/archive/refs/tags/v1.0.0.zip",
"repository": "https://github.com/Quratulain-bilal/spec-kit-changelog",
"homepage": "https://github.com/Quratulain-bilal/spec-kit-changelog",
"documentation": "https://github.com/Quratulain-bilal/spec-kit-changelog/blob/main/README.md",
"changelog": "https://github.com/Quratulain-bilal/spec-kit-changelog/blob/main/CHANGELOG.md",
"license": "MIT",
"requires": {
"speckit_version": ">=0.4.0"
},
"provides": {
"commands": 4,
"hooks": 1
},
"tags": [
"changelog",
"release-notes",
"documentation",
"git-history",
"notifications"
],
"verified": false,
"downloads": 0,
"stars": 0,
"created_at": "2026-04-11T18:00:00Z",
"updated_at": "2026-04-11T18:00:00Z"
},
"ci-guard": {
"name": "CI Guard",
"id": "ci-guard",
@@ -1545,8 +1481,8 @@
"id": "memory-md",
"description": "Spec Kit extension for repository-native Markdown memory that captures durable decisions, bugs, and project context",
"author": "DyanGalih",
"version": "0.8.5",
"download_url": "https://github.com/DyanGalih/spec-kit-memory-hub/archive/refs/tags/v0.8.5.zip",
"version": "0.8.0",
"download_url": "https://github.com/DyanGalih/spec-kit-memory-hub/archive/refs/tags/v0.8.0.zip",
"repository": "https://github.com/DyanGalih/spec-kit-memory-hub",
"homepage": "https://github.com/DyanGalih/spec-kit-memory-hub",
"documentation": "https://github.com/DyanGalih/spec-kit-memory-hub/blob/main/README.md",
@@ -1556,8 +1492,8 @@
"speckit_version": ">=0.2.0"
},
"provides": {
"commands": 7,
"hooks": 2
"commands": 6,
"hooks": 0
},
"tags": [
"memory",
@@ -1571,7 +1507,7 @@
"downloads": 0,
"stars": 0,
"created_at": "2026-04-23T00:00:00Z",
"updated_at": "2026-05-11T14:58:00Z"
"updated_at": "2026-05-07T15:37:14Z"
},
"memorylint": {
"name": "MemoryLint",
@@ -2279,8 +2215,8 @@
"id": "security-review",
"description": "Full-project secure-by-design security audits plus staged, branch/PR, plan, task, follow-up, and apply reviews",
"author": "DyanGalih",
"version": "1.5.0",
"download_url": "https://github.com/DyanGalih/spec-kit-security-review/archive/refs/tags/v1.5.0.zip",
"version": "1.4.5",
"download_url": "https://github.com/DyanGalih/spec-kit-security-review/archive/refs/tags/v1.4.5.zip",
"repository": "https://github.com/DyanGalih/spec-kit-security-review",
"homepage": "https://github.com/DyanGalih/spec-kit-security-review",
"documentation": "https://github.com/DyanGalih/spec-kit-security-review/blob/main/README.md",
@@ -2290,8 +2226,8 @@
"speckit_version": ">=0.1.0"
},
"provides": {
"commands": 9,
"hooks": 3
"commands": 7,
"hooks": 0
},
"tags": [
"security",
@@ -2304,7 +2240,7 @@
"downloads": 0,
"stars": 0,
"created_at": "2026-04-03T03:24:03Z",
"updated_at": "2026-05-11T14:58:00Z"
"updated_at": "2026-05-06T22:28:55Z"
},
"sf": {
"name": "SFSpeckit — Salesforce Spec-Driven Development",

View File

@@ -256,43 +256,6 @@
"created_at": "2026-04-09T08:00:00Z",
"updated_at": "2026-04-27T08:00:00Z"
},
"game-narrative-writing": {
"name": "Game Narrative Writing",
"id": "game-narrative-writing",
"version": "1.0.0",
"description": "Spec-Driven Development for interactive game-narrative pre-production in video games. Authors write in a portable generic format, Twine/Sugarcube (.twee) or Ink (.ink). Covers choice-IF, visual novels, and branching dialogue. Supports Tier 1 mechanic hooks (flag, counter, inventory, timer, trust, currency, npc_state, ending_condition), multi-ending design, series carry-over variable registry, and NPC-focused character architecture.",
"author": "Andreas Daumann",
"repository": "https://github.com/adaumann/speckit-preset-game-narrative-writing",
"download_url": "https://github.com/adaumann/speckit-preset-game-narrative-writing/archive/refs/tags/v1.0.0.zip",
"homepage": "https://github.com/adaumann/speckit-preset-game-narrative-writing",
"documentation": "https://github.com/adaumann/speckit-preset-game-narrative-writing/blob/main/game-narrative-writing/README.md",
"license": "MIT",
"requires": {
"speckit_version": ">=0.5.0"
},
"provides": {
"templates": 22,
"commands": 36,
"scripts": 2
},
"tags": [
"game-writing",
"interactive-fiction",
"twine",
"ink",
"renpy",
"point-and-click",
"branching-narrative",
"choice-if",
"visual-novel",
"mechanic-hooks",
"game-narrative",
"export",
"series"
],
"created_at": "2026-05-05T08:00:00Z",
"updated_at": "2026-05-05T08:00:00Z"
},
"isaqb-architecture-governance": {
"name": "iSAQB Architecture Governance",
"id": "isaqb-architecture-governance",

View File

@@ -1,6 +1,6 @@
[project]
name = "specify-cli"
version = "0.8.9"
version = "0.8.8"
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
requires-python = ">=3.11"
dependencies = [

View File

@@ -1,180 +0,0 @@
"""Shared catalog stack config primitives.
Catalog-backed features use the same local config shape and URL validation
rules. This module keeps those narrow primitives in one place while individual
catalog types keep their active source resolution, fetch, cache, and
domain-specific validation behavior.
"""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import ClassVar
import yaml
@dataclass
class CatalogEntry:
"""Represents a single catalog source in a catalog stack."""
url: str
name: str
priority: int
install_allowed: bool
description: str = ""
class CatalogStackBase:
"""Base class for ordered catalog-source resolution.
Subclasses provide catalog-specific metadata and exception classes. Fetching
and schema validation stay in each concrete catalog because those formats
differ across integrations, extensions, presets, and workflows.
"""
ENTRY_CLASS: ClassVar[type[CatalogEntry]] = CatalogEntry
ERROR_TYPE: ClassVar[type[Exception]] = ValueError
VALIDATION_ERROR_TYPE: ClassVar[type[Exception]] = ValueError
CONFIG_FILENAME: ClassVar[str]
@classmethod
def _error(cls, message: str) -> Exception:
return cls.ERROR_TYPE(message)
@classmethod
def _validation_error(cls, message: str) -> Exception:
return cls.VALIDATION_ERROR_TYPE(message)
@classmethod
def _entry(
cls,
*,
url: str,
name: str,
priority: int,
install_allowed: bool,
description: str = "",
) -> CatalogEntry:
return cls.ENTRY_CLASS(
url=url,
name=name,
priority=priority,
install_allowed=install_allowed,
description=description,
)
@classmethod
def _validate_catalog_url(cls, url: str) -> None:
"""Validate that a catalog URL uses HTTPS, except localhost HTTP."""
from urllib.parse import urlparse
parsed = urlparse(url)
is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
if parsed.scheme != "https" and not (parsed.scheme == "http" and is_localhost):
raise cls._error(
f"Catalog URL must use HTTPS (got {parsed.scheme}://). "
"HTTP is only allowed for localhost."
)
if not parsed.netloc:
raise cls._error("Catalog URL must be a valid URL with a host.")
def _load_catalog_config(self, config_path: Path) -> list[CatalogEntry] | None:
"""Load catalog stack configuration from a YAML file.
Returns ``None`` when the file does not exist. Existing files fail
closed when they are malformed, empty, or contain no usable URLs.
"""
if not config_path.exists():
return None
try:
data = yaml.safe_load(config_path.read_text(encoding="utf-8"))
except (yaml.YAMLError, OSError, UnicodeError) as exc:
raise self._validation_error(
f"Failed to read catalog config {config_path}: {exc}"
) from exc
if data is None:
data = {}
if not isinstance(data, dict):
raise self._validation_error(
f"Invalid catalog config {config_path}: expected a YAML mapping at the root"
)
catalogs_data = data.get("catalogs", [])
if not isinstance(catalogs_data, list):
raise self._validation_error(
f"Invalid catalog config {config_path}: 'catalogs' must be a list, "
f"got {type(catalogs_data).__name__}"
)
if not catalogs_data:
raise self._validation_error(
f"Catalog config {config_path} exists but contains no 'catalogs' entries. "
f"Remove the file to use built-in defaults, or add valid catalog entries."
)
entries: list[CatalogEntry] = []
skipped: list[int] = []
for idx, item in enumerate(catalogs_data):
if not isinstance(item, dict):
raise self._validation_error(
f"Invalid catalog config {config_path}: catalog entry at index {idx}: "
f"expected a mapping, got {type(item).__name__}"
)
url = str(item.get("url", "")).strip()
if not url:
skipped.append(idx)
continue
try:
self._validate_catalog_url(url)
except self.ERROR_TYPE as exc:
raise self._validation_error(
f"Invalid catalog URL in {config_path} at index {idx}: {exc}"
) from exc
raw_priority = item.get("priority", idx + 1)
if isinstance(raw_priority, bool):
raise self._validation_error(
f"Invalid catalog config {config_path}: "
f"Invalid priority for catalog '{item.get('name', idx + 1)}': "
f"expected integer, got {raw_priority!r}"
)
try:
priority = int(raw_priority)
except (TypeError, ValueError):
raise self._validation_error(
f"Invalid catalog config {config_path}: "
f"Invalid priority for catalog '{item.get('name', idx + 1)}': "
f"expected integer, got {raw_priority!r}"
)
raw_install = item.get("install_allowed", False)
if isinstance(raw_install, str):
install_allowed = raw_install.strip().lower() in ("true", "yes", "1")
else:
install_allowed = bool(raw_install)
raw_name = item.get("name")
name = str(raw_name).strip() if raw_name is not None else ""
if not name:
name = f"catalog-{len(entries) + 1}"
entries.append(
self._entry(
url=url,
name=name,
priority=priority,
install_allowed=install_allowed,
description=str(item.get("description", "")),
)
)
entries.sort(key=lambda e: e.priority)
if not entries:
raise self._validation_error(
f"Catalog config {config_path} contains {len(catalogs_data)} "
f"entries but none have valid URLs (entries at indices {skipped} "
f"were skipped). Each catalog entry must have a 'url' field."
)
return entries

View File

@@ -21,8 +21,6 @@ from typing import Any, Dict, List, Optional, Tuple
import yaml
from packaging import version as pkg_version
from ..catalogs import CatalogEntry, CatalogStackBase
# ---------------------------------------------------------------------------
# Errors
@@ -45,15 +43,21 @@ class IntegrationDescriptorError(Exception):
# ---------------------------------------------------------------------------
@dataclass
class IntegrationCatalogEntry(CatalogEntry):
class IntegrationCatalogEntry:
"""Represents a single catalog source in the catalog stack."""
url: str
name: str
priority: int
install_allowed: bool
description: str = ""
# ---------------------------------------------------------------------------
# IntegrationCatalog
# ---------------------------------------------------------------------------
class IntegrationCatalog(CatalogStackBase):
class IntegrationCatalog:
"""Manages integration catalog fetching, caching, and searching."""
DEFAULT_CATALOG_URL = (
@@ -63,15 +67,136 @@ class IntegrationCatalog(CatalogStackBase):
"https://raw.githubusercontent.com/github/spec-kit/main/integrations/catalog.community.json"
)
CACHE_DURATION = 3600 # 1 hour
CONFIG_FILENAME = "integration-catalogs.yml"
ENTRY_CLASS = IntegrationCatalogEntry
ERROR_TYPE = IntegrationCatalogError
VALIDATION_ERROR_TYPE = IntegrationValidationError
def __init__(self, project_root: Path) -> None:
self.project_root = project_root
self.cache_dir = project_root / ".specify" / "integrations" / ".cache"
# -- URL validation ---------------------------------------------------
@staticmethod
def _validate_catalog_url(url: str) -> None:
from urllib.parse import urlparse
parsed = urlparse(url)
is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
if parsed.scheme != "https" and not (parsed.scheme == "http" and is_localhost):
raise IntegrationCatalogError(
f"Catalog URL must use HTTPS (got {parsed.scheme}://). "
"HTTP is only allowed for localhost."
)
if not parsed.netloc:
raise IntegrationCatalogError(
"Catalog URL must be a valid URL with a host."
)
# -- Catalog stack ----------------------------------------------------
def _load_catalog_config(
self, config_path: Path
) -> Optional[List[IntegrationCatalogEntry]]:
"""Load catalog stack from a YAML file.
Returns None when the file does not exist.
Raises:
IntegrationValidationError: on any local-config / YAML problem
(parse failures, wrong shape, missing/invalid fields,
invalid catalog URLs, etc.). This is a subclass of
:class:`IntegrationCatalogError`, so any caller that already
catches ``IntegrationCatalogError`` keeps working — but
callers that want to distinguish *local config* problems
from *remote/network* problems can match the subclass.
"""
if not config_path.exists():
return None
try:
data = yaml.safe_load(config_path.read_text(encoding="utf-8"))
except (yaml.YAMLError, OSError, UnicodeError) as exc:
raise IntegrationValidationError(
f"Failed to read catalog config {config_path}: {exc}"
) from exc
if data is None:
data = {}
if not isinstance(data, dict):
raise IntegrationValidationError(
f"Invalid catalog config {config_path}: expected a YAML mapping at the root"
)
catalogs_data = data.get("catalogs", [])
if not isinstance(catalogs_data, list):
raise IntegrationValidationError(
f"Invalid catalog config {config_path}: 'catalogs' must be a list, "
f"got {type(catalogs_data).__name__}"
)
if not catalogs_data:
raise IntegrationValidationError(
f"Catalog config {config_path} exists but contains no 'catalogs' entries. "
f"Remove the file to use built-in defaults, or add valid catalog entries."
)
entries: List[IntegrationCatalogEntry] = []
skipped: List[int] = []
for idx, item in enumerate(catalogs_data):
if not isinstance(item, dict):
raise IntegrationValidationError(
f"Invalid catalog config {config_path}: catalog entry at index {idx}: "
f"expected a mapping, got {type(item).__name__}"
)
url = str(item.get("url", "")).strip()
if not url:
skipped.append(idx)
continue
try:
self._validate_catalog_url(url)
except IntegrationCatalogError as exc:
# ``_validate_catalog_url`` raises the base class for direct
# callers (e.g. ``add_catalog`` validating user input); when
# the bad URL came from a local config file, surface it as a
# validation error so CLI handlers can route it accordingly.
raise IntegrationValidationError(
f"Invalid catalog URL in {config_path} at index {idx}: {exc}"
) from exc
raw_priority = item.get("priority", idx + 1)
if isinstance(raw_priority, bool):
raise IntegrationValidationError(
f"Invalid catalog config {config_path}: "
f"Invalid priority for catalog '{item.get('name', idx + 1)}': "
f"expected integer, got {raw_priority!r}"
)
try:
priority = int(raw_priority)
except (TypeError, ValueError):
raise IntegrationValidationError(
f"Invalid catalog config {config_path}: "
f"Invalid priority for catalog '{item.get('name', idx + 1)}': "
f"expected integer, got {raw_priority!r}"
)
raw_install = item.get("install_allowed", False)
if isinstance(raw_install, str):
install_allowed = raw_install.strip().lower() in ("true", "yes", "1")
else:
install_allowed = bool(raw_install)
raw_name = item.get("name")
name = str(raw_name).strip() if raw_name is not None else ""
if not name:
name = f"catalog-{len(entries) + 1}"
entries.append(
IntegrationCatalogEntry(
url=url,
name=name,
priority=priority,
install_allowed=install_allowed,
description=str(item.get("description", "")),
)
)
entries.sort(key=lambda e: e.priority)
if not entries:
raise IntegrationValidationError(
f"Catalog config {config_path} contains {len(catalogs_data)} "
f"entries but none have valid URLs (entries at indices {skipped} "
f"were skipped). Each catalog entry must have a 'url' field."
)
return entries
def get_active_catalogs(self) -> List[IntegrationCatalogEntry]:
"""Return the ordered list of active integration catalogs.
@@ -319,6 +444,8 @@ class IntegrationCatalog(CatalogStackBase):
# -- Catalog-source management ----------------------------------------
CONFIG_FILENAME = "integration-catalogs.yml"
def get_catalog_configs(self) -> List[Dict[str, Any]]:
"""Return the active catalog stack as a list of dicts.

View File

@@ -3,14 +3,6 @@
from ..base import MarkdownIntegration
# Kiro CLI file-based prompts do NOT support any argument-substitution syntax,
# so a raw "$ARGUMENTS" token would reach the model verbatim and break the
# prompt (issue #1926, kirodotdev/Kiro#4141). Use a prose fallback so the
# rendered prompt instructs the model to take its argument from the user's
# next message.
_KIRO_ARG_FALLBACK = "(the user will provide the argument in this conversation)"
class KiroCliIntegration(MarkdownIntegration):
key = "kiro-cli"
config = {
@@ -23,7 +15,7 @@ class KiroCliIntegration(MarkdownIntegration):
registrar_config = {
"dir": ".kiro/prompts",
"format": "markdown",
"args": _KIRO_ARG_FALLBACK,
"args": "$ARGUMENTS",
"extension": ".md",
}
context_file = "AGENTS.md"

View File

@@ -1,7 +1,6 @@
# Implementation Plan: [FEATURE]
**Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
**Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
**Note**: This template is filled in by the `__SPECKIT_COMMAND_PLAN__` command. See `.specify/templates/plan-template.md` for the execution workflow.
@@ -18,22 +17,14 @@
the iteration process.
-->
**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
**Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
**Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION]
**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
**Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION]
**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
**Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
## Constitution Check

View File

@@ -1,11 +1,8 @@
# Feature Specification: [FEATURE NAME]
**Feature Branch**: `[###-feature-name]`
**Created**: [DATE]
**Status**: Draft
**Feature Branch**: `[###-feature-name]`
**Created**: [DATE]
**Status**: Draft
**Input**: User description: "$ARGUMENTS"
## User Scenarios & Testing *(mandatory)*
@@ -14,7 +11,7 @@
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
you should still have a viable MVP (Minimum Viable Product) that delivers value.
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
Think of each story as a standalone slice of functionality that can be:
- Developed independently
@@ -88,7 +85,7 @@
### Functional Requirements
- **FR-001**: System MUST [specific capability, e.g., "allow users to create accounts"]
- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"]
- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"]
- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"]
- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"]
- **FR-005**: System MUST [behavior, e.g., "log all security events"]

View File

@@ -6,7 +6,6 @@ description: "Task list template for feature implementation"
# Tasks: [FEATURE NAME]
**Input**: Design documents from `/specs/[###-feature-name]/`
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
**Tests**: The examples below include test tasks. Tests are OPTIONAL - only include them if explicitly requested in the feature specification.
@@ -26,21 +25,21 @@ description: "Task list template for feature implementation"
- **Mobile**: `api/src/`, `ios/src/` or `android/src/`
- Paths shown below assume single project - adjust based on plan.md structure
<!--
<!--
============================================================================
IMPORTANT: The tasks below are SAMPLE TASKS for illustration purposes only.
The __SPECKIT_COMMAND_TASKS__ command MUST replace these with actual tasks based on:
- User stories from spec.md (with their priorities P1, P2, P3...)
- Feature requirements from plan.md
- Entities from data-model.md
- Endpoints from contracts/
Tasks MUST be organized by user story so each story can be:
- Implemented independently
- Tested independently
- Delivered as an MVP increment
DO NOT keep these sample tasks in the generated tasks.md file.
============================================================================
-->

View File

@@ -1,41 +1,10 @@
"""Tests for KiroCliIntegration."""
import os
import re
from specify_cli.integrations import get_integration
from specify_cli.integrations.kiro_cli import _KIRO_ARG_FALLBACK
from specify_cli.integrations.manifest import IntegrationManifest
from .test_integration_base_markdown import MarkdownIntegrationTests
# Regex shapes that indicate a value is a placeholder token, not prose.
# Covers Bash ($VAR, ${VAR}, ${VAR:-default}), Mustache/Handlebars/Jinja
# ({{var}}, {{{var}}}), Liquid/Jinja control ({% ... %}), Python str.format /
# .NET ({var}, {0}), angle-bracket (<var>), and Windows-style (%VAR%).
# Anchored to the FULL STRING so legitimate prose mentioning a placeholder
# (e.g. "the {{magic}} of placeholders") is not flagged. The Liquid pattern
# is anchored to the START so multi-tag templates fire while mid-sentence
# {%-quotation does not.
_PLACEHOLDER_TOKEN_PATTERNS = (
re.compile(r"^\$\w+$"), # $ARGUMENTS, $args
re.compile(r"^\$\{\w+(?:[:\-+?][^}]*)?\}$"), # ${ARGS}, ${ARGS:-default}
re.compile(r"^\{\{\{?\s*\w+(\s*[|.][^}]*)?\s*\}?\}\}$"), # {{var}} {{{var}}} {{x|y}}
re.compile(r"^\{%"), # {% if x %}{{ x }}{% endif %}
re.compile(r"^<\w+>$"), # <args>
re.compile(r"^%\w+%$"), # %USERNAME%
re.compile(r"^\{(?:\d+|[a-zA-Z_]\w*)(?:[.\[][^}]*)?(?:![rsa])?(?::[^}]*)?\}$"), # {0}, {var}, {0:>5}
)
def _looks_like_placeholder_token(value: str) -> bool:
"""Return True if *value* matches a known placeholder-token shape."""
if not value:
return False
return any(p.search(value) for p in _PLACEHOLDER_TOKEN_PATTERNS)
class TestKiroCliIntegration(MarkdownIntegrationTests):
KEY = "kiro-cli"
FOLDER = ".kiro/"
@@ -43,85 +12,6 @@ class TestKiroCliIntegration(MarkdownIntegrationTests):
REGISTRAR_DIR = ".kiro/prompts"
CONTEXT_FILE = "AGENTS.md"
def test_registrar_config(self):
"""Override base assertion: kiro-cli uses a prose fallback for args
because Kiro CLI file-based prompts do not natively substitute
``$ARGUMENTS`` (see issue #1926 / kirodotdev/Kiro#4141). The
regression-guard load is carried by the two layer tests below
(exact-fallback + placeholder-shape rejection)."""
i = get_integration(self.KEY)
assert i.registrar_config["dir"] == self.REGISTRAR_DIR
assert i.registrar_config["format"] == "markdown"
assert i.registrar_config["extension"] == ".md"
def test_registrar_config_args_is_exact_prose_fallback(self):
"""Layer 1 — pin the exact fallback so wording drift requires a
deliberate paired commit (production constant + test update)."""
i = get_integration(self.KEY)
assert i.registrar_config["args"] == _KIRO_ARG_FALLBACK, (
f"args drifted from the pinned fallback constant. "
f"Got: {i.registrar_config['args']!r}; expected: {_KIRO_ARG_FALLBACK!r}. "
f"If the wording change is intentional, update _KIRO_ARG_FALLBACK and "
f"this test together."
)
def test_registrar_config_args_does_not_look_like_a_placeholder_token(self):
"""Layer 2 — independent regression guard: even if someone bypasses
layer-1 by changing both constant and test, the value still must not
look like ANY placeholder token shape ($X, ${X}, {{X}}, <X>, %X%, {0},
{% %}). Catches the class of regression Copilot called out: a swap
from $ARGUMENTS to $INPUT or {{userMessage}} would fail this test
even if it accidentally passed layer 1."""
i = get_integration(self.KEY)
args = i.registrar_config["args"]
assert not _looks_like_placeholder_token(args), (
f"registrar_config['args'] = {args!r} matches a known placeholder-"
f"token shape — Kiro CLI does not substitute placeholders so this "
f"would reach the model verbatim and break the prompt (issue #1926). "
f"Use a prose fallback instead."
)
def test_rendered_prompts_do_not_contain_raw_arguments(self, tmp_path):
"""Rendered Kiro prompt files must NOT contain the raw ``$ARGUMENTS``
token — Kiro CLI does not substitute it, so the literal would reach
the model and break the prompt (issue #1926)."""
integration = get_integration(self.KEY)
manifest = IntegrationManifest(self.KEY, tmp_path)
integration.setup(tmp_path, manifest, script_type="sh")
prompts_dir = tmp_path / self.REGISTRAR_DIR
rendered = list(prompts_dir.glob("*.md"))
assert rendered, "expected at least one rendered prompt file"
offenders = [
p.name for p in rendered if "$ARGUMENTS" in p.read_text(encoding="utf-8")
]
assert offenders == [], (
f"these rendered prompts still contain the raw $ARGUMENTS token: {offenders}"
)
def test_rendered_prompts_contain_kiro_arg_placeholder(self, tmp_path):
"""The chosen kiro-cli args fallback string must end up in at least
one rendered prompt (proves substitution actually fired, not just
that $ARGUMENTS was removed). Imports the fallback constant directly
instead of reading the field back so the test stays independent of
the integration's own config — even if the registrar_config['args']
regresses, this test still verifies the FALLBACK STRING is in the
rendered output."""
integration = get_integration(self.KEY)
manifest = IntegrationManifest(self.KEY, tmp_path)
integration.setup(tmp_path, manifest, script_type="sh")
expected = _KIRO_ARG_FALLBACK
prompts_dir = tmp_path / self.REGISTRAR_DIR
contents = "\n".join(
p.read_text(encoding="utf-8") for p in prompts_dir.glob("*.md")
)
assert expected in contents, (
f"none of the rendered prompts contain the configured args fallback "
f"({expected!r})"
)
class TestKiroAlias:
"""--ai kiro alias normalizes to kiro-cli and auto-promotes."""

View File

@@ -1949,16 +1949,7 @@ def install_self_test_preset(manager: PresetManager, speckit_version: str = "0.1
class TestSelfTestPreset:
"""Tests using the self-test preset that ships with the repo.
The self-test preset ships a wrap-strategy command (``speckit.wrap-test``)
without a corresponding core base layer; reconciliation deliberately
surfaces a UserWarning in that case. Tests install via
``install_self_test_preset`` (defined above), which scopes a narrow
``warnings.filterwarnings`` block to that specific message and
``UserWarning`` category — so the expected warning stays quiet without
masking unrelated warnings or real reconciliation failures.
"""
"""Tests using the self-test preset that ships with the repo."""
def test_self_test_preset_exists(self):
"""Verify the self-test preset directory and manifest exist."""
@@ -2246,12 +2237,7 @@ class TestInitOptions:
class TestPresetSkills:
"""Tests for preset skill registration and unregistration.
Tests that install the self-test preset use ``install_self_test_preset``
which scopes a narrow filter to the expected wrap-strategy warning.
Reconciliation failures remain audible so real regressions surface.
"""
"""Tests for preset skill registration and unregistration."""
def _write_init_options(self, project_dir, ai="claude", ai_skills=True, script="sh"):
from specify_cli import save_init_options