Pular para o conteúdo

kds-public-api

api specs/api/kds-public-api.kmd

Corpo da especificação

KDS Public API (v1)

Normative contract for the JSON + text endpoints under https://kds.koder.dev/api/v1/ and the AI-agent discovery surfaces at https://kds.koder.dev/llms.txt + /llms-full.txt.

Consumers today:

  • engines/sdk/koder-design-lsp (editor hover + autocomplete from tokens.json, 24h TTL cache)
  • Figma sync (per-deploy snapshot of tokens.json)
  • AI agents (Claude Code, Cursor, Copilot, Gemini) via llms.txt + llms-full.txt
  • Internal monitors / scripts
  • Future: MCP server (tools/design-gen#117)

This spec exists so consumers can pin against a known contract and the generator can change implementation without silently breaking them.

Status: v0.1.0 Draft. Move to Ratified when: (a) every endpoint below has a passing contract test in tools/design-gen/tests/regression/, AND (b) at least one external consumer (LSP) is wired to validate against the JSON schemas before parsing.

R1 — Endpoint inventory

The canonical surface, as of v0.1.0:

PathMethodContent-TypePurpose
/api/v1/index.jsonGETapplication/jsonEndpoint catalog discovery (10+ endpoints)
/api/v1/specs.jsonGETapplication/jsonCatalog of every published spec (slug + locale URLs + kind + summary)
/api/v1/specs/<slug>.jsonGETapplication/jsonPer-spec payload (full frontmatter + body markdown + cross-refs)
/api/v1/specs/openapi.yamlGETtext/yamlOpenAPI 3.1 description of /api/v1/specs/*
/api/v1/tokens.jsonGETapplication/jsonLSP-consumable token manifest (Verge tokens + presets)
/<locale>/search-index.jsonGETapplication/jsonPer-locale full-text search index
/<locale>/mcp/descriptor.jsonGETapplication/jsonMCP resource descriptor (future MCP server input — #117)
/<locale>/llms.txtGETtext/plain; charset=utf-8llmstxt.org-compliant AI agent discovery index
/<locale>/llms-full.txtGETtext/plain; charset=utf-8Full markdown corpus for RAG ingestion
/llms.txtGETtext/plain; charset=utf-8Locale-negotiated alias of /<default-locale>/llms.txt
/sitemap.xmlGETapplication/xmlCrawler discovery (env-aware noindex per policies/environments.kmd)
/feed.xmlGETapplication/rss+xmlRSS feed of versioned releases

Locales served today: en-US, pt-BR, es-ES.

Future endpoints (planned, not part of v1):

  • /api/v1/index/<kind>.json (per-kind subindex — #110)
  • /mcp (MCP HTTP+SSE server — #117)

R2 — Response shapes (JSON schema fragments)

/api/v1/index.json

{
  "endpoints": [
    {
      "url": "https://kds.koder.dev/api/v1/specs.json",
      "kind": "catalog",
      "description": "Full spec catalog with cross-refs"
    },
    {
      "url": "https://kds.koder.dev/api/v1/tokens.json",
      "kind": "tokens-manifest",
      "description": "Verge + UI-style token manifest"
    }
  ],
  "_meta": {
    "version": "v1",
    "generated_at": "2026-05-24T18:00:00Z",
    "commit_sha": "abc123"
  }
}

/api/v1/specs.json

{
  "specs": [
    {
      "slug": "verge",
      "kind": "theme",
      "name": "Verge (v0 — Adwaita-based)",
      "summary": "Canonical visual language of the Koder Design System",
      "locales": {
        "en-US": "https://kds.koder.dev/en-US/themes/verge/",
        "pt-BR": "https://kds.koder.dev/pt-BR/themes/verge/",
        "es-ES": "https://kds.koder.dev/es-ES/themes/verge/"
      },
      "source": "meta/docs/stack/specs/themes/verge.kmd"
    }
  ]
}

/api/v1/tokens.json

{
  "verge": {
    "color": { "primary": "#3584e4", "...": "..." },
    "spacing": { "1": "4px", "2": "8px", "...": "..." },
    "radius": { "sm": "4px", "md": "8px", "...": "..." }
  },
  "presets": [ { "slug": "material3", "tokens": {...} } ]
}

Schemas above are descriptive baselines. The implementation may add fields; consumers MUST tolerate unknown fields.

R3 — Versioning policy

/api/v1/ is the major version. Backwards-compatible changes ship in place; breaking changes trigger a new major path prefix (/api/v2/).

Backwards-compatible:

  • Adding new fields to existing response shapes
  • Adding new endpoints under /api/v1/
  • Adding new spec kinds to existing catalog responses
  • Adding new locales (existing entries gain locales.<new> keys)
  • Loosening field types (string → string | null)

Breaking (require /api/v2/):

  • Removing or renaming any field
  • Changing the type of a field (string → number, scalar → object)
  • Removing an endpoint
  • Removing a locale (consumers may have pinned URLs)
  • Changing the semantics of a value within the same field type

Major-version bumps SHOULD ship with at least 90 days of /api/v1/ overlap so consumers can migrate. Removal of /api/v1/ requires a ticketed sunset announcement.

R4 — Compatibility guarantees

Consumers MAY rely on these:

  • G1 — JSON responses are valid UTF-8 with no BOM
  • G2 — Top-level keys named in this spec WILL be present in every response (no conditional fields at the top level)
  • G3 — URLs in responses are always absolute (https://kds.koder.dev/...), never relative or protocol-relative
  • G4 — Slugs are stable across renames; if a spec slug changes, the old slug remains addressable via a 301 redirect for the remainder of /api/v1/
  • G5 — Locale codes are BCP 47 (en-US, pt-BR, es-ES); locale in URL ALWAYS uses uppercase region code
  • G6_meta object (when present) is informational; consumers MUST NOT fail if absent (it's only emitted when build-time env vars are set — see R5)

Consumers MUST NOT rely on these:

  • N1 — Order of array elements (sort client-side if order matters)
  • N2 — Whitespace / formatting of JSON payloads (may be minified)
  • N3 — Specific _meta field shape beyond commit_sha + generated_at
  • N4 — That /api/v1/index.json will list EVERY endpoint forever (the catalog grows; consumers should re-fetch on cache miss, not hard-code endpoint URLs)

The generator-emitted Cache-Control headers (set in tools/design-gen/deploy/prd.kds.koder.dev.site.toml):

PathCache-ControlRationale
/api/v1/tokens.jsonpublic, max-age=3600, stale-while-revalidate=86400Tokens shift slowly; 1h fresh + 24h SWR
/api/v1/specs.json, /api/v1/index.jsonpublic, max-age=300, stale-while-revalidate=3600Catalog — 5min fresh + 1h SWR
/<locale>/llms.txt, /<locale>/llms-full.txtpublic, max-age=3600, stale-while-revalidate=86400Same as tokens — AI agents
/<locale>/search-index.jsonpublic, max-age=300, stale-while-revalidate=3600Same as catalog
/<locale>/mcp/descriptor.jsonpublic, max-age=3600, stale-while-revalidate=86400Same as tokens

Consumers SHOULD honor stale-while-revalidate for resilience and to reduce origin pressure during deploy windows. ETag + Last-Modified SHOULD be present (Jet emits these automatically for static files).

R6 — Discovery convention

Discovery starts at /api/v1/index.json — every other endpoint under /api/v1/ MUST appear there. Future addition: /.well-known/kds.json MAY ship (RFC 8615) for cross-origin discovery without a path guess.

llms.txt-style endpoints follow the llmstxt.org convention:

  • /llms.txt — short index, prepended with locale-negotiation hint
  • /<locale>/llms.txt — per-locale (canonical)
  • /<locale>/llms-full.txt — full corpus per locale

Search:

  • /<locale>/search-index.json — per-locale full-text index; client-side runtime filters

When build-time env vars KDS_COMMIT_SHA + KDS_GENERATED_AT are set, the generator emits a _meta block in JSON responses + a header comment in llms.txt:

> <!-- kds-fingerprint commit=abc123 generated=2026-05-24T18:00:00Z -->

Plus a standalone dist/.deploy-fingerprint.json:

{
  "commit_sha": "abc123",
  "generated_at": "2026-05-24T18:00:00Z",
  "tool": "design-gen",
  "version": "v0.1.0"
}

A freshness-probe tool (dev/koder-tools/cmd/koder-kds-freshness-probe/) runs on a cron schedule comparing live kds.koder.dev/llms.txt fingerprint against the latest commit on master touching tools/design-gen/ or meta/docs/stack/specs/. Drift > 24h opens an alert.

R8 — Body content trust model

Spec bodies in /api/v1/specs/<slug>.json (and the corresponding <body> HTML rendered at /<locale>/<kind>/<slug>.html) are first-party PR-gated content, NOT arbitrary user input.

R8.1 — Markdown is rendered through Goldmark with html.WithUnsafe() enabled (tools/design-gen/internal/kinds/pattern.go). Inline raw HTML in spec bodies — <details>, <style> scoped to the page, inline <script> for interactive playgrounds — renders verbatim into both the published HTML and the API payload body.

R8.2 — Consumers of /api/v1/specs/*.json MAY render body / body_html fields without additional sanitization. Doing so is safe ONLY because the trust boundary is "authored by a Koder Stack contributor with merge rights to meta/docs/stack/", and that boundary is enforced by the same PR + review workflow that gates any other code change in the monorepo.

R8.3 — Consumers that redistribute spec bodies into contexts where the original trust boundary does not extend (e.g. embedding a spec body inside a multi-tenant SaaS dashboard where end-users can deep-link KDS content) MUST sanitize before rendering. The KDS API does not pre-sanitize; the integration carries the responsibility.

R8.4 — Cross-link: policies/security.kmd for the broader Stack posture on trusted vs untrusted content boundaries.

T1 — Endpoint reachability test

/api/v1/index.json resolves with HTTP 200 + application/json Content-Type for every published endpoint.

curl -sf https://kds.koder.dev/api/v1/index.json | jq -e '.endpoints | length > 5'

T2 — Schema validity test

/api/v1/specs.json parses as valid JSON; every entry has slug, kind, name, summary, locales, source fields per R2.

T3 — URL absolutization test

Every URL in /api/v1/specs.json .locales values starts with https://kds.koder.dev/ (G3 enforcement).

T4 — Locale parity test

Every spec entry has locales.en-US; entries with locales.pt-BR / locales.es-ES resolve to live pages.

T5 — Cache headers test (post-#108)

curl -sI https://kds.koder.dev/api/v1/tokens.json returns cache-control: public, max-age=3600, stale-while-revalidate=86400.

T6 — Slug stability test

Specs in done/ backlog (renamed historically) still resolve via slug redirects (G4 enforcement). Requires a test fixture mapping old slug → 301 → new slug.

N1 — Removed endpoint returns 404

A removed endpoint MUST return HTTP 404 (not 200 with empty body).

N2 — Bad locale returns 404

/api/v1/specs/<slug>/?locale=xx-XX returns 404, not falls back to default locale (consumer must request a supported locale).

N3 — Malformed _meta is tolerated

A future build that emits a NEW _meta field MUST NOT break consumers that parsed v0.1.0 (compatibility test runs against historical fixture payloads).

Tooling

  • Generator: tools/design-gen/internal/api/ (api.go, index.go, mcp.go) + internal/llmstxt/llmstxt.go
  • Token emitter: tools/design-gen/internal/tokens/extract.go
  • Contract tests: tools/design-gen/tests/regression/api_*_test.go (TBD per T1-T6)
  • Freshness probe: dev/koder-tools/cmd/koder-kds-freshness-probe/ (per #112)

Não-escopo

  • Write API — KDS is read-only; specs change via PR against meta/docs/stack/specs/
  • gRPC / GraphQL alternatives — static JSON is the contract
  • Per-user authentication — KDS is anonymous read-only
  • Webhooks / push notifications — consumers poll with the SWR Cache-Control hint
  • tools/design-gen#108 — Cache-Control headers (R5)
  • tools/design-gen#110 — Per-kind index split
  • tools/design-gen#112 — Freshness fingerprint + probe (R7)
  • tools/design-gen#117 — MCP server (alternative live query surface — separate from /api/v1/)
  • meta/docs/stack/registries/token-consumers.md — every consumer pinning against this API

Referências