diff --git a/docs/architecture.md b/docs/architecture.md index c0c251d..c0d63d7 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -16,11 +16,17 @@ The system is complete in three layers: 2. Catalog resources provide normalized discovery. 3. Zensical builds a static site from those same Markdown sources and the FastAPI app serves it in the FastMCP runtime process. -For Phase 1, this architecture is anchored by three contracts: +This architecture is anchored by three contracts: -1. Step 1: docs-first authored content contract under `docs/` with strict per-skill ownership. -2. Step 2: SKILL.md frontmatter contract with Anthropic fields plus `x-personal-mcp` metadata. -3. Step 3: canonical resource URI contract with break-and-replace policy for contract changes. +1. Docs-first authored content contract under `docs/` with strict per-skill ownership. +2. `SKILL.md` frontmatter contract with Anthropic fields plus `x-personal-mcp` metadata. +3. Canonical resource URI contract with break-and-replace policy for contract changes. + +Detailed contract pages: + +1. [Content Contract](./content.md) +2. [Frontmatter Contract](./frontmatter.md) +3. [URI Contract](./uris.md) This architecture keeps authored content human-friendly while preserving machine-stable contracts. @@ -62,7 +68,7 @@ Only canonical catalog resources are part of the runtime contract in this phase. ### Registry Loader -Phase 2 runtime composition introduces a startup registry loader that reads packaged docs resources using `importlib.resources.files(...)` and `Traversable` APIs. +The runtime composition includes a startup registry loader that reads packaged docs resources using `importlib.resources.files(...)` and `Traversable` APIs. Loader responsibilities: @@ -104,6 +110,8 @@ flowchart TD Each skill declares frontmatter in `docs/skills//SKILL.md`. +For the full field-level contract, validation model, and FastMCP metadata mapping, see [Frontmatter Contract](./frontmatter.md). + Anthropic-facing required fields: 1. name @@ -124,6 +132,8 @@ No `metadata.yaml` sidecar is part of the end-state contract. Canonical resource URIs are: +For the full URI semantics, parameter validation rules, and compatibility policy, see [URI Contract](./uris.md). + 1. resource://skills//document 2. resource://skills//references/ 3. resource://catalog/skills_index diff --git a/docs/content.md b/docs/content.md new file mode 100644 index 0000000..957ceb2 --- /dev/null +++ b/docs/content.md @@ -0,0 +1,84 @@ +# Content Contract + +This page defines the authored content contract for the docs-first MCP architecture. + +## Canonical Source Of Truth + +1. All authored Markdown lives under `docs/`. +2. MCP resources and static docs are two distribution surfaces of the same authored files. +3. No parallel authored markdown is allowed in `src/` or other package-only paths. + +## Canonical Skill Shape + +Each skill is one directory under `docs/skills/`: + +```text +docs/ + skills/ + / + SKILL.md + references/ + ... (one or more markdown files, optional nested folders) +``` + +Rules: + +1. `SKILL.md` is required for every skill. +2. `references/` is the only place for skill-specific supporting docs. +3. Nested folders inside `references/` are allowed so a skill can reorganize internals without changing global architecture. +4. Skill directories are independent ownership boundaries; no cross-skill file writes. + +## File Placement And Ownership Boundaries + +1. Top-level project docs stay in `docs/*.md`. +2. Skill docs stay in `docs/skills//...`. +3. A skill may link to other skills, but must not store content inside another skill's directory. +4. Server and runtime code may index and serve docs, but must not be the source of authored markdown. + +## Metadata Location Constraint + +1. Skill metadata is embedded in YAML frontmatter in `SKILL.md`. +2. No `metadata.yaml` sidecar exists in the end state. +3. Reference lookup metadata, including reference id to relative path mappings, is declared from `SKILL.md` frontmatter rather than inferred as a hidden global convention. + +## Skill Id Contract + +`skill-id` is the public identifier and should satisfy all rules below: + +1. Format: lowercase kebab-case only. +2. Character set: `a-z`, `0-9`, and `-`. +3. Must start with a letter. +4. No underscores, spaces, dots, or uppercase characters. +5. Directory name should equal `skill-id` in each committed revision. +6. Frontmatter `id` should equal directory name in each committed revision. +7. Treat `skill-id` as immutable after release; any rename is a breaking replacement and clients must move to the new id. + +Valid examples: + +1. `fastapi-uv-docker` +2. `zensical-docs` +3. `pytest-scaffolding` + +Invalid examples: + +1. `fastapi_uv_docker` +2. `Zensical-Docs` +3. `docs.zensical` + +## Invariants + +This contract guarantees: + +1. One authored source tree in `docs/` for both website and MCP. +2. One skill directory maps to one skill identity per revision. +3. Namespace and slug drift is minimized by keeping directory and frontmatter ids aligned per revision. +4. Per-skill reference structure can evolve without changing cross-skill architecture. +5. Packaging for stdio is deterministic because authored content is path-stable. + +## Non-Goals + +This contract does not define: + +1. URI versioning policy details. +2. The full frontmatter schema. +3. Migration instructions from the current architecture. \ No newline at end of file diff --git a/docs/frontmatter.md b/docs/frontmatter.md new file mode 100644 index 0000000..e15645a --- /dev/null +++ b/docs/frontmatter.md @@ -0,0 +1,309 @@ +# Frontmatter Contract + +This page defines the `SKILL.md` frontmatter and FastMCP metadata contract. + +## Anthropic Frontmatter Support + +Across Anthropic API and Agent Skills surfaces: + +1. Required fields for custom skill bundles are `name` and `description`. +2. `name` must be 1-64 characters, lowercase letters, numbers, and hyphens only, with no XML tags, and must not use the reserved words `anthropic` or `claude`. +3. `description` must be 1-1024 characters, non-empty, and contain no XML tags. + +Portable optional fields from the Agent Skills specification: + +1. `license` +2. `compatibility` +3. `metadata` +4. `allowed-tools` + +Claude Code-specific optional fields: + +1. `when_to_use` +2. `argument-hint` +3. `arguments` +4. `disable-model-invocation` +5. `user-invocable` +6. `allowed-tools` +7. `disallowed-tools` +8. `model` +9. `effort` +10. `context` +11. `agent` +12. `hooks` +13. `paths` +14. `shell` + +Repository contract decisions: + +1. Treat `name` and `description` as required in all `SKILL.md` files. +2. Keep Anthropic-facing semantics in standard fields. +3. Keep MCP indexing metadata in a namespaced extension block. +4. Preserve forward compatibility by allowing additive optional metadata fields over time. + +## Canonical Frontmatter Schema + +Use this two-layer pattern: + +1. Anthropic layer: top-level fields intended for Anthropic and Agent Skills behavior. +2. Repository layer: one namespaced block, `x-personal-mcp`, for MCP catalog and routing metadata. + +Canonical shape: + +```yaml +--- +name: +description: + +# Optional Anthropic and Agent Skills fields +when_to_use: +allowed-tools: +disable-model-invocation: false +user-invocable: true +license: +compatibility: + +# Repository-specific metadata +x-personal-mcp: + id: + version: + tags: + - + capabilities: + - resource://skills//document + depends_on: [] + references: + : + path: references/.md + mime_type: text/markdown + title: +--- +``` + +## Repository Metadata Field Rules + +Rules for `x-personal-mcp`: + +1. `id` is required, must follow the skill id rules from the content contract, and must equal the directory name. +2. `version` is required and must be a semantic version string. +3. `tags` is optional and should be a list of kebab-case discovery labels. +4. `capabilities` is required and lists the MCP URIs the skill publishes. +5. `depends_on` is optional and lists other skill ids. +6. `references` is an optional map keyed by `ref-id`. + +Reference entry rules: + +1. `ref-id` is lowercase kebab-case. +2. `path` is a skill-relative markdown path and must stay inside the same skill directory. +3. Nested folders under `references/` are allowed. +4. `mime_type` defaults to `text/markdown` when omitted. +5. `title` is an optional display label. +6. Renaming `ref-id` values is allowed when needed; optional aliases may be used during transitions. + +## Validation Models + +The normative model uses Pydantic v2 with change-friendly validation: + +```python +from __future__ import annotations + +import re +from pathlib import PurePosixPath +from typing import Any + +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator + +SKILL_ID_RE = re.compile(r"^[a-z][a-z0-9-]*$") +SEMVER_RE = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:[-+][0-9A-Za-z.-]+)?$") + + +class ReferenceEntry(BaseModel): + model_config = ConfigDict(extra="ignore", str_strip_whitespace=True) + + path: str + mime_type: str = "text/markdown" + title: str | None = None + + @field_validator("path") + @classmethod + def validate_reference_path(cls, value: str) -> str: + p = PurePosixPath(value) + if p.is_absolute() or ".." in p.parts: + raise ValueError("reference path must be a relative in-skill path") + if not str(p).startswith("references/"): + raise ValueError("reference path must stay under references/") + if p.suffix.lower() != ".md": + raise ValueError("reference path must target a markdown file") + return str(p) + + +class PersonalMcpMetadata(BaseModel): + model_config = ConfigDict(extra="ignore", str_strip_whitespace=True) + + id: str + version: str + tags: list[str] = Field(default_factory=list) + capabilities: list[str] = Field(min_length=1) + depends_on: list[str] = Field(default_factory=list) + references: dict[str, ReferenceEntry] = Field(default_factory=dict) + + @field_validator("id") + @classmethod + def validate_id(cls, value: str) -> str: + if not SKILL_ID_RE.fullmatch(value): + raise ValueError("id must be lowercase kebab-case and start with a letter") + return value + + @field_validator("version") + @classmethod + def validate_version(cls, value: str) -> str: + if not SEMVER_RE.fullmatch(value): + raise ValueError("version must be semver") + return value + + @field_validator("depends_on") + @classmethod + def validate_depends_on(cls, value: list[str]) -> list[str]: + for dep in value: + if not SKILL_ID_RE.fullmatch(dep): + raise ValueError(f"invalid depends_on skill id: {dep}") + return value + + @field_validator("references") + @classmethod + def validate_reference_ids(cls, value: dict[str, ReferenceEntry]) -> dict[str, ReferenceEntry]: + for ref_id in value: + if not SKILL_ID_RE.fullmatch(ref_id): + raise ValueError(f"invalid reference id: {ref_id}") + return value + + @model_validator(mode="after") + def ensure_primary_capability(self) -> "PersonalMcpMetadata": + expected = f"resource://skills/{self.id}/document" + if expected not in self.capabilities: + raise ValueError(f"capabilities must include {expected}") + return self + + +class SkillFrontmatter(BaseModel): + model_config = ConfigDict(extra="ignore", str_strip_whitespace=True) + + name: str = Field(min_length=1, max_length=64) + description: str = Field(min_length=1, max_length=1024) + when_to_use: str | None = None + allowed_tools: str | list[str] | None = Field(default=None, alias="allowed-tools") + disallowed_tools: str | list[str] | None = Field(default=None, alias="disallowed-tools") + disable_model_invocation: bool | None = Field(default=None, alias="disable-model-invocation") + user_invocable: bool | None = Field(default=None, alias="user-invocable") + argument_hint: str | None = Field(default=None, alias="argument-hint") + arguments: str | list[str] | None = None + license: str | None = None + compatibility: str | None = None + metadata: dict[str, str] | None = None + + x_personal_mcp: PersonalMcpMetadata = Field(alias="x-personal-mcp") + + @field_validator("name") + @classmethod + def validate_name(cls, value: str) -> str: + if not SKILL_ID_RE.fullmatch(value): + raise ValueError("name must be lowercase kebab-case and start with a letter") + if "anthropic" in value or "claude" in value: + raise ValueError("name must not contain reserved words anthropic or claude") + return value + + @model_validator(mode="after") + def cross_validate(self) -> "SkillFrontmatter": + if self.x_personal_mcp.id != self.name: + raise ValueError("x-personal-mcp.id must exactly match name") + return self + + +def validate_skill_frontmatter(raw: dict[str, Any], skill_dir_name: str) -> SkillFrontmatter: + model = SkillFrontmatter.model_validate(raw) + if model.name != skill_dir_name: + raise ValueError("frontmatter name must exactly match skill directory name") + return model +``` + +Validation behavior contract: + +1. Validate required core fields and relationships during registry load before FastMCP resource or tool registration. +2. Allow unknown additive fields so frontmatter can evolve without blocking startup. +3. Treat hard contract violations, including missing required fields, invalid ids, and broken required mappings, as startup errors. +4. Treat non-critical compatibility issues as warnings when possible. +5. Error messages should include the skill path and failing field for CI readability. + +Projection mode contract for Anthropic API upload pipelines: + +1. Parse with `SkillFrontmatter` first. +2. Emit Anthropic-safe frontmatter with standard fields only. +3. Serialize repository metadata into standard `metadata` as namespaced keys. +4. Preserve the canonical authored source in `x-personal-mcp`; projection output is a build artifact. + +## Anthropic Upload Compatibility Rule + +1. Anthropic documentation guarantees behavior for standard frontmatter fields but does not explicitly guarantee handling of arbitrary unknown top-level keys. +2. Publishing pipelines that target strict API compatibility should support a projection mode that emits only standard frontmatter fields for upload. +3. In projection mode, repository extension metadata is serialized into the standard `metadata` field as namespaced keys or JSON-encoded values, while source-of-truth authoring remains in `x-personal-mcp`. + +## FastMCP Native Metadata Surfaces + +Resources support native definition metadata: + +1. `name` +2. `description` +3. `mime_type` +4. `tags` +5. `annotations`, including `readOnlyHint` and `idempotentHint` +6. `icons` +7. `meta` +8. `version` +9. `enabled`, which is deprecated in FastMCP v3 in favor of server-level enable and disable controls + +Resources also support runtime metadata through `ResourceContent.meta` and `ResourceResult.meta`. + +Tools support native definition metadata: + +1. `name` +2. `description` +3. `tags` +4. `annotations`, including `title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint` +5. `icons` +6. `meta` +7. `version` +8. `timeout` +9. `output_schema` +10. `run_in_thread` +11. `enabled`, which is deprecated in FastMCP v3 in favor of server-level enable and disable controls + +Tools also support runtime metadata through `ToolResult.meta`. + +## Frontmatter To FastMCP Mapping Contract + +At server startup, map `x-personal-mcp` into FastMCP registration as follows: + +1. `x-personal-mcp.id` defines the canonical URI namespace and identity checks. +2. `description` becomes the default description for the primary skill document resource. +3. `x-personal-mcp.tags` maps to resource and tool tags. +4. `x-personal-mcp.version` maps to resource and tool version metadata. +5. `x-personal-mcp.capabilities` becomes the registered URI list and catalog exposure. +6. `x-personal-mcp.references[*]` becomes resource templates or concrete resources with `mime_type`, read-only annotations, and `meta` that includes `skill_id`, `ref_id`, and source `path`. +7. `x-personal-mcp.depends_on` becomes catalog dependency graph metadata and validation inputs. + +## Invariants + +This contract guarantees: + +1. Anthropic-required frontmatter stays valid for custom skill upload and Claude Code loading. +2. MCP-specific metadata remains embedded in `SKILL.md` frontmatter, with no `metadata.yaml` sidecar. +3. FastMCP registration uses native metadata fields for resources and tools. +4. Reference ids and metadata can evolve with low-friction updates while internal file layout under `references/` stays refactor-friendly. + +## Non-Goals + +This contract does not define: + +1. URI versioning and deprecation rollout policy details. +2. Migration script design from existing `metadata.yaml` files. +3. Runtime caching and indexing performance tuning. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 6f64048..d6896ef 100644 --- a/docs/index.md +++ b/docs/index.md @@ -39,6 +39,9 @@ When the server is running, the health check is available at `/healthz` and the ## Architecture - [Resource-First Pattern Module Architecture](./architecture.md) +- [Content Contract](./content.md) +- [Frontmatter Contract](./frontmatter.md) +- [URI Contract](./uris.md) - [Static Docs Hosting Pattern](./mcp_layout.md) - [Skill Usage Mechanics](./usage.md) - [Copilot MCP Mechanics](./copilot.md) diff --git a/docs/mcp_contract_steps_1_5.md b/docs/mcp_contract_steps_1_5.md deleted file mode 100644 index 2f9f2c5..0000000 --- a/docs/mcp_contract_steps_1_5.md +++ /dev/null @@ -1,66 +0,0 @@ -# FastMCP Greenfield Contracts (Steps 1-5) - -## Step 1: End-State Content Contract - -1. All authored markdown lives under docs/. -2. Skill docs live under docs/skills//. -3. Canonical skill shape is: - -```text -docs/ - skills/ - / - SKILL.md - references/ -``` - -4. SKILL.md is required for every skill. -5. references/ is the only place for skill-specific supporting docs. -6. Skill directories are ownership boundaries. -7. Skill id rules: - - lowercase kebab-case - - starts with a letter - - directory name matches skill id - - SKILL frontmatter id matches directory name - -## Step 2: SKILL Frontmatter and Metadata Contract - -1. name and description are required top-level frontmatter fields. -2. Repository indexing metadata lives in x-personal-mcp. -3. x-personal-mcp fields: - - required: id, version, capabilities - - optional: tags, depends_on, references -4. references maps stable ref ids to skill-relative markdown paths under references/. -5. metadata.yaml sidecars are not part of the canonical model. - -## Step 3: URI Contract and Compatibility Policy - -Canonical URI surface: - -1. resource://catalog/skills_index -2. resource://catalog/skills/{skill_id} -3. resource://skills/{skill_id}/document -4. resource://skills/{skill_id}/references/{ref_id} -5. resource://docs/{path*} - -Rules: - -1. skill_id and ref_id are lowercase kebab-case. -2. docs path is markdown-only and cannot traverse outside docs/. -3. URI families are unversioned and canonical in this phase. -4. Breaking changes use direct replacement with no compatibility aliases. - -## Step 4: Docs Registry Loader Contract - -1. Loader uses importlib.resources.files(...) and Traversable APIs. -2. Startup validates SKILL frontmatter schema, id invariants, reference integrity, dependency graph, and URI uniqueness. -3. Registry is immutable for request-time reads. -4. Invalid docs state is a hard startup error. - -## Step 5: Registry-Driven Resource Registration Contract - -1. FastMCP resources are registered from the validated registry. -2. RFC6570 templates are used for parameterized routes. -3. Docs resources declare explicit MIME types. -4. Docs resources include readOnlyHint and idempotentHint annotations. -5. Duplicate registrations fail startup via strict duplicate policy. diff --git a/docs/mcp_layout.md b/docs/mcp_layout.md index ba56d79..20b015d 100644 --- a/docs/mcp_layout.md +++ b/docs/mcp_layout.md @@ -29,8 +29,10 @@ treeView-beta "docs" "index.md" "architecture.md" + "content.md" + "frontmatter.md" "mcp_layout.md" - "mcp_contract_steps_1_5.md" + "uris.md" "skills" "new-skill" "SKILL.md" @@ -153,8 +155,6 @@ When clients cannot attach MCP resources directly, thin catalog tools may retrie ## URI Compatibility Policy -This phase is a greenfield break-and-replace baseline. - 1. Canonical URIs are the only supported URIs in this runtime. 2. No backward-compatibility aliases or dual registration paths are maintained. 3. Contract changes should update clients to canonical URIs directly. diff --git a/docs/new_skill.md b/docs/new_skill.md index 7b5cb1f..3c13f94 100644 --- a/docs/new_skill.md +++ b/docs/new_skill.md @@ -1,8 +1,10 @@ # Hooking Up a New Skill -Use this checklist to add a new skill in the Phase 1 docs-first model. +Use this checklist to add a new skill in the docs-first model. -## Step 1 Contract: Canonical Skill Shape +For the full contract details, see [Content Contract](./content.md), [Frontmatter Contract](./frontmatter.md), and [URI Contract](./uris.md). + +## Canonical Skill Shape Create one skill directory under `docs/skills/`: @@ -22,7 +24,7 @@ Rules: 3. Skill directories are ownership boundaries; no cross-skill writes. 4. `skill-id` is lowercase kebab-case and should remain stable. -## Step 2 Contract: SKILL.md Frontmatter +## SKILL.md Frontmatter `SKILL.md` frontmatter is authoritative for metadata. @@ -74,7 +76,7 @@ Reference manifest rules: No `metadata.yaml` sidecar is part of this model. -## Step 3 Contract: URI Surface +## URI Surface Canonical resource URIs for a skill: diff --git a/docs/uris.md b/docs/uris.md new file mode 100644 index 0000000..b852892 --- /dev/null +++ b/docs/uris.md @@ -0,0 +1,114 @@ +# URI Contract + +This page defines the canonical resource URI contract, template parameter rules, and compatibility policy. + +## Canonical URI Surface + +The public, preferred URIs are: + +1. `resource://catalog/skills_index` +2. `resource://catalog/skills/{skill_id}` +3. `resource://skills/{skill_id}/document` +4. `resource://skills/{skill_id}/references/{ref_id}` +5. `resource://docs/{path*}` + +Contract intent: + +1. Catalog URIs are discovery surfaces. +2. Skill URIs are the primary per-skill guidance surfaces. +3. The docs wildcard URI is a direct authored-markdown access surface under `docs/`. + +## URI Semantics + +### `resource://catalog/skills_index` + +1. Returns a compact list of skill records for discovery. +2. Contains one entry per `skill_id`. +3. Includes enough metadata for client-side selection, at minimum `id`, `name`, `description`, `tags`, and `capabilities`. + +### `resource://catalog/skills/{skill_id}` + +1. Returns one normalized record for `skill_id`. +2. Includes the canonical document URI and declared reference ids. +3. Returns not found when `skill_id` does not exist. + +### `resource://skills/{skill_id}/document` + +1. Returns the canonical `SKILL.md` authored content for that skill. +2. `skill_id` must satisfy the stable skill id rules from the content contract. + +### `resource://skills/{skill_id}/references/{ref_id}` + +1. Returns one reference document declared in the skill frontmatter references manifest. +2. `ref_id` is the stable public handle for that reference document. + +### `resource://docs/{path*}` + +1. Returns authored markdown at a normalized relative path under `docs/`. +2. Supports nested paths via RFC6570 wildcard expansion. +3. Typical examples include `index.md`, `usage.md`, `skills//SKILL.md`, and `skills//references/.md`. + +## Template Parameter And Validation Rules + +### `skill_id` + +1. Lowercase kebab-case. +2. Must satisfy the stable skill id rules from the content contract. + +### `ref_id` + +1. Lowercase kebab-case. +2. Must be declared in the skill's references manifest. + +### `path*` + +1. Relative POSIX path only. +2. No leading slash. +3. No `..` traversal segments. +4. Resolves only inside `docs/`. +5. Markdown-only in the end state, meaning `.md` files. + +## URI Versioning Policy + +Default rule: + +1. Keep URIs unversioned by default. +2. Allow URI and payload updates when they improve clarity or implementation simplicity. + +Breaking-change rule: + +1. Breaking changes use direct replacement of the canonical URI family. +2. No compatibility aliases or dual URI families are maintained. + +FastMCP version metadata usage: + +1. Resource `version` metadata may be used for implementation and version discovery. +2. URI readability and maintainability remain the primary contract. + +## Reference Id Compatibility Policy + +`ref_id` is the public identifier for a reference document, separate from file path. + +Rules: + +1. Prefer keeping `ref_id` stable when practical. +2. File paths may change without URI churn as long as the mapped `ref_id` still resolves. +3. If a reference is renamed, introduce a new `ref_id` and treat the old one as retired. +4. Avoid reusing retired `ref_id` values for unrelated content. + +## Invariants + +This contract guarantees: + +1. One canonical URI pattern per core capability surface. +2. Fast, low-friction URI evolution through direct replacement of canonical URIs. +3. A single canonical catalog URI family with no alias maintenance overhead. +4. Reference mappings can evolve with minimal churn. + +## Non-Goals + +This contract does not define: + +1. Implementation-specific transform wiring details, such as `VersionFilter`, mounts, or provider composition. +2. Migration script mechanics for auto-generating aliases. +3. Authorization policy design for URI-level access control. \ No newline at end of file diff --git a/zensical.toml b/zensical.toml index 8ae8d2f..e4adb1a 100644 --- a/zensical.toml +++ b/zensical.toml @@ -48,9 +48,11 @@ nav = [ { "Home" = "index.md" }, { "Guide" = [ { "Arch" = "architecture.md" }, + { "Content" = "content.md" }, + { "Frontmatter" = "frontmatter.md" }, + { "URIs" = "uris.md" }, { "MCP" = "mcp_layout.md" }, { "Copilot" = "copilot.md" }, - { "Contracts 1-5" = "mcp_contract_steps_1_5.md" }, { "Usage" = "usage.md" }, { "Future Work" = "future_work.md" }, { "New Skill" = "new_skill.md" },