diff --git a/openspec/changes/skill-catalog-subscription/.openspec.yaml b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/.openspec.yaml similarity index 100% rename from openspec/changes/skill-catalog-subscription/.openspec.yaml rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/.openspec.yaml diff --git a/openspec/changes/skill-catalog-subscription/design.md b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/design.md similarity index 100% rename from openspec/changes/skill-catalog-subscription/design.md rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/design.md diff --git a/openspec/changes/skill-catalog-subscription/proposal.md b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/proposal.md similarity index 100% rename from openspec/changes/skill-catalog-subscription/proposal.md rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/proposal.md diff --git a/openspec/changes/skill-catalog-subscription/specs/skill-catalog/spec.md b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/specs/skill-catalog/spec.md similarity index 100% rename from openspec/changes/skill-catalog-subscription/specs/skill-catalog/spec.md rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/specs/skill-catalog/spec.md diff --git a/openspec/changes/skill-catalog-subscription/specs/skill-mcp-tools/spec.md b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/specs/skill-mcp-tools/spec.md similarity index 100% rename from openspec/changes/skill-catalog-subscription/specs/skill-mcp-tools/spec.md rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/specs/skill-mcp-tools/spec.md diff --git a/openspec/changes/skill-catalog-subscription/specs/skill-subscription-sync/spec.md b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/specs/skill-subscription-sync/spec.md similarity index 100% rename from openspec/changes/skill-catalog-subscription/specs/skill-subscription-sync/spec.md rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/specs/skill-subscription-sync/spec.md diff --git a/openspec/changes/skill-catalog-subscription/tasks.md b/openspec/changes/archive/2026-07-15-skill-catalog-subscription/tasks.md similarity index 100% rename from openspec/changes/skill-catalog-subscription/tasks.md rename to openspec/changes/archive/2026-07-15-skill-catalog-subscription/tasks.md diff --git a/openspec/specs/skill-catalog/spec.md b/openspec/specs/skill-catalog/spec.md new file mode 100644 index 0000000..97b852f --- /dev/null +++ b/openspec/specs/skill-catalog/spec.md @@ -0,0 +1,56 @@ +# skill-catalog Specification + +## Purpose +Provides a local, read-only catalog of Skills (knowledge and flow-template) synced from the Subscription Platform, queryable by list, search, and id without per-query network round-trips. +## Requirements +### Requirement: Unified Skill data model +The system SHALL represent every Skill with shared metadata (id, name, description, version, tags, source/subscription id, updated_at) and a `kind` discriminator of either `knowledge` or `flow_template`, so both kinds can be listed and searched through one catalog. + +#### Scenario: Knowledge skill has content +- **WHEN** a Skill with `kind = knowledge` is stored +- **THEN** it includes a `content` field (structured instructional text/markdown) in addition to the shared metadata + +#### Scenario: Flow-template skill has steps and parameters +- **WHEN** a Skill with `kind = flow_template` is stored +- **THEN** it includes an ordered `steps` list (each referencing a tool name and an args template that may contain `{param}` placeholders) and a `parameters` schema (name, type, required, description) in addition to the shared metadata + +### Requirement: Local skill storage +The system SHALL persist the synced Skill Catalog locally so that skills can be listed and fetched without a live round-trip to the Subscription Platform for every query. + +#### Scenario: Skill readable after sync +- **WHEN** a skill has been synced from the Subscription Platform into the local catalog +- **THEN** subsequent list/search/get operations return that skill without requiring a new network call to the Subscription Platform + +#### Scenario: Local catalog is not independently authored +- **WHEN** a caller attempts to create or edit a skill directly in the local catalog (outside of a sync operation) +- **THEN** the system SHALL reject or ignore the write, since the Subscription Platform is the sole source of truth for skill content + +### Requirement: Skill search and query +The system SHALL provide functions to list all currently visible skills, search skills by name/tag/description text, and fetch a single skill by id. + +#### Scenario: List returns only visible skills +- **WHEN** the catalog is queried for the list of skills visible to the current caller +- **THEN** it returns only skills whose subscription is currently active for that caller, sorted in a stable order (e.g. by name) + +#### Scenario: Search matches on name, tags, or description +- **WHEN** a search query string matches a skill's name, a tag, or its description +- **THEN** that skill is included in the search results + +#### Scenario: Get by id returns full content +- **WHEN** a caller fetches a skill by its id +- **THEN** the system returns the full skill record, including `content` for knowledge skills or `steps`/`parameters` for flow-template skills + +#### Scenario: Get by id for unknown or invisible skill +- **WHEN** a caller fetches a skill id that does not exist, or exists but is not currently visible to them (subscription inactive) +- **THEN** the system returns a clear "not found" result rather than leaking the skill's existence or content + +### Requirement: Flow-template tool reference validation +The system SHALL validate that a flow-template skill's referenced tool names correspond to currently registered device-capability tools, and SHALL mark a flow-template skill as invalid/unavailable rather than allowing it to be fetched successfully if a referenced tool does not exist. + +#### Scenario: Valid flow template +- **WHEN** every step in a flow-template skill references a tool name that is currently registered +- **THEN** the skill is fetchable and returned normally + +#### Scenario: Flow template references an unknown tool +- **WHEN** a flow-template skill's steps reference a tool name that is not currently registered (e.g. renamed or removed) +- **THEN** fetching that skill returns a clear "skill unavailable/invalid" result instead of a step list containing a dangling tool reference diff --git a/openspec/specs/skill-mcp-tools/spec.md b/openspec/specs/skill-mcp-tools/spec.md new file mode 100644 index 0000000..453069b --- /dev/null +++ b/openspec/specs/skill-mcp-tools/spec.md @@ -0,0 +1,44 @@ +# skill-mcp-tools Specification + +## Purpose +Exposes Skill Catalog discovery, retrieval, and flow-template parameter resolution as MCP tools on the same surface used for device capabilities, so an LLM client can discover and use Skills through the existing tool-calling mechanism. +## Requirements +### Requirement: MCP tools for skill discovery and retrieval +The system SHALL expose `list_skills`, `search_skills`, and `get_skill` as MCP tools on the same MCP server surface used for device capabilities, so an LLM client can discover and fetch Skill content using the same tool-calling mechanism it already uses for device actions. + +#### Scenario: LLM lists available skills +- **WHEN** an MCP client calls `list_skills` +- **THEN** it receives the set of skills currently visible to it (per subscription visibility), each with id, name, description, kind, and tags, without any Subscription Platform-specific fields or identifiers + +#### Scenario: LLM searches for a relevant skill +- **WHEN** an MCP client calls `search_skills` with a query string +- **THEN** it receives matching skills ranked/filtered by relevance to the query, using the same visibility rules as `list_skills` + +#### Scenario: LLM fetches a specific skill's content +- **WHEN** an MCP client calls `get_skill` with a skill id +- **THEN** it receives the full skill content appropriate to its kind: `content` text for a `knowledge` skill, or `steps`/`parameters` for a `flow_template` skill + +### Requirement: Flow-template parameter resolution helper +The system SHALL provide an MCP-facing helper that, given a flow-template skill id and a set of proposed parameter values, validates the values against the skill's declared `parameters` schema and returns the fully resolved step sequence (placeholders substituted) for the LLM to then execute step-by-step via the existing device-capability tools. + +#### Scenario: Valid parameters resolve the template +- **WHEN** the LLM provides values for all required parameters of a flow-template skill +- **THEN** the system returns the ordered steps with all `{param}` placeholders substituted by the provided values + +#### Scenario: Missing required parameter +- **WHEN** the LLM omits a required parameter when resolving a flow-template skill +- **THEN** the system returns a clear validation error identifying the missing parameter(s) instead of returning a partially-substituted step list + +### Requirement: No server-side flow execution tool +The system SHALL NOT expose an MCP tool that executes a flow-template skill's full step sequence server-side on the LLM's behalf; the LLM SHALL issue each resulting device-capability tool call itself so every step remains subject to the existing Agent Runtime's Observe-Think-Act loop and Executor retry/wait handling. + +#### Scenario: No batch-execute tool is available +- **WHEN** the MCP tool list is inspected +- **THEN** it contains skill discovery/retrieval/resolution tools but no tool that both resolves and executes a flow-template skill's steps in a single call + +### Requirement: Skill MCP errors are semantic +The system SHALL translate catalog-level errors (skill not found, skill not visible/entitled, invalid/unavailable flow template) into clear, semantic MCP tool error responses, consistent in style with the device-capability tool error handling. + +#### Scenario: Requesting a non-visible skill +- **WHEN** `get_skill` is called with a skill id that exists but is not visible to the caller's current subscriptions +- **THEN** the tool returns a semantic "not found" error rather than a raw database or internal exception diff --git a/openspec/specs/skill-subscription-sync/spec.md b/openspec/specs/skill-subscription-sync/spec.md new file mode 100644 index 0000000..cd86cda --- /dev/null +++ b/openspec/specs/skill-subscription-sync/spec.md @@ -0,0 +1,64 @@ +# skill-subscription-sync Specification + +## Purpose +Keeps the local Skill Catalog aligned with the external Subscription Platform via periodic pull sync (and optional push-triggered sync), enforcing subscription-based visibility and degrading gracefully on sync failures. +## Requirements +### Requirement: Pull-based sync from the Subscription Platform +The system SHALL periodically fetch, from the external Subscription Platform, the set of skills the current deployment (tenant/device/agent) is entitled to, and SHALL apply creates/updates/removals to the local Skill Catalog to match that entitled set. + +#### Scenario: New skill appears after sync +- **WHEN** the Subscription Platform reports a new entitled skill that does not yet exist locally +- **THEN** the next sync cycle creates it in the local Skill Catalog + +#### Scenario: Updated skill content is refreshed +- **WHEN** the Subscription Platform reports a newer version of a skill already present locally +- **THEN** the next sync cycle updates the local copy to the newer version + +#### Scenario: Revoked entitlement removes local visibility +- **WHEN** the Subscription Platform no longer includes a previously-entitled skill in the current entitled set +- **THEN** the next sync cycle removes or marks that skill as no longer visible in the local Skill Catalog + +#### Scenario: Sync interval is configurable +- **WHEN** the deployment is configured with a sync poll interval +- **THEN** the system performs pull sync on approximately that interval without requiring a restart to take effect on the next cycle + +### Requirement: Optional push-triggered sync +The system MAY support receiving a change notification (e.g. webhook) from the Subscription Platform, and WHEN it does, SHALL trigger an immediate out-of-cycle pull sync rather than waiting for the next poll interval; correctness of the catalog SHALL NOT depend on push notifications being delivered. + +#### Scenario: Push notification triggers immediate sync +- **WHEN** a change notification is received from the Subscription Platform +- **THEN** the system performs a pull sync immediately, independent of the regular poll schedule + +#### Scenario: No push configured still stays eventually consistent +- **WHEN** push notifications are not configured or not received +- **THEN** the local Skill Catalog still reflects the Subscription Platform's entitled set within one poll interval via the baseline pull sync + +### Requirement: Subscription-based visibility enforcement +The system SHALL enforce, at both sync time and query time, that only skills belonging to the caller's currently active subscription(s) are stored as visible or returned by catalog queries. + +#### Scenario: Query-time re-check catches stale entitlement +- **WHEN** a skill's entitlement has been revoked but the local cache has not yet completed its next sync cycle +- **AND** a catalog query for that skill is made using already-known revocation information +- **THEN** the system does not return that skill as visible, even though its record may still exist locally pending cleanup + +#### Scenario: Multiple subscriptions compose visibility +- **WHEN** a deployment holds more than one active subscription, each entitling a different set of skills +- **THEN** catalog queries return the union of skills entitled across all of that deployment's active subscriptions + +### Requirement: Sync client contract is transport-replaceable +The system SHALL define the Subscription Platform integration (fetch entitled skills, optional change notification receipt) behind a single internal interface, so the concrete HTTP client/auth mechanism can be adjusted to match the real Subscription Platform API without changes to the Skill Catalog or MCP tool layers. + +#### Scenario: Sync client swap does not affect catalog/tools +- **WHEN** the concrete Subscription Platform client implementation is replaced (e.g. different auth scheme or request/response shape) +- **THEN** `skill-catalog` and `skill-mcp-tools` behavior and their own specs remain unaffected, as long as the new client still satisfies the sync interface + +### Requirement: Sync failure handling +The system SHALL treat a failed sync attempt (network error, auth failure, malformed response) as non-fatal to already-cached skills: the local catalog SHALL continue serving its last-known-good state, and the failure SHALL be recorded/observable rather than silently discarded. + +#### Scenario: Sync failure preserves last-known catalog +- **WHEN** a sync attempt fails due to a network or platform error +- **THEN** the local Skill Catalog is left unchanged (not cleared or partially corrupted) and remains queryable using its last successfully synced state + +#### Scenario: Sync failure is observable +- **WHEN** a sync attempt fails +- **THEN** the system records the failure (e.g. last-error timestamp/reason) so it can be surfaced to operators rather than failing silently forever