Files
github-spec-kit/integrations/CONTRIBUTING.md
Copilot 282dd3da56 feat: Integration catalog — discovery, versioning, and community distribution (#2130)
* Initial plan

* feat: add integration catalog system with catalog files, IntegrationCatalog class, list --catalog flag, upgrade command, integration.yml descriptor, and tests

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/bbcd44e8-c69c-4735-adc1-bdf1ce109184

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* fix: address PR review feedback

- Replace empty except with cache cleanup in _fetch_single_catalog
- Log teardown failure warning instead of silent pass in upgrade
- Validate catalog_data and integrations are dicts before use
- Catch OSError/UnicodeError in IntegrationDescriptor._load
- Add isinstance checks for integration/requires/provides/commands
- Enforce semver (X.Y.Z) instead of PEP 440 for descriptor versions
- Fix docstring and CONTRIBUTING.md to match actual block-on-modified behavior
- Restore old manifest on upgrade failure for transactional safety

* refactor: address second round of PR review feedback

- Remove dead cache_file/cache_metadata_file attributes from IntegrationCatalog
- Deduplicate non-default catalog warning (show once per process)
- Anchor version regex to reject partial matches like 1.0.0beta
- Fix 'Preserved modified' message to 'Skipped' for accuracy
- Make upgrade transactional: install new files first, then remove stale
  old-only files, so a failed setup leaves old integration intact
- Update CONTRIBUTING.md: speckit_version validates presence only

* Potential fix for pull request finding 'Empty except'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* fix: address third round of PR review feedback

- Fix CONTRIBUTING.md JSON examples to show full catalog structure with
  schema_version and integrations wrapper
- Wrap cache writes in try/except OSError for read-only project dirs
- Validate _load_catalog_config YAML root is a dict
- Skip non-dict integ_data entries in merged catalog
- Normalize tags to list-of-strings before filtering/searching
- Add path traversal containment check for stale file deletion
- Clarify docstring: lower numeric priority = higher precedence

* fix: address fourth round of PR review feedback

- Remove unused _write_catalog helper from test file
- Fix comment: tests use monkeypatched urlopen, not file:// URLs
- Wrap cache unlink calls in OSError handler
- Add explicit encoding='utf-8' to all cache read_text/write_text calls
- Restore packaging.version.Version for descriptor version validation
  to align with extension/preset validators
- Add missing goose entry to integrations/catalog.json

* fix: remove unused Path import, add comment to empty except

* fix: validate descriptor root is dict, add shared infra to upgrade

- Add isinstance(self.data, dict) check at start of _validate() so
  non-mapping YAML roots raise IntegrationDescriptorError
- Run _install_shared_infra() and ensure_executable_scripts() in
  upgrade command to match install/switch behavior

* fix: address sixth round of PR review feedback

- Validate integration.id/name/version/description are strings
- Catch TypeError in pkg_version.Version() for non-string versions
- Swap validation order: check catalogs type before emptiness
- Isolate TestActiveCatalogs from user ~/.specify/ via monkeypatch

* fix: address seventh round of PR review feedback

- Update docs: version field uses PEP 440, not semver
- Harden search() against non-string author/name/description fields
- Validate requires.speckit_version is a non-empty string
- Validate command name/file are non-empty strings, file is safe relative path
- Handle stale symlinks in upgrade cleanup
- Document catalog configuration stack in README.md

* fix: validate script entries, remove destructive teardown from upgrade rollback

- Validate provides.scripts entries are non-empty strings with safe relative paths
- Remove teardown from upgrade rollback since setup overwrites in-place —
  teardown would delete files that were working before the upgrade

* fix: use consistent resolved root for stale-file cleanup paths

* fix: validate redirect URL and reject drive-qualified paths

- Validate final URL after redirects with _validate_catalog_url()
- Reject paths with Path.drive or Path.anchor for Windows safety
- Update FakeResponse mocks with geturl() method

* fix: fix docstring backticks, assert file modification in upgrade tests

* docs: clarify directory naming convention for hyphenated integration keys

* fix: correct key type hint, isolate all catalog tests from env

- Fix key parameter type to str | None (defaults to None)
- Add HOME/USERPROFILE monkeypatch and clear SPECKIT_INTEGRATION_CATALOG_URL
  in all TestCatalogFetch tests for full environment isolation

* fix: neutralize catalog table title, handle non-dict cache metadata

* fix: validate requires.tools entries in descriptor

* fix: show discovery-only status, clear metadata files in clear_cache

* fix: catch OSError/UnicodeError in cache read path

* refactor: reuse IntegrationManifest.uninstall for stale-file cleanup

* fix: normalize null tools to empty list in descriptor accessor

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-04-16 08:59:32 -05:00

143 lines
4.6 KiB
Markdown

# Contributing to the Integration Catalog
This guide covers adding integrations to both the **built-in** and **community** catalogs.
## Adding a Built-In Integration
Built-in integrations are maintained by the Spec Kit core team and ship with the CLI.
### Checklist
1. **Create the integration subpackage** under `src/specify_cli/integrations/<package_dir>/`
`<package_dir>` matches the integration key when it contains no hyphens (e.g., `gemini`), or replaces hyphens with underscores when it does (e.g., key `cursor-agent` → directory `cursor_agent/`, key `kiro-cli` → directory `kiro_cli/`). Python package names cannot use hyphens.
2. **Implement the integration class** extending `MarkdownIntegration`, `TomlIntegration`, or `SkillsIntegration`
3. **Register the integration** in `src/specify_cli/integrations/__init__.py`
4. **Add tests** under `tests/integrations/test_integration_<package_dir>.py`
5. **Add a catalog entry** in `integrations/catalog.json`
6. **Update documentation** in `AGENTS.md` and `README.md`
### Catalog Entry Format
Add your integration under the top-level `integrations` key in `integrations/catalog.json`:
```json
{
"schema_version": "1.0",
"integrations": {
"my-agent": {
"id": "my-agent",
"name": "My Agent",
"version": "1.0.0",
"description": "Integration for My Agent",
"author": "spec-kit-core",
"repository": "https://github.com/github/spec-kit",
"tags": ["cli"]
}
}
}
```
## Adding a Community Integration
Community integrations are contributed by external developers and listed in `integrations/catalog.community.json` for discovery.
### Prerequisites
1. **Working integration** — tested with `specify integration install`
2. **Public repository** — hosted on GitHub or similar
3. **`integration.yml` descriptor** — valid descriptor file (see below)
4. **Documentation** — README with usage instructions
5. **License** — open source license file
### `integration.yml` Descriptor
Every community integration must include an `integration.yml`:
```yaml
schema_version: "1.0"
integration:
id: "my-agent"
name: "My Agent"
version: "1.0.0"
description: "Integration for My Agent"
author: "your-name"
repository: "https://github.com/your-name/speckit-my-agent"
license: "MIT"
requires:
speckit_version: ">=0.6.0"
tools:
- name: "my-agent"
version: ">=1.0.0"
required: true
provides:
commands:
- name: "speckit.specify"
file: "templates/speckit.specify.md"
scripts:
- update-context.sh
```
### Descriptor Validation Rules
| Field | Rule |
|-------|------|
| `schema_version` | Must be `"1.0"` |
| `integration.id` | Lowercase alphanumeric + hyphens (`^[a-z0-9-]+$`) |
| `integration.version` | Valid PEP 440 version (parsed with `packaging.version.Version()`) |
| `requires.speckit_version` | Required field; specify a version constraint such as `>=0.6.0` (current validation checks presence only) |
| `provides` | Must include at least one command or script |
| `provides.commands[].name` | String identifier |
| `provides.commands[].file` | Relative path to template file |
### Submitting to the Community Catalog
1. **Fork** the [spec-kit repository](https://github.com/github/spec-kit)
2. **Add your entry** under the `integrations` key in `integrations/catalog.community.json`:
```json
{
"schema_version": "1.0",
"integrations": {
"my-agent": {
"id": "my-agent",
"name": "My Agent",
"version": "1.0.0",
"description": "Integration for My Agent",
"author": "your-name",
"repository": "https://github.com/your-name/speckit-my-agent",
"tags": ["cli"]
}
}
}
```
3. **Open a pull request** with:
- Your catalog entry
- Link to your integration repository
- Confirmation that `integration.yml` is valid
### Version Updates
To update your integration version in the catalog:
1. Release a new version of your integration
2. Open a PR updating the `version` field in `catalog.community.json`
3. Ensure backward compatibility or document breaking changes
## Upgrade Workflow
The `specify integration upgrade` command supports diff-aware upgrades:
1. **Hash comparison** — the manifest records SHA-256 hashes of all installed files
2. **Modified file detection** — files changed since installation are flagged
3. **Safe default** — the upgrade blocks if any installed files were modified since installation
4. **Forced reinstall** — passing `--force` overwrites modified files with the latest version
```bash
# Upgrade current integration (blocks if files are modified)
specify integration upgrade
# Force upgrade (overwrites modified files)
specify integration upgrade --force
```