MCPcopy Index your code
hub / github.com/github/spec-kit / WorkflowCatalog

Class WorkflowCatalog

src/specify_cli/workflows/catalog.py:129–589  ·  view source on GitHub ↗

Manages workflow catalog fetching, caching, and searching. Resolution order for catalog sources: 1. ``SPECKIT_WORKFLOW_CATALOG_URL`` env var (overrides all) 2. Project-level ``.specify/workflow-catalogs.yml`` 3. User-level ``~/.specify/workflow-catalogs.yml`` 4. Built-in default

Source from the content-addressed store, hash-verified

127
128
129class WorkflowCatalog:
130 """Manages workflow catalog fetching, caching, and searching.
131
132 Resolution order for catalog sources:
133 1. ``SPECKIT_WORKFLOW_CATALOG_URL`` env var (overrides all)
134 2. Project-level ``.specify/workflow-catalogs.yml``
135 3. User-level ``~/.specify/workflow-catalogs.yml``
136 4. Built-in defaults (official + community)
137 """
138
139 DEFAULT_CATALOG_URL = (
140 "https://raw.githubusercontent.com/github/spec-kit/main/"
141 "workflows/catalog.json"
142 )
143 COMMUNITY_CATALOG_URL = (
144 "https://raw.githubusercontent.com/github/spec-kit/main/"
145 "workflows/catalog.community.json"
146 )
147 CACHE_DURATION = 3600 # 1 hour
148
149 def __init__(self, project_root: Path) -> None:
150 self.project_root = project_root
151 self.workflows_dir = project_root / ".specify" / "workflows"
152 self.cache_dir = self.workflows_dir / ".cache"
153
154 # -- Catalog resolution -----------------------------------------------
155
156 def _validate_catalog_url(self, url: str) -> None:
157 """Validate that a catalog URL uses HTTPS (localhost HTTP allowed)."""
158 from urllib.parse import urlparse
159
160 parsed = urlparse(url)
161 is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
162 if parsed.scheme != "https" and not (
163 parsed.scheme == "http" and is_localhost
164 ):
165 raise WorkflowValidationError(
166 f"Catalog URL must use HTTPS (got {parsed.scheme}://). "
167 "HTTP is only allowed for localhost."
168 )
169 if not parsed.hostname:
170 raise WorkflowValidationError(
171 "Catalog URL must be a valid URL with a host."
172 )
173
174 def _load_catalog_config(
175 self, config_path: Path
176 ) -> list[WorkflowCatalogEntry] | None:
177 """Load catalog stack configuration from a YAML file."""
178 if not config_path.exists():
179 return None
180 try:
181 data = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
182 except (yaml.YAMLError, OSError, UnicodeError) as exc:
183 raise WorkflowValidationError(
184 f"Failed to read catalog config {config_path}: {exc}"
185 ) from exc
186 if not isinstance(data, dict):

Calls

no outgoing calls