diff --git a/docs/concepts/scoring.md b/docs/concepts/scoring.md index 10ab297..b762784 100644 --- a/docs/concepts/scoring.md +++ b/docs/concepts/scoring.md @@ -46,7 +46,7 @@ Every agent card validation returns three independent score dimensions: --- - How well does the agent card conform to the A2A v0.3.0 specification? + How well does the agent card conform to the A2A v{{ protocol_version }} specification? Measures protocol adherence, required fields, format validation, and data quality. @@ -74,7 +74,7 @@ Each dimension has its own detailed breakdown, rating enum, and independent scor ## ๐Ÿ“„ Dimension 1: Spec Compliance (100 points) -**What it measures:** How well the agent card adheres to the A2A v0.3.0 specification. +**What it measures:** How well the agent card adheres to the A2A v{{ protocol_version }} specification. **Why it matters:** Protocol compliance ensures interoperability. An agent with poor compliance won't work correctly with other agents, registries, or tooling. diff --git a/docs/concepts/validation.md b/docs/concepts/validation.md index 1632e50..8dc4987 100644 --- a/docs/concepts/validation.md +++ b/docs/concepts/validation.md @@ -113,7 +113,7 @@ If only a domain is provided, CapiscIO will attempt discovery: ## Schema Validation -### Required Fields (A2A v0.3.0) +### Required Fields (A2A v{{ protocol_version }}) #### Basic Required Fields - `name`: Agent display name @@ -123,7 +123,7 @@ If only a domain is provided, CapiscIO will attempt discovery: - `version`: Agent version (semver format) #### A2A Protocol Required Fields -- `protocolVersion`: A2A protocol version (e.g., "0.3.0") +- `protocolVersion`: A2A protocol version (e.g., "{{ protocol_version }}") - `preferredTransport`: Primary transport protocol #### Provider Structure @@ -275,7 +275,7 @@ Each skill in the `skills` array must have: **Warning Generated:** ``` LEGACY_DISCOVERY_ENDPOINT: Agent discovered via legacy endpoint. -The A2A v0.3.0 specification recommends using /.well-known/agent-card.json +The A2A v{{ protocol_version }} specification recommends using /.well-known/agent-card.json ``` ### Transport Protocol Validation @@ -297,7 +297,7 @@ The A2A v0.3.0 specification recommends using /.well-known/agent-card.json โœ… A2A AGENT VALIDATION PASSED Agent: https://example.com/.well-known/agent-card.json Score: 100/100 -Version: 0.3.0 (Strictness: progressive) +Version: {{ protocol_version }} (Strictness: progressive) ๐Ÿ” VALIDATION SUMMARY: ๐Ÿ“Š 3 checks performed: 3 passed, 0 failed, 0 warnings @@ -310,8 +310,8 @@ Version: 0.3.0 (Strictness: progressive) โœ… Endpoint Connectivity All endpoints are accessible and responding Duration: 195ms -โœ… A2A v0.3.0 Features - All v0.3.0 features are properly configured +โœ… A2A v{{ protocol_version }} Features + All v{{ protocol_version }} features are properly configured ๐Ÿ† Perfect! Your agent passes all validations. ๐Ÿš€ Your agent is ready for deployment! @@ -331,14 +331,14 @@ Version: 0.3.0 (Strictness: progressive) "id": "schema_validation", "name": "Schema Validation", "status": "passed", - "message": "Agent card conforms to A2A v0.3.0 schema", + "message": "Agent card conforms to A2A v{{ protocol_version }} schema", "duration": 12, "details": "Agent card structure is valid" } ], "versionInfo": { - "detectedVersion": "0.3.0", - "validatorVersion": "0.3.0", + "detectedVersion": "{{ protocol_version }}", + "validatorVersion": "{{ protocol_version }}", "strictness": "progressive", "compatibility": { "compatible": true, diff --git a/docs/getting-started/cicd/2-action.md b/docs/getting-started/cicd/2-action.md index ceeeeec..008671a 100644 --- a/docs/getting-started/cicd/2-action.md +++ b/docs/getting-started/cicd/2-action.md @@ -68,7 +68,7 @@ cat > agent-card.json << 'EOF' "description": "A sample A2A agent", "url": "https://example.com/agent", "version": "1.0.0", - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", "provider": { "organization": "My Company" }, @@ -101,7 +101,7 @@ When the action runs, you'll see output like: ``` โœ… A2A AGENT VALIDATION PASSED Score: 75/100 -Version: 0.3.0 +Version: {{ protocol_version }} Agent passed with warnings ISSUES FOUND: diff --git a/docs/getting-started/secure/2-sdk.md b/docs/getting-started/secure/2-sdk.md index 1932d64..8ad0e65 100644 --- a/docs/getting-started/secure/2-sdk.md +++ b/docs/getting-started/secure/2-sdk.md @@ -23,7 +23,7 @@ python -c "import capiscio_sdk; print(capiscio_sdk.__version__)" Expected output: ``` -2.5.0 +{{ capiscio_version }} ``` --- @@ -56,7 +56,7 @@ async def get_agent_card(): "description": "An A2A agent with CapiscIO security", "url": "http://localhost:8000", "version": "1.0.0", - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", "provider": { "organization": "My Company" }, @@ -124,7 +124,7 @@ async def get_agent_card(): "description": "An A2A agent with CapiscIO security", "url": "http://localhost:8000", "version": "1.0.0", - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", "provider": {"organization": "My Company"}, "capabilities": {"streaming": False, "pushNotifications": False}, "public_keys": [ @@ -233,7 +233,7 @@ You'll see your public key embedded: "use": "sig" } ], - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", ... } ``` diff --git a/docs/getting-started/secure/5-production.md b/docs/getting-started/secure/5-production.md index 62cf07a..e7a5757 100644 --- a/docs/getting-started/secure/5-production.md +++ b/docs/getting-started/secure/5-production.md @@ -57,7 +57,7 @@ Create a proper `agent-card.json`: "description": "Production A2A agent for My Company", "url": "https://agent.mycompany.com", "version": "1.0.0", - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", "provider": { "organization": "My Company Inc.", "url": "https://mycompany.com" diff --git a/docs/getting-started/validate/1-intro.md b/docs/getting-started/validate/1-intro.md index ff16aba..b3fb978 100644 --- a/docs/getting-started/validate/1-intro.md +++ b/docs/getting-started/validate/1-intro.md @@ -54,7 +54,7 @@ Here's a minimal example: { "name": "My Agent", "url": "https://example.com/agent", - "protocolVersion": "0.3.0" + "protocolVersion": "{{ protocol_version }}" } ``` diff --git a/docs/getting-started/validate/2-install.md b/docs/getting-started/validate/2-install.md index 3d0c2a0..948c2c3 100644 --- a/docs/getting-started/validate/2-install.md +++ b/docs/getting-started/validate/2-install.md @@ -25,7 +25,7 @@ The CapiscIO CLI is available for Node.js and Python. Choose your preferred plat Expected output: ``` - capiscio/2.5.0 (darwin-arm64) + capiscio/{{ capiscio_version }} (darwin-arm64) ``` === "pip (Python)" @@ -42,7 +42,7 @@ The CapiscIO CLI is available for Node.js and Python. Choose your preferred plat Expected output: ``` - capiscio/2.5.0 (darwin-arm64) + capiscio/{{ capiscio_version }} (darwin-arm64) ``` === "Go (Direct)" @@ -142,7 +142,7 @@ cat > agent-card.json << 'EOF' "description": "A sample A2A agent for learning CapiscIO", "url": "https://example.com/agent", "version": "1.0.0", - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", "provider": { "organization": "My Company" }, diff --git a/docs/getting-started/validate/4-reports.md b/docs/getting-started/validate/4-reports.md index 1241ccb..cebed6e 100644 --- a/docs/getting-started/validate/4-reports.md +++ b/docs/getting-started/validate/4-reports.md @@ -55,11 +55,8 @@ Our sample agent card scores 75/100. Let's improve it: "description": "A sample A2A agent for learning CapiscIO", "url": "https://example.com/agent", "version": "1.0.0", - "protocolVersion": "0.3.0", + "protocolVersion": "{{ protocol_version }}", "provider": { - "organization": "My Company", - "url": "https://mycompany.com" - }, "capabilities": { "streaming": false, "pushNotifications": false, diff --git a/docs/reference/grpc.md b/docs/reference/grpc.md index e76743d..d402337 100644 --- a/docs/reference/grpc.md +++ b/docs/reference/grpc.md @@ -1,10 +1,5 @@ # gRPC Services - - `capiscio-core` exposes gRPC services for validation, scoring, and badge operations. The gRPC server is **automatically started and managed by the SDK** when using the Python or Node.js SDKs. !!! note "No Manual Server Start Required" diff --git a/docs/reference/sdk-python/badge.md b/docs/reference/sdk-python/badge.md index 8bea629..7d662f3 100644 --- a/docs/reference/sdk-python/badge.md +++ b/docs/reference/sdk-python/badge.md @@ -32,316 +32,131 @@ if result.valid: else: print(f"โŒ Verification failed: {result.error}") ``` -``` --- ## Functions -### verify_badge - -Verify a Trust Badge token with full RFC-002 validation. - -```python -def verify_badge( - token: str, - *, - trusted_issuers: Optional[List[str]] = None, - audience: Optional[str] = None, - mode: VerifyMode = VerifyMode.ONLINE, - skip_revocation_check: bool = False, - skip_agent_status_check: bool = False, - public_key_jwk: Optional[str] = None, - fail_open: bool = False, - stale_threshold_seconds: int = 300, - options: Optional[VerifyOptions] = None, -) -> VerifyResult -``` - -**Parameters:** - -| Parameter | Type | Description | -|-----------|------|-------------| -| `token` | `str` | The badge JWT/JWS token to verify | -| `trusted_issuers` | `List[str]` | Trusted issuer URLs. If empty, all issuers accepted | -| `audience` | `str` | Your service URL for audience validation | -| `mode` | `VerifyMode` | Verification mode (online, offline, hybrid) | -| `skip_revocation_check` | `bool` | Skip revocation check (testing only) | -| `skip_agent_status_check` | `bool` | Skip agent status check (testing only) | -| `public_key_jwk` | `str` | Override public key for offline verification | -| `fail_open` | `bool` | If `True`, treat verification errors as valid (use with caution) | -| `stale_threshold_seconds` | `int` | Max staleness for cached revocation data (default: 300) | -| `options` | `VerifyOptions` | Alternative to individual parameters | - -**Returns:** `VerifyResult` with validation status and claims. - -**Example:** - -```python -from capiscio_sdk import verify_badge - -# Basic verification -result = verify_badge(token) - -# With trusted issuers (recommended for production) -result = verify_badge( - token, - trusted_issuers=["https://registry.capisc.io", "https://my-ca.example.com"], -) - -# With audience check -result = verify_badge( - token, - audience="https://my-agent.example.com", -) -``` - ---- - -### parse_badge - -Parse badge claims without verification. Use for inspection before full verification. - -```python -def parse_badge(token: str) -> BadgeClaims -``` - -**Parameters:** - -| Parameter | Type | Description | -|-----------|------|-------------| -| `token` | `str` | The badge JWT/JWS token to parse | - -**Returns:** `BadgeClaims` object with parsed claims. - -**Raises:** `ValueError` if the token cannot be parsed. - -**Example:** - -```python -from capiscio_sdk import parse_badge - -# Inspect badge before verification -claims = parse_badge(token) -print(f"Agent: {claims.agent_id}") -print(f"Issuer: {claims.issuer}") -print(f"Expires: {claims.expires_at}") -print(f"Expired: {claims.is_expired}") -``` - ---- - -### request_badge - -Request a new Trust Badge from a Certificate Authority (async). - -```python -async def request_badge( - agent_id: str, - *, - ca_url: str = "https://registry.capisc.io", - api_key: Optional[str] = None, - domain: Optional[str] = None, - trust_level: TrustLevel = TrustLevel.LEVEL_1, - audience: Optional[List[str]] = None, - timeout: float = 30.0, -) -> str -``` - -**Parameters:** - -| Parameter | Type | Description | -|-----------|------|-------------| -| `agent_id` | `str` | Agent identifier to request badge for | -| `ca_url` | `str` | Certificate Authority URL | -| `api_key` | `str` | API key for CA authentication | -| `domain` | `str` | Agent's domain (required for verification) | -| `trust_level` | `TrustLevel` | Requested trust level | -| `audience` | `List[str]` | Optional audience restrictions | -| `timeout` | `float` | Request timeout in seconds | - -**Returns:** The signed badge JWT token. - -**Example:** - -```python -import asyncio -from capiscio_sdk import request_badge, TrustLevel - -async def get_badge(): - token = await request_badge( - agent_id="my-agent", - ca_url="https://registry.capisc.io", - api_key=os.environ["CAPISCIO_API_KEY"], - domain="example.com", - trust_level=TrustLevel.LEVEL_2, - ) - return token - -badge = asyncio.run(get_badge()) -``` - ---- - -### request_badge_sync - -Synchronous version of `request_badge`. - -```python -def request_badge_sync( - agent_id: str, - *, - ca_url: str = "https://registry.capisc.io", - api_key: Optional[str] = None, - domain: Optional[str] = None, - trust_level: TrustLevel = TrustLevel.LEVEL_1, - audience: Optional[List[str]] = None, - timeout: float = 30.0, -) -> str -``` - -**Example:** - -```python -from capiscio_sdk import request_badge_sync - -token = request_badge_sync( - agent_id="my-agent", - api_key=os.environ["CAPISCIO_API_KEY"], - domain="example.com", -) -``` +::: capiscio_sdk.badge.verify_badge + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.parse_badge + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.request_badge + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.request_badge_sync + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.request_pop_badge + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.request_pop_badge_sync + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.start_badge_keeper + options: + show_root_heading: true + show_source: false + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy --- ## Classes -### BadgeClaims - -Parsed badge claims from a Trust Badge token. - -```python -@dataclass -class BadgeClaims: - jti: str # Unique badge identifier (UUID) - issuer: str # Badge issuer URL (CA) - maps to `iss` - subject: str # Agent DID (did:key or did:web) - maps to `sub` - issued_at: datetime # When issued - maps to `iat` - expires_at: datetime # When expires - maps to `exp` - trust_level: TrustLevel # From `vc.credentialSubject.level` - domain: str # Agent's verified domain - agent_name: str = "" # Human-readable name - audience: List[str] = [] # Intended audience URLs - maps to `aud` - ial: str = "0" # Identity Assurance Level ("0" or "1", per RFC-002) - raw_claims: Optional[dict] = None # Original decoded claims dict -``` - -**Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `agent_id` | `str` | Extracted agent ID from subject DID | -| `is_expired` | `bool` | Whether badge has expired | -| `is_not_yet_valid` | `bool` | Whether badge is not yet valid | -| `has_key_binding` | `bool` | Whether badge has a confirmation key (IAL-1) | -| `confirmation_key` | `Optional[dict]` | The confirmation key JWK, if present | - -**Methods:** - -| Method | Description | -|--------|-------------| -| `from_dict(data)` | Create from dictionary | -| `to_dict()` | Convert to dictionary | - ---- - -### VerifyResult - -Result of badge verification. - -```python -@dataclass -class VerifyResult: - valid: bool # Whether valid - claims: Optional[BadgeClaims] # Parsed claims - error: Optional[str] # Error message - error_code: Optional[str] # RFC-002 error code - warnings: List[str] # Non-fatal issues - mode: VerifyMode # Mode used -``` - ---- - -### VerifyOptions - -Options for badge verification. - -```python -@dataclass -class VerifyOptions: - mode: VerifyMode = VerifyMode.ONLINE - trusted_issuers: List[str] = [] - audience: Optional[str] = None - skip_revocation_check: bool = False - skip_agent_status_check: bool = False - public_key_jwk: Optional[str] = None - fail_open: bool = False - stale_threshold_seconds: int = 300 -``` - -**Example:** - -```python -from capiscio_sdk import verify_badge, VerifyOptions, VerifyMode - -options = VerifyOptions( - mode=VerifyMode.HYBRID, - trusted_issuers=["https://registry.capisc.io"], - audience="https://my-service.example.com", -) - -result = verify_badge(token, options=options) -``` - ---- - -### VerifyMode - -Badge verification mode. - -```python -class VerifyMode(Enum): - ONLINE = "online" # Real-time checks against registry - OFFLINE = "offline" # Local trust store and cache only - HYBRID = "hybrid" # Try online, fall back to cache -``` - ---- - -### TrustLevel - -Trust level as defined in RFC-002 ยง5. - -```python -class TrustLevel(Enum): - # RFC-002 ยง5 Trust Levels - LEVEL_0 = "0" # Self-Signed (SS) - Development only - LEVEL_1 = "1" # Registered (REG) - Account registration - LEVEL_2 = "2" # Domain Validated (DV) - DNS/HTTP challenge - LEVEL_3 = "3" # Organization Validated (OV) - Legal entity - LEVEL_4 = "4" # Extended Validated (EV) - Security audit -``` - -| Level | Name | Description | -|-------|------|-------------| -| 0 | Self-Signed (SS) | Development only, `did:key` issuer, `iss` = `sub` | -| 1 | Registered (REG) | Account registration with CapiscIO CA | -| 2 | Domain Validated (DV) | DNS TXT or HTTP challenge, domain ownership | -| 3 | Organization Validated (OV) | DV + legal entity verification | -| 4 | Extended Validated (EV) | OV + manual security audit | - -!!! warning "Level 0 (Self-Signed)" - Level 0 badges are for **development only**. In production, verifiers MUST reject Level 0 badges by default. Use `--accept-self-signed` (CLI) to explicitly opt in during development. +::: capiscio_sdk.badge.BadgeClaims + options: + show_root_heading: true + show_source: false + members_order: source + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.VerifyResult + options: + show_root_heading: true + show_source: false + members_order: source + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.VerifyOptions + options: + show_root_heading: true + show_source: false + members_order: source + heading_level: 3 + show_signature_annotations: true + separate_signature: true + docstring_style: google + docstring_section_style: spacy + +::: capiscio_sdk.badge.VerifyMode + options: + show_root_heading: true + show_source: false + heading_level: 3 + docstring_style: google + +::: capiscio_sdk.badge.TrustLevel + options: + show_root_heading: true + show_source: false + heading_level: 3 + docstring_style: google --- diff --git a/docs/reference/sdk-python/config.md b/docs/reference/sdk-python/config.md index dd58395..a809d8e 100644 --- a/docs/reference/sdk-python/config.md +++ b/docs/reference/sdk-python/config.md @@ -21,11 +21,13 @@ config = SecurityConfig.production() config = SecurityConfig.strict() # Custom configuration +from capiscio_sdk.config import DownstreamConfig, UpstreamConfig + config = SecurityConfig( - validate_inbound=True, - validate_outbound=True, - require_signature=True, - log_level="INFO" + downstream=DownstreamConfig(require_signatures=True), + upstream=UpstreamConfig(validate_agent_cards=True), + strict_mode=True, + fail_mode="block", ) ``` diff --git a/docs/reference/sdk-python/mcp.md b/docs/reference/sdk-python/mcp.md index de5f42d..89c0a06 100644 --- a/docs/reference/sdk-python/mcp.md +++ b/docs/reference/sdk-python/mcp.md @@ -362,7 +362,7 @@ def health(client_version: str = "") -> dict **Example:** ```python -status = client.mcp.health(client_version="capiscio-sdk-python/2.5.0") +status = client.mcp.health(client_version="capiscio-sdk-python/{{ capiscio_version }}") if status["healthy"]: print(f"โœ… MCP service healthy (core {status['core_version']})") diff --git a/docs/reference/server/badge-ca.md b/docs/reference/server/badge-ca.md index 7cece0d..6fc130a 100644 --- a/docs/reference/server/badge-ca.md +++ b/docs/reference/server/badge-ca.md @@ -1,11 +1,5 @@ # Badge Certificate Authority - - The capiscio-server includes a built-in Certificate Authority (CA) for issuing trust badges with two identity assurance levels. --- diff --git a/docs/reference/server/deployment.md b/docs/reference/server/deployment.md index c64f35c..997be31 100644 --- a/docs/reference/server/deployment.md +++ b/docs/reference/server/deployment.md @@ -1,10 +1,5 @@ # Deployment Guide - - Deploy capiscio-server in production or development environments. --- diff --git a/docs/reference/server/index.md b/docs/reference/server/index.md index 29a6f89..6125454 100644 --- a/docs/reference/server/index.md +++ b/docs/reference/server/index.md @@ -1,16 +1,12 @@ # capiscio-server Reference - - The **capiscio-server** is a commercial backend API server that powers the CapiscIO Registry. It provides agent management, badge issuance (CA-signed), and trust verification services. !!! info "Enterprise Product" capiscio-server is a commercial product available to enterprise customers. [Contact Sales](mailto:sales@capisc.io) for licensing options. !!! info "Version" - Current version: **v2.5.0** + Current version: **v{{ capiscio_version }}** ## Overview diff --git a/docs/reference/wrappers/node.md b/docs/reference/wrappers/node.md index 92cb4ed..b625a9e 100644 --- a/docs/reference/wrappers/node.md +++ b/docs/reference/wrappers/node.md @@ -87,7 +87,7 @@ Add validation to your `package.json`: "validate:json": "capiscio validate agent-card.json --json" }, "devDependencies": { - "capiscio": "^2.5.0" + "capiscio": "^{{ capiscio_version }}" } } ``` diff --git a/docs/reference/wrappers/python.md b/docs/reference/wrappers/python.md index be0937c..08ecc11 100644 --- a/docs/reference/wrappers/python.md +++ b/docs/reference/wrappers/python.md @@ -15,7 +15,7 @@ pip install capiscio Or with a specific version: ```bash -pip install capiscio==2.5.0 +pip install capiscio=={{ capiscio_version }} ``` --- diff --git a/hooks/version_vars.py b/hooks/version_vars.py new file mode 100644 index 0000000..43211a4 --- /dev/null +++ b/hooks/version_vars.py @@ -0,0 +1,18 @@ +"""MkDocs hook: replace version placeholders in markdown content. + +Replaces {{ capiscio_version }} and {{ protocol_version }} with values +defined in mkdocs.yml extra: config. This avoids the macros plugin which +conflicts with GitHub Actions {{ }} syntax in code examples. +""" + +VERSION_KEYS = {"capiscio_version", "protocol_version"} + + +def on_page_markdown(markdown, page, config, files): + """Replace version placeholders before markdown rendering.""" + extra = config.get("extra", {}) + for key in VERSION_KEYS: + value = extra.get(key) + if value: + markdown = markdown.replace("{{ " + key + " }}", str(value)) + return markdown diff --git a/mkdocs.yml b/mkdocs.yml index 39a786f..0b0ae79 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -140,7 +140,12 @@ markdown_extensions: custom_checkbox: true - pymdownx.tilde +hooks: + - hooks/version_vars.py + extra: + capiscio_version: "2.5.0" + protocol_version: "0.3.0" homepage: https://docs.capisc.io # Analytics: Cloudflare Pages auto-injects Web Analytics at the edge # Enable in: CF Dashboard โ†’ Pages โ†’ capiscio-docs โ†’ Settings โ†’ Web Analytics