mirror of
https://github.com/github/spec-kit.git
synced 2026-03-17 02:43:08 +00:00
docs: update RFC, user guide, and API reference for multi-catalog support
- RFC: replace FUTURE FEATURE section with full implementation docs, add catalog stack resolution order, config file examples, merge conflict resolution, and install_allowed behavior - EXTENSION-USER-GUIDE.md: add multi-catalog section with CLI examples for catalogs/catalog-add/catalog-remove, update catalog config docs - EXTENSION-API-REFERENCE.md: add CatalogEntry class docs, update ExtensionCatalog docs with new methods and result annotations, add catalog CLI commands (catalogs, catalog add, catalog remove) Also fix extension_catalogs command to correctly show "Using built-in default catalog stack" when config file exists but has empty catalogs Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
This commit is contained in:
committed by
Manfred Riem
parent
50c605ed5f
commit
ad591607ea
@@ -243,6 +243,32 @@ manager.check_compatibility(
|
|||||||
) # Raises: CompatibilityError if incompatible
|
) # Raises: CompatibilityError if incompatible
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### CatalogEntry
|
||||||
|
|
||||||
|
**Module**: `specify_cli.extensions`
|
||||||
|
|
||||||
|
Represents a single catalog in the active catalog stack.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from specify_cli.extensions import CatalogEntry
|
||||||
|
|
||||||
|
entry = CatalogEntry(
|
||||||
|
url="https://example.com/catalog.json",
|
||||||
|
name="org-approved",
|
||||||
|
priority=1,
|
||||||
|
install_allowed=True,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fields**:
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `url` | `str` | Catalog URL (must use HTTPS, or HTTP for localhost) |
|
||||||
|
| `name` | `str` | Human-readable catalog name |
|
||||||
|
| `priority` | `int` | Sort order (lower = higher priority, wins on conflicts) |
|
||||||
|
| `install_allowed` | `bool` | Whether extensions from this catalog can be installed |
|
||||||
|
|
||||||
### ExtensionCatalog
|
### ExtensionCatalog
|
||||||
|
|
||||||
**Module**: `specify_cli.extensions`
|
**Module**: `specify_cli.extensions`
|
||||||
@@ -253,30 +279,65 @@ from specify_cli.extensions import ExtensionCatalog
|
|||||||
catalog = ExtensionCatalog(project_root)
|
catalog = ExtensionCatalog(project_root)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Class attributes**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
ExtensionCatalog.DEFAULT_CATALOG_URL # org-approved catalog URL
|
||||||
|
ExtensionCatalog.COMMUNITY_CATALOG_URL # community catalog URL
|
||||||
|
```
|
||||||
|
|
||||||
**Methods**:
|
**Methods**:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Fetch catalog
|
# Get the ordered list of active catalogs
|
||||||
|
entries = catalog.get_active_catalogs() # List[CatalogEntry]
|
||||||
|
|
||||||
|
# Fetch catalog (primary catalog, backward compat)
|
||||||
catalog_data = catalog.fetch_catalog(force_refresh: bool = False) # Dict
|
catalog_data = catalog.fetch_catalog(force_refresh: bool = False) # Dict
|
||||||
|
|
||||||
# Search extensions
|
# Search extensions across all active catalogs
|
||||||
|
# Each result includes _catalog_name and _install_allowed
|
||||||
results = catalog.search(
|
results = catalog.search(
|
||||||
query: Optional[str] = None,
|
query: Optional[str] = None,
|
||||||
tag: Optional[str] = None,
|
tag: Optional[str] = None,
|
||||||
author: Optional[str] = None,
|
author: Optional[str] = None,
|
||||||
verified_only: bool = False
|
verified_only: bool = False
|
||||||
) # Returns: List[Dict]
|
) # Returns: List[Dict] — each dict includes _catalog_name, _install_allowed
|
||||||
|
|
||||||
# Get extension info
|
# Get extension info (searches all active catalogs)
|
||||||
|
# Returns None if not found; includes _catalog_name and _install_allowed
|
||||||
ext_info = catalog.get_extension_info(extension_id: str) # Optional[Dict]
|
ext_info = catalog.get_extension_info(extension_id: str) # Optional[Dict]
|
||||||
|
|
||||||
# Check cache validity
|
# Check cache validity (primary catalog)
|
||||||
is_valid = catalog.is_cache_valid() # bool
|
is_valid = catalog.is_cache_valid() # bool
|
||||||
|
|
||||||
# Clear cache
|
# Clear all catalog caches
|
||||||
catalog.clear_cache()
|
catalog.clear_cache()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Result annotation fields**:
|
||||||
|
|
||||||
|
Each extension dict returned by `search()` and `get_extension_info()` includes:
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `_catalog_name` | `str` | Name of the source catalog |
|
||||||
|
| `_install_allowed` | `bool` | Whether installation is allowed from this catalog |
|
||||||
|
|
||||||
|
**Catalog config file** (`.specify/extension-catalogs.yml`):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
catalogs:
|
||||||
|
- name: "org-approved"
|
||||||
|
url: "https://example.com/catalog.json"
|
||||||
|
priority: 1
|
||||||
|
install_allowed: true
|
||||||
|
- name: "community"
|
||||||
|
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json"
|
||||||
|
priority: 2
|
||||||
|
install_allowed: false
|
||||||
|
```
|
||||||
|
|
||||||
### HookExecutor
|
### HookExecutor
|
||||||
|
|
||||||
**Module**: `specify_cli.extensions`
|
**Module**: `specify_cli.extensions`
|
||||||
@@ -543,6 +604,38 @@ EXECUTE_COMMAND: {command}
|
|||||||
|
|
||||||
**Output**: List of installed extensions with metadata
|
**Output**: List of installed extensions with metadata
|
||||||
|
|
||||||
|
### extension catalogs
|
||||||
|
|
||||||
|
**Usage**: `specify extension catalogs`
|
||||||
|
|
||||||
|
Lists all active catalogs in the current catalog stack, showing name, URL, priority, and `install_allowed` status.
|
||||||
|
|
||||||
|
### extension catalog add
|
||||||
|
|
||||||
|
**Usage**: `specify extension catalog add URL [OPTIONS]`
|
||||||
|
|
||||||
|
**Options**:
|
||||||
|
|
||||||
|
- `--name NAME` - Catalog name (required)
|
||||||
|
- `--priority INT` - Priority (lower = higher priority, default: 10)
|
||||||
|
- `--install-allowed / --no-install-allowed` - Allow installs from this catalog (default: false)
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `URL` - Catalog URL (must use HTTPS)
|
||||||
|
|
||||||
|
Adds a catalog entry to `.specify/extension-catalogs.yml`.
|
||||||
|
|
||||||
|
### extension catalog remove
|
||||||
|
|
||||||
|
**Usage**: `specify extension catalog remove NAME`
|
||||||
|
|
||||||
|
**Arguments**:
|
||||||
|
|
||||||
|
- `NAME` - Catalog name to remove
|
||||||
|
|
||||||
|
Removes a catalog entry from `.specify/extension-catalogs.yml`.
|
||||||
|
|
||||||
### extension add
|
### extension add
|
||||||
|
|
||||||
**Usage**: `specify extension add EXTENSION [OPTIONS]`
|
**Usage**: `specify extension add EXTENSION [OPTIONS]`
|
||||||
@@ -551,13 +644,13 @@ EXECUTE_COMMAND: {command}
|
|||||||
|
|
||||||
- `--from URL` - Install from custom URL
|
- `--from URL` - Install from custom URL
|
||||||
- `--dev PATH` - Install from local directory
|
- `--dev PATH` - Install from local directory
|
||||||
- `--version VERSION` - Install specific version
|
|
||||||
- `--no-register` - Skip command registration
|
|
||||||
|
|
||||||
**Arguments**:
|
**Arguments**:
|
||||||
|
|
||||||
- `EXTENSION` - Extension name or URL
|
- `EXTENSION` - Extension name or URL
|
||||||
|
|
||||||
|
**Note**: Extensions from catalogs with `install_allowed: false` cannot be installed via this command.
|
||||||
|
|
||||||
### extension remove
|
### extension remove
|
||||||
|
|
||||||
**Usage**: `specify extension remove EXTENSION [OPTIONS]`
|
**Usage**: `specify extension remove EXTENSION [OPTIONS]`
|
||||||
@@ -575,6 +668,8 @@ EXECUTE_COMMAND: {command}
|
|||||||
|
|
||||||
**Usage**: `specify extension search [QUERY] [OPTIONS]`
|
**Usage**: `specify extension search [QUERY] [OPTIONS]`
|
||||||
|
|
||||||
|
Searches all active catalogs simultaneously. Results include source catalog name and install_allowed status.
|
||||||
|
|
||||||
**Options**:
|
**Options**:
|
||||||
|
|
||||||
- `--tag TAG` - Filter by tag
|
- `--tag TAG` - Filter by tag
|
||||||
@@ -589,6 +684,8 @@ EXECUTE_COMMAND: {command}
|
|||||||
|
|
||||||
**Usage**: `specify extension info EXTENSION`
|
**Usage**: `specify extension info EXTENSION`
|
||||||
|
|
||||||
|
Shows source catalog and install_allowed status.
|
||||||
|
|
||||||
**Arguments**:
|
**Arguments**:
|
||||||
|
|
||||||
- `EXTENSION` - Extension ID
|
- `EXTENSION` - Extension ID
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ vim .specify/extensions/jira/jira-config.yml
|
|||||||
|
|
||||||
## Finding Extensions
|
## Finding Extensions
|
||||||
|
|
||||||
**Note**: By default, `specify extension search` uses your organization's catalog (`catalog.json`). If the catalog is empty, you won't see any results. See [Extension Catalogs](#extension-catalogs) to learn how to populate your catalog from the community reference catalog.
|
`specify extension search` searches **all active catalogs** simultaneously, including the community catalog by default. Results are annotated with their source catalog and install status.
|
||||||
|
|
||||||
### Browse All Extensions
|
### Browse All Extensions
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ vim .specify/extensions/jira/jira-config.yml
|
|||||||
specify extension search
|
specify extension search
|
||||||
```
|
```
|
||||||
|
|
||||||
Shows all extensions in your organization's catalog.
|
Shows all extensions across all active catalogs (org-approved and community by default).
|
||||||
|
|
||||||
### Search by Keyword
|
### Search by Keyword
|
||||||
|
|
||||||
@@ -402,13 +402,13 @@ In addition to extension-specific environment variables (`SPECKIT_{EXT_ID}_*`),
|
|||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
|----------|-------------|---------|
|
|----------|-------------|---------|
|
||||||
| `SPECKIT_CATALOG_URL` | Override the extension catalog URL | GitHub-hosted catalog |
|
| `SPECKIT_CATALOG_URL` | Override the full catalog stack with a single URL (backward compat) | Built-in default stack |
|
||||||
| `GH_TOKEN` / `GITHUB_TOKEN` | GitHub API token for downloads | None |
|
| `GH_TOKEN` / `GITHUB_TOKEN` | GitHub API token for downloads | None |
|
||||||
|
|
||||||
#### Example: Using a custom catalog for testing
|
#### Example: Using a custom catalog for testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Point to a local or alternative catalog
|
# Point to a local or alternative catalog (replaces the full stack)
|
||||||
export SPECKIT_CATALOG_URL="http://localhost:8000/catalog.json"
|
export SPECKIT_CATALOG_URL="http://localhost:8000/catalog.json"
|
||||||
|
|
||||||
# Or use a staging catalog
|
# Or use a staging catalog
|
||||||
@@ -419,13 +419,73 @@ export SPECKIT_CATALOG_URL="https://example.com/staging/catalog.json"
|
|||||||
|
|
||||||
## Extension Catalogs
|
## Extension Catalogs
|
||||||
|
|
||||||
For information about how Spec Kit's dual-catalog system works (`catalog.json` vs `catalog.community.json`), see the main [Extensions README](README.md#extension-catalogs).
|
Spec Kit uses a **catalog stack** — an ordered list of catalogs searched simultaneously. By default, two catalogs are active:
|
||||||
|
|
||||||
|
| Priority | Catalog | Install Allowed | Purpose |
|
||||||
|
|----------|---------|-----------------|---------|
|
||||||
|
| 1 | `catalog.json` (org-approved) | ✅ Yes | Extensions your org approves for installation |
|
||||||
|
| 2 | `catalog.community.json` (community) | ❌ No (discovery only) | Browse community extensions |
|
||||||
|
|
||||||
|
### Listing Active Catalogs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
specify extension catalogs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding a Catalog (Project-scoped)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add an internal catalog that allows installs
|
||||||
|
specify extension catalog add \
|
||||||
|
--name "internal" \
|
||||||
|
--priority 2 \
|
||||||
|
--install-allowed \
|
||||||
|
https://internal.company.com/spec-kit/catalog.json
|
||||||
|
|
||||||
|
# Add a discovery-only catalog
|
||||||
|
specify extension catalog add \
|
||||||
|
--name "partner" \
|
||||||
|
--priority 5 \
|
||||||
|
https://partner.example.com/spec-kit/catalog.json
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates or updates `.specify/extension-catalogs.yml`.
|
||||||
|
|
||||||
|
### Removing a Catalog
|
||||||
|
|
||||||
|
```bash
|
||||||
|
specify extension catalog remove internal
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Config File
|
||||||
|
|
||||||
|
You can also edit `.specify/extension-catalogs.yml` directly:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
catalogs:
|
||||||
|
- name: "org-approved"
|
||||||
|
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json"
|
||||||
|
priority: 1
|
||||||
|
install_allowed: true
|
||||||
|
|
||||||
|
- name: "internal"
|
||||||
|
url: "https://internal.company.com/spec-kit/catalog.json"
|
||||||
|
priority: 2
|
||||||
|
install_allowed: true
|
||||||
|
|
||||||
|
- name: "community"
|
||||||
|
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json"
|
||||||
|
priority: 3
|
||||||
|
install_allowed: false
|
||||||
|
```
|
||||||
|
|
||||||
|
A user-level equivalent lives at `~/.specify/extension-catalogs.yml`. Project-level config takes full precedence when present.
|
||||||
|
|
||||||
## Organization Catalog Customization
|
## Organization Catalog Customization
|
||||||
|
|
||||||
### Why Customize Your Catalog
|
### Why Customize Your Catalog
|
||||||
|
|
||||||
Organizations customize their `catalog.json` to:
|
Organizations customize their catalogs to:
|
||||||
|
|
||||||
- **Control available extensions** - Curate which extensions your team can install
|
- **Control available extensions** - Curate which extensions your team can install
|
||||||
- **Host private extensions** - Internal tools that shouldn't be public
|
- **Host private extensions** - Internal tools that shouldn't be public
|
||||||
@@ -503,24 +563,40 @@ Options for hosting your catalog:
|
|||||||
|
|
||||||
#### 3. Configure Your Environment
|
#### 3. Configure Your Environment
|
||||||
|
|
||||||
##### Option A: Environment variable (recommended for CI/CD)
|
##### Option A: Catalog stack config file (recommended)
|
||||||
|
|
||||||
|
Add to `.specify/extension-catalogs.yml` in your project:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
catalogs:
|
||||||
|
- name: "org-approved"
|
||||||
|
url: "https://your-org.com/spec-kit/catalog.json"
|
||||||
|
priority: 1
|
||||||
|
install_allowed: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use the CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
specify extension catalog add \
|
||||||
|
--name "org-approved" \
|
||||||
|
--install-allowed \
|
||||||
|
https://your-org.com/spec-kit/catalog.json
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Option B: Environment variable (recommended for CI/CD, single-catalog)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In ~/.bashrc, ~/.zshrc, or CI pipeline
|
# In ~/.bashrc, ~/.zshrc, or CI pipeline
|
||||||
export SPECKIT_CATALOG_URL="https://your-org.com/spec-kit/catalog.json"
|
export SPECKIT_CATALOG_URL="https://your-org.com/spec-kit/catalog.json"
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Option B: Per-project configuration
|
|
||||||
|
|
||||||
Create `.env` or set in your shell before running spec-kit commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
SPECKIT_CATALOG_URL="https://your-org.com/spec-kit/catalog.json" specify extension search
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. Verify Configuration
|
#### 4. Verify Configuration
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# List active catalogs
|
||||||
|
specify extension catalogs
|
||||||
|
|
||||||
# Search should now show your catalog's extensions
|
# Search should now show your catalog's extensions
|
||||||
specify extension search
|
specify extension search
|
||||||
|
|
||||||
|
|||||||
@@ -868,7 +868,7 @@ Spec Kit uses two catalog files with different purposes:
|
|||||||
|
|
||||||
- **Purpose**: Organization's curated catalog of approved extensions
|
- **Purpose**: Organization's curated catalog of approved extensions
|
||||||
- **Default State**: Empty by design - users populate with extensions they trust
|
- **Default State**: Empty by design - users populate with extensions they trust
|
||||||
- **Usage**: Default catalog used by `specify extension` CLI commands
|
- **Usage**: Primary catalog (priority 1, `install_allowed: true`) in the default stack
|
||||||
- **Control**: Organizations maintain their own fork/version for their teams
|
- **Control**: Organizations maintain their own fork/version for their teams
|
||||||
|
|
||||||
#### Community Reference Catalog (`catalog.community.json`)
|
#### Community Reference Catalog (`catalog.community.json`)
|
||||||
@@ -879,16 +879,16 @@ Spec Kit uses two catalog files with different purposes:
|
|||||||
- **Verification**: Community extensions may have `verified: false` initially
|
- **Verification**: Community extensions may have `verified: false` initially
|
||||||
- **Status**: Active - open for community contributions
|
- **Status**: Active - open for community contributions
|
||||||
- **Submission**: Via Pull Request following the Extension Publishing Guide
|
- **Submission**: Via Pull Request following the Extension Publishing Guide
|
||||||
- **Usage**: Browse to discover extensions, then copy to your `catalog.json`
|
- **Usage**: Secondary catalog (priority 2, `install_allowed: false`) in the default stack — discovery only
|
||||||
|
|
||||||
**How It Works:**
|
**How It Works (default stack):**
|
||||||
|
|
||||||
1. **Discover**: Browse `catalog.community.json` to find available extensions
|
1. **Discover**: `specify extension search` searches both catalogs — community extensions appear automatically
|
||||||
2. **Review**: Evaluate extensions for security, quality, and organizational fit
|
2. **Review**: Evaluate community extensions for security, quality, and organizational fit
|
||||||
3. **Curate**: Copy approved extension entries from community catalog to your `catalog.json`
|
3. **Curate**: Copy approved entries from community catalog to your `catalog.json`, or add to `.specify/extension-catalogs.yml` with `install_allowed: true`
|
||||||
4. **Install**: Use `specify extension add <name>` (pulls from your curated catalog)
|
4. **Install**: Use `specify extension add <name>` — only allowed from `install_allowed: true` catalogs
|
||||||
|
|
||||||
This approach gives organizations full control over which extensions are available to their teams while maintaining a shared community resource for discovery.
|
This approach gives organizations full control over which extensions can be installed while still providing community discoverability out of the box.
|
||||||
|
|
||||||
### Catalog Format
|
### Catalog Format
|
||||||
|
|
||||||
@@ -961,30 +961,89 @@ specify extension info jira
|
|||||||
|
|
||||||
### Custom Catalogs
|
### Custom Catalogs
|
||||||
|
|
||||||
**⚠️ FUTURE FEATURE - NOT YET IMPLEMENTED**
|
Spec Kit supports a **catalog stack** — an ordered list of catalogs that the CLI merges and searches across. This allows organizations to benefit from org-approved extensions, an internal catalog, and community discovery all at once.
|
||||||
|
|
||||||
The following catalog management commands are proposed design concepts but are not yet available in the current implementation:
|
#### Catalog Stack Resolution
|
||||||
|
|
||||||
```bash
|
The active catalog stack is resolved in this order (first match wins):
|
||||||
# Add custom catalog (FUTURE - NOT AVAILABLE)
|
|
||||||
specify extension add-catalog https://internal.company.com/spec-kit/catalog.json
|
|
||||||
|
|
||||||
# Set as default (FUTURE - NOT AVAILABLE)
|
1. **`SPECKIT_CATALOG_URL` environment variable** — single catalog replacing all defaults (backward compat)
|
||||||
specify extension set-catalog --default https://internal.company.com/spec-kit/catalog.json
|
2. **Project-level `.specify/extension-catalogs.yml`** — full control for the project
|
||||||
|
3. **User-level `~/.specify/extension-catalogs.yml`** — personal defaults
|
||||||
|
4. **Built-in default stack** — `catalog.json` (install_allowed: true) + `catalog.community.json` (install_allowed: false)
|
||||||
|
|
||||||
# List catalogs (FUTURE - NOT AVAILABLE)
|
#### Default Built-in Stack
|
||||||
specify extension catalogs
|
|
||||||
|
When no config file exists, the CLI uses:
|
||||||
|
|
||||||
|
| Priority | Catalog | install_allowed | Purpose |
|
||||||
|
|----------|---------|-----------------|---------|
|
||||||
|
| 1 | `catalog.json` (org-approved) | `true` | Extensions your org approves for installation |
|
||||||
|
| 2 | `catalog.community.json` (community) | `false` | Discovery only — browse but not install |
|
||||||
|
|
||||||
|
This means `specify extension search` surfaces community extensions out of the box, while `specify extension add` is still restricted to org-approved entries.
|
||||||
|
|
||||||
|
#### `.specify/extension-catalogs.yml` Config File
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
catalogs:
|
||||||
|
- name: "org-approved"
|
||||||
|
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json"
|
||||||
|
priority: 1 # Highest — only approved entries can be installed
|
||||||
|
install_allowed: true
|
||||||
|
|
||||||
|
- name: "internal"
|
||||||
|
url: "https://internal.company.com/spec-kit/catalog.json"
|
||||||
|
priority: 2
|
||||||
|
install_allowed: true
|
||||||
|
|
||||||
|
- name: "community"
|
||||||
|
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json"
|
||||||
|
priority: 3 # Lowest — discovery only, not installable
|
||||||
|
install_allowed: false
|
||||||
```
|
```
|
||||||
|
|
||||||
**Proposed catalog priority** (future design):
|
A user-level equivalent lives at `~/.specify/extension-catalogs.yml`. When a project-level config is present, it takes full control and the built-in defaults are not applied.
|
||||||
|
|
||||||
1. Project-specific catalog (`.specify/extension-catalogs.yml`) - *not implemented*
|
#### Catalog CLI Commands
|
||||||
2. User-level catalog (`~/.specify/extension-catalogs.yml`) - *not implemented*
|
|
||||||
3. Default GitHub catalog
|
|
||||||
|
|
||||||
#### Current Implementation: SPECKIT_CATALOG_URL
|
```bash
|
||||||
|
# List active catalogs with name, URL, priority, and install_allowed
|
||||||
|
specify extension catalogs
|
||||||
|
|
||||||
**The currently available method** for using custom catalogs is the `SPECKIT_CATALOG_URL` environment variable:
|
# Add a catalog (project-scoped)
|
||||||
|
specify extension catalog add --name "internal" --install-allowed \
|
||||||
|
https://internal.company.com/spec-kit/catalog.json
|
||||||
|
|
||||||
|
# Add a discovery-only catalog
|
||||||
|
specify extension catalog add --name "community" \
|
||||||
|
https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json
|
||||||
|
|
||||||
|
# Remove a catalog
|
||||||
|
specify extension catalog remove internal
|
||||||
|
|
||||||
|
# Show which catalog an extension came from
|
||||||
|
specify extension info jira
|
||||||
|
# → Source catalog: org-approved
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Merge Conflict Resolution
|
||||||
|
|
||||||
|
When the same extension `id` appears in multiple catalogs, the higher-priority (lower priority number) catalog wins. Extensions from lower-priority catalogs with the same `id` are ignored.
|
||||||
|
|
||||||
|
#### `install_allowed: false` Behavior
|
||||||
|
|
||||||
|
Extensions from discovery-only catalogs are shown in `specify extension search` results but cannot be installed directly:
|
||||||
|
|
||||||
|
```
|
||||||
|
⚠ 'linear' is available in the 'community' catalog but installation is not allowed from that catalog.
|
||||||
|
|
||||||
|
To enable installation, add 'linear' to an approved catalog (install_allowed: true) in .specify/extension-catalogs.yml.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `SPECKIT_CATALOG_URL` (Backward Compatibility)
|
||||||
|
|
||||||
|
The `SPECKIT_CATALOG_URL` environment variable still works — it is treated as a single `install_allowed: true` catalog, **replacing both defaults** for full backward compatibility:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Point to your organization's catalog
|
# Point to your organization's catalog
|
||||||
|
|||||||
@@ -1878,8 +1878,10 @@ def extension_catalogs():
|
|||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
config_path = project_root / ".specify" / "extension-catalogs.yml"
|
config_path = project_root / ".specify" / "extension-catalogs.yml"
|
||||||
if config_path.exists():
|
if config_path.exists() and catalog._load_catalog_config(config_path) is not None:
|
||||||
console.print(f"[dim]Config: {config_path.relative_to(project_root)}[/dim]")
|
console.print(f"[dim]Config: {config_path.relative_to(project_root)}[/dim]")
|
||||||
|
elif os.environ.get("SPECKIT_CATALOG_URL"):
|
||||||
|
console.print("[dim]Catalog configured via SPECKIT_CATALOG_URL environment variable.[/dim]")
|
||||||
else:
|
else:
|
||||||
console.print("[dim]Using built-in default catalog stack.[/dim]")
|
console.print("[dim]Using built-in default catalog stack.[/dim]")
|
||||||
console.print(
|
console.print(
|
||||||
|
|||||||
Reference in New Issue
Block a user