{"id":51339649,"url":"https://github.com/async/api-contract","last_synced_at":"2026-07-02T06:04:45.779Z","repository":{"id":364685879,"uuid":"1268834691","full_name":"async/api-contract","owner":"async","description":"Semantic API contract surfaces, ledgers, and impact checks for Async packages.","archived":false,"fork":false,"pushed_at":"2026-06-14T02:57:57.000Z","size":31,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T04:19:58.797Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/async.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-14T01:51:12.000Z","updated_at":"2026-06-14T02:57:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/async/api-contract","commit_stats":null,"previous_names":["async/api-contract"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/async/api-contract","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async%2Fapi-contract","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async%2Fapi-contract/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async%2Fapi-contract/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async%2Fapi-contract/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/async","download_url":"https://codeload.github.com/async/api-contract/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/async%2Fapi-contract/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35035005,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-02T06:04:45.140Z","updated_at":"2026-07-02T06:04:45.761Z","avatar_url":"https://github.com/async.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @async/api-contract\n\n`@async/api-contract` is the metadata contract layer for packages and local\ntools. It lets maintainers describe multiple API concerns from one source, then\nemit stable artifacts for compatibility review, programmatic invocation, CLIs,\nlocal dashboards, MCP tools, evidence, and generated clients.\n\nThe package still treats compatibility as feature-based:\n\n```txt\nrequired.features subset_of supported.features\n```\n\nPackage versions, release tags, docs text, README prose, prompt copy, and\ndashboard layout hints do not decide compatibility unless a package maps them\nto explicit contract-bearing feature ids.\n\n## What This Solves\n\nLocal developer tools often grow the same behavior in several places:\n\n- a programmatic API for tests and library users;\n- a CLI for humans;\n- a machine JSON command surface for automation and local dashboards;\n- an MCP server for agent/tool clients;\n- schema metadata for validation, prompts, and forms;\n- docs that explain the workflow;\n- reports and receipts that prove what happened;\n- compatibility ledgers that show what changed.\n\nWhen those surfaces are maintained separately, they drift.\n`@async/api-contract` keeps behavior behind programmatic handlers and makes CLI,\ndashboard, schema, and docs surfaces projections of one metadata source.\nMCP tools follow the same rule: they are adapters over operations, not a second\nplace to implement behavior.\n\n## Core Idea\n\nDescribe the API once:\n\n- feature catalogs and compatibility surfaces;\n- schema metadata;\n- callable operations;\n- CLI projections;\n- dashboard projections;\n- MCP projections;\n- effects, receipts, reports, and transcripts;\n- docs references.\n\nThen generate review and adapter artifacts:\n\n- `api-contract.json`;\n- `API_SURFACE.md`;\n- CLI descriptors;\n- dashboard manifests;\n- MCP descriptors;\n- MCP stdio server module source;\n- typed client source;\n- machine CLI router descriptors.\n\nGenerators emit descriptors, routers, manifests, and docs. They do not execute\nbusiness logic.\n\n## Choose Your Goal\n\n### Compatibility\n\nUse feature catalogs and surfaces when the goal is to publish what a package\nsupports, requires, emits, or consumes.\n\nUse it when:\n\n- you need release-review ledgers;\n- consumers need impact checks;\n- capability compatibility should not depend on package versions.\n\nIt emits:\n\n- normalized surfaces;\n- stable surface hashes;\n- `API_SURFACE.md`;\n- diff and impact reports.\n\nIt deliberately does not own:\n\n- host-specific validation;\n- release policy;\n- runtime behavior.\n\n### Schema Metadata\n\nUse schema metadata when the goal is to describe input/output shapes for\nvalidation, prompts, forms, tables, or metadata inspection.\n\nUse it when:\n\n- a CLI needs prompt choices or validation;\n- a dashboard needs a form or table;\n- a package wants to publish shape metadata without choosing one schema library.\n\nIt emits:\n\n- JSON Schema output;\n- defaults;\n- examples;\n- field help text;\n- UI-safe widget hints;\n- prompt-safe input hints;\n- optional schema feature ids.\n\nIt deliberately does not own:\n\n- storage engines;\n- host-specific domain rules;\n- one required validator library.\n\n### Programmatic Interface\n\nUse operation contracts when the goal is to expose callable API behavior.\n\nUse it when:\n\n- tests, CLIs, dashboards, and generated clients should call one handler path;\n- removing an operation should appear in compatibility diffs;\n- local side effects need to be visible before execution.\n\nIt emits:\n\n- operation metadata;\n- operation-derived feature surfaces;\n- handler bindings;\n- standard invocation helpers.\n\nIt deliberately does not own:\n\n- business logic;\n- permissions enforcement;\n- process or filesystem policy.\n\n### Generated CLI\n\nUse CLI projections when the goal is to generate human commands and machine JSON\nendpoints from operation or schema metadata.\n\nUse it when:\n\n- humans need ergonomic commands;\n- dashboards and automation need stable JSON commands;\n- interactive prompts should be metadata-driven.\n\nIt emits:\n\n- command paths;\n- args and flags;\n- prompt metadata;\n- output mode metadata;\n- machine JSON command mapping;\n- exit-code metadata.\n\nIt deliberately does not own:\n\n- operation handlers;\n- terminal scraping;\n- dashboard state.\n\n### Generated Dashboard\n\nUse dashboard projections when the goal is to generate a local inspection UI\nfrom the same metadata.\n\nUse it when:\n\n- a local dashboard needs forms, tables, details, summaries, or logs;\n- the dashboard should call a machine CLI instead of duplicating behavior;\n- users need to inspect receipts and reports.\n\nIt emits:\n\n- operation groups;\n- form/table/detail view metadata;\n- result summaries;\n- empty states;\n- local transport config.\n\nIt deliberately does not own:\n\n- durable state authority;\n- business logic;\n- long-lived service state.\n\n### Generated MCP\n\nUse MCP projections when the goal is to expose selected operations as MCP tools.\n\nUse it when:\n\n- agent clients should discover and call tool operations;\n- MCP exposure needs to be explicit and reviewable;\n- maintainers want generated `registerTool()` boilerplate without adding an MCP\n  runtime dependency to this package.\n\nIt emits:\n\n- MCP tool descriptors;\n- tool names, titles, descriptions, annotations, schemas, effects, and receipts;\n- TypeScript stdio server module source.\n\nIt deliberately does not own:\n\n- business logic;\n- the MCP runtime dependency;\n- MCP resources, prompts, Streamable HTTP, auth, or subscriptions.\n\n### Evidence And Receipts\n\nUse effects and receipts when the goal is to make local work auditable.\n\nUse it when:\n\n- operations write files;\n- operations spawn processes;\n- tools produce reports, transcripts, or verification logs;\n- users need durable evidence beyond terminal output.\n\nIt emits:\n\n- effect lists;\n- receipt path templates;\n- report/transcript/verification metadata.\n\nIt deliberately does not own:\n\n- secret handling;\n- transcript storage policy;\n- verification semantics for a host package.\n\n## Concepts\n\n### Feature Surfaces\n\nA `Surface` is normalized runtime data with sorted unique feature ids and a\nstable hash. Compatibility is checked by comparing required features with\nsupported features.\n\n### Schema Metadata\n\nA schema is a portable description of shape plus optional generation hints.\nSchemas can provide JSON Schema, defaults, examples, enum labels, field help\ntext, prompt hints, and widget hints.\n\n### Operations\n\nAn operation is a callable unit such as `project.init`, `project.verify`, or\n`project.report`. Operations can derive compatibility features such as\n`operation.project.init`, so removed callable capabilities appear in normal diff\nand impact workflows.\n\n### Projections\n\nProjections describe user-facing surfaces. A CLI projection names command paths,\nflags, positional arguments, prompts, output modes, and machine JSON mapping. A\ndashboard projection names form, table, detail, summary, or log views. An MCP\nprojection names which operations become MCP tools and how those tools should be\ndescribed.\n\n### Handlers\n\nHandlers are implementation functions bound to operation ids. A handler is the\nprogrammatic source of behavior. Tests, generated clients, CLI commands,\ndashboard transports, and generated MCP tools all invoke handlers through the\nsame operation id.\n\n### Effects\n\nEffects document what an operation may do: read files, write files, spawn\nprocesses, make network requests, run agent-style workers, verify browser\noutput, write to Git, or install packages.\n\n### Receipts\n\nReceipts describe durable evidence written by operations, such as reports,\ntranscripts, verification logs, or JSON receipts.\n\n### Docs\n\nDocs references attach bounded source material to operations: README sections,\nspec paths, URLs, short summaries, and optional hashes. Full markdown embedding\nshould be opt-in and size-limited.\n\n### Compatibility Hashes\n\nFeature ids decide compatibility hashes. Labels, README summaries, CLI prompt\ntext, and dashboard layout hints stay outside compatibility unless the package\ndeliberately publishes feature ids for them.\n\n## Quick Start\n\n```sh\npnpm add @async/api-contract\n```\n\n```ts\nimport { defineApiContract, defineOperation } from \"@async/api-contract/interface\";\nimport { jsonSchemaAdapter } from \"@async/api-contract/schema\";\nimport {\n  generateCliDescriptor,\n  generateDashboardManifest,\n  generateMcpDescriptor\n} from \"@async/api-contract/generators\";\n\nconst projectInitInput = jsonSchemaAdapter\u003c{ name: string }\u003e({\n  type: \"object\",\n  required: [\"name\"],\n  properties: {\n    name: { type: \"string\" }\n  }\n}, {\n  parse(value) {\n    if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n      throw new Error(\"input must be an object\");\n    }\n    const input = value as { name?: unknown };\n    if (typeof input.name !== \"string\") throw new Error(\"name must be a string\");\n    return { name: input.name };\n  }\n});\n\nconst projectInitOutput = jsonSchemaAdapter\u003c{ ok: boolean }\u003e({\n  type: \"object\",\n  required: [\"ok\"],\n  properties: {\n    ok: { type: \"boolean\" }\n  }\n});\n\nconst contract = defineApiContract({\n  packageName: \"workspace-tool\",\n  operations: [\n    defineOperation({\n      id: \"project.init\",\n      title: \"Initialize project\",\n      input: projectInitInput,\n      output: projectInitOutput,\n      effects: [\"filesystem.write\"],\n      cli: {\n        command: \"init\",\n        interactive: true\n      },\n      dashboard: {\n        group: \"Project\",\n        view: \"form\",\n        resultView: \"summary\",\n        transport: \"machine-cli\"\n      },\n      mcp: {\n        toolName: \"project.init\",\n        title: \"Initialize project\",\n        resultContent: \"json-text\"\n      }\n    })\n  ]\n});\n\nconsole.log(generateCliDescriptor(contract, { binaryName: \"workspace-tool\" }));\nconsole.log(generateDashboardManifest(contract, { binaryName: \"workspace-tool\" }));\nconsole.log(generateMcpDescriptor(contract, { serverName: \"workspace-tool\" }));\n```\n\n## Generating From Metadata\n\n`@async/api-contract` can generate user-facing surfaces from either:\n\n- a programmatic API contract;\n- schema metadata;\n- both together.\n\n### Generating A CLI\n\nA CLI can be generated from operation metadata:\n\n```ts\nconst contract = defineApiContract({\n  packageName: \"workspace-tool\",\n  operations: [\n    defineOperation({\n      id: \"project.init\",\n      title: \"Initialize project\",\n      input: projectInitInput,\n      output: projectInitOutput,\n      effects: [\"filesystem.write\"],\n      cli: {\n        command: \"init\",\n        interactive: true\n      }\n    })\n  ]\n});\n```\n\nGenerated human CLI:\n\n```sh\nworkspace-tool init\n```\n\nGenerated machine CLI:\n\n```sh\nworkspace-tool api manifest --json\nworkspace-tool api describe project.init --json\nworkspace-tool api invoke project.init --input-json '{\"name\":\"Acme\"}'\n```\n\nRule: dashboards and automation call the machine JSON API, not interactive\nprompt output.\n\nA CLI can also be generated from schema metadata alone for tools that only need\nvalidation, inspection, or form-like commands.\n\n### Generating A Dashboard\n\nA dashboard can be generated from the same metadata:\n\n```ts\ndashboard: {\n  group: \"Project\",\n  view: \"form\",\n  resultView: \"summary\",\n  transport: \"machine-cli\"\n}\n```\n\nThe generated dashboard manifest describes:\n\n- available operations;\n- input forms;\n- result views;\n- table/detail views;\n- local invoke command;\n- receipt and report locations.\n\nDashboard rule: the dashboard is a projection. It must not become the durable\nstate authority.\n\n### Generating MCP Servers\n\nMCP can be generated from the same operation metadata. In v1, MCP support is\nlimited to tools over stdio.\n\n```ts\nimport { generateMcpDescriptor, generateMcpServerModule } from \"@async/api-contract/generators\";\n\nconst contract = defineApiContract({\n  packageName: \"workspace-tool\",\n  operations: [\n    defineOperation({\n      id: \"project.init\",\n      title: \"Initialize project\",\n      input: projectInitInput,\n      output: projectInitOutput,\n      effects: [\"filesystem.write\"],\n      receipts: [{ kind: \"report\", pathTemplate: \"reports/init-{timestamp}.md\" }],\n      mcp: {\n        toolName: \"project.init\",\n        title: \"Initialize project\",\n        description: \"Create a local project workspace.\",\n        annotations: { destructiveHint: true },\n        resultContent: \"json-text\",\n        featureId: \"mcp.project.init\"\n      }\n    })\n  ]\n});\n\nconst descriptor = generateMcpDescriptor(contract, {\n  serverName: \"workspace-tool\",\n  serverVersion: \"1.0.0\"\n});\n\nconst serverSource = generateMcpServerModule(contract, {\n  serverName: \"workspace-tool\",\n  serverVersion: \"1.0.0\"\n});\n```\n\nThe descriptor has `format: \"api-contract.mcp.v1\"` and includes package name,\nserver name, protocol target, tools, schemas, effects, receipts, and feature\nids. It is review data; it does not import or execute the MCP SDK.\n\nThe generated server module is TypeScript source text. It imports\n`invokeOperation()` from `@async/api-contract`, imports `McpServer` and\n`StdioServerTransport` from the consuming project's MCP SDK install, registers\ntools, exports `createMcpServer(api)` and `main(api)`, and calls\n`invokeOperation(api, operationId, args)`.\n\nMCP exposure is explicit by default:\n\n```ts\ngenerateMcpDescriptor(contract); // only operations with mcp metadata\ngenerateMcpDescriptor(contract, { exposure: \"all\" }); // every operation except disabled MCP projections\n```\n\nUse explicit exposure for local-first tools because MCP tools are model-visible\nactions. Operation ids can become tool names only when they already match MCP\ntool-name guidance. If an operation id contains spaces or other unsafe\ncharacters, set `mcp.toolName`.\n\nConsumer packages install the official MCP TypeScript SDK only when they need\nto run the generated server module. `@async/api-contract` does not depend on an\nMCP runtime package.\n\n### From Schema Metadata\n\nSchema-only dashboards or CLIs are valid.\n\nExamples:\n\n- render a form from JSON Schema;\n- render a table from output schema;\n- generate prompt choices from enums;\n- generate validation commands;\n- generate metadata inspection views.\n\nThis is useful for later host packages, but the core concept stays generic.\n\n### From Programmatic API\n\nOperation-first tools define handlers and invoke them:\n\n```ts\nimport { bindApiHandlers } from \"@async/api-contract/interface\";\n\nconst api = bindApiHandlers(contract, {\n  \"project.init\": async (input, context) =\u003e {\n    return createProject(input, context);\n  }\n});\n```\n\nGenerated CLI and dashboard surfaces both route through the same operation\nhandler.\n\nGenerated MCP tools route through that same handler path. They should not embed\nhandler implementation logic in generated source.\n\n## Tooling Overview\n\n### `defineFeatureCatalog()`\n\nDeclares compatibility features for an API concern.\n\nUse it when you want a reviewed feature inventory with release and lifecycle\nmetadata.\n\nIt emits a normalized feature catalog. It does not execute or validate runtime\nbehavior.\n\n### `createSurface()`\n\nCreates a normalized feature surface with a stable hash.\n\nUse it when you need supported, required, emitted, or consumed feature lists.\n\nIt emits sorted feature ids and a hash. It does not decide release policy.\n\n### `defineSchema()`\n\nDefines generic schema metadata.\n\nUse it when a shape should be reusable across validation, prompts, forms, and\ncompatibility features.\n\nIt emits schema metadata. It does not enforce host-specific domain rules.\n\n### `jsonSchemaAdapter()`\n\nWraps JSON Schema with optional parsing, defaults, examples, and descriptions.\n\nUse it when generators need portable schema data and invocation still needs\nruntime parsing.\n\nIt emits a schema adapter. It does not require a validation library.\n\n### `standardSchemaAdapter()`\n\nWraps a Standard Schema-style validator.\n\nUse it when a package already exposes a Standard Schema-compatible object.\n\nIt emits a schema adapter. The current helper only supports synchronous parsing.\n\n### `createSchemaFeature()`\n\nMaps schema metadata to a compatibility feature.\n\nUse it when changing or removing a schema should be visible in diff and impact\nworkflows.\n\nIt emits a `FeatureSpec`. It does not automatically decide whether a schema is\ncontract-bearing.\n\n### `defineApiContract()`\n\nDefines the maintained operation source for a package.\n\nUse it when operations, schemas, docs, and projections should serialize into\none interface manifest.\n\nIt emits an `api-contract.interface.v1` structure. It does not bind handlers.\n\n### `defineOperation()`\n\nNormalizes one callable operation with schemas, lifecycle, effects, errors,\nreceipts, CLI metadata, and dashboard metadata.\n\nUse it when a callable capability should be programmatically invoked or mapped\nto generated surfaces.\n\nIt emits operation metadata. It does not contain business logic.\n\n### `bindApiHandlers()`\n\nConnects operation metadata to implementation functions.\n\nUse it when tests, CLIs, dashboards, and generated clients should share one\nhandler path.\n\nIt emits a bound API. It does not generate a CLI by itself.\n\n### `invokeOperation()`\n\nInvokes one bound operation by id, parses input, runs the handler, and parses\noutput.\n\nUse it as the common runtime path for generated adapters.\n\nIt emits the operation result. It does not own retries, permissions, or\ntransport policy.\n\n### `createOperationSurface()`\n\nConverts operations into a compatibility surface.\n\nUse it when removed or renamed operations should appear in existing feature\ndiffs and impact reports.\n\nIt emits a `Surface`. It does not decide whether schema or projection changes\nare breaking.\n\n### `defineCliProjection()`\n\nDefines command metadata for a generated CLI.\n\nUse it when operation or schema metadata should become commands, flags, prompts,\nmachine JSON endpoints, output modes, or exit-code mappings.\n\nIt emits CLI projection metadata. It does not parse process arguments.\n\n### `defineDashboardProjection()`\n\nDefines local dashboard metadata.\n\nUse it when operation or schema metadata should become forms, tables, details,\nsummaries, empty states, or local transport calls.\n\nIt emits dashboard projection metadata. It does not store durable dashboard\nstate.\n\n### `defineMcpProjection()`\n\nDefines MCP tool projection metadata.\n\nUse it when selected operations should become MCP tools with explicit names,\nannotations, result content behavior, or feature ids.\n\nIt emits MCP projection metadata. It does not import the MCP SDK or register\nruntime tools.\n\n### `defineProjectionSet()`\n\nGroups CLI, dashboard, and MCP projections.\n\nUse it when a package wants to serialize projections independently from the\noperations that reference them.\n\nIt emits a projection set. It does not generate files.\n\n### `generatePackageManifest()`\n\nEmits `api-contract.json` with existing catalogs and surfaces plus\n`x-interface` metadata.\n\nUse it when one source should produce the package manifest.\n\nIt emits a manifest. It does not run validation outside the metadata shape.\n\n### `generateApiSurfaceMarkdown()`\n\nRenders `API_SURFACE.md` from a manifest.\n\nUse it when maintainers need deterministic human review output.\n\nIt emits markdown. It does not infer hidden runtime behavior.\n\n### `generateCliDescriptor()`\n\nProduces a CLI descriptor with human commands and machine-stable JSON commands.\n\nUse it when a CLI should be generated from operation and schema metadata.\n\nIt emits a descriptor. It does not execute business logic.\n\n### `generateDashboardManifest()`\n\nProduces local dashboard metadata.\n\nUse it when a dashboard should render operations, forms, result views, and local\ninvoke commands from the same metadata.\n\nIt emits a dashboard manifest. It does not become state authority.\n\n### `generateMcpDescriptor()`\n\nProduces an MCP descriptor from operation metadata.\n\nUse it when maintainers need reviewable MCP tool exposure before generating or\nrunning a server adapter.\n\nIt emits `api-contract.mcp.v1` metadata. It does not import or execute MCP SDK\ncode.\n\n### `generateMcpServerModule()`\n\nProduces TypeScript source for a thin MCP stdio server adapter.\n\nUse it when a consuming package wants generated `registerTool()` boilerplate\nthat invokes bound operation handlers.\n\nIt emits source text with `createMcpServer(api)` and `main(api)`. It does not\nbundle handlers, install dependencies, or add MCP resources and prompts.\n\n### `generateTypeScriptClient()`\n\nProduces deterministic TypeScript client source for operation invocation.\n\nUse it when consumers need generated client code instead of hand-written\nwrappers.\n\nIt emits source text. It does not execute the client.\n\n### `generateMachineCliRouter()`\n\nProduces a machine CLI router descriptor.\n\nUse it when dashboards and automation need stable `api describe` and\n`api invoke` routes.\n\nIt emits route metadata. It does not scrape human CLI output.\n\n## Example Matrix\n\nAll examples are neutral and intentionally package-agnostic.\nExecutable examples live in\n[`examples/combinations`](examples/combinations/README.md).\n\n| Example | Combination | Why use it |\n| --- | --- | --- |\n| [`compatibility-only`](examples/combinations/compatibility-only/README.md) | Feature catalogs plus supported/required surfaces | Publish capability compatibility and ledgers before adding operation handlers. |\n| [`schema-metadata-only`](examples/combinations/schema-metadata-only/README.md) | Generic schema metadata only | Share validation, prompt, form, and table metadata without a runtime API. |\n| [`programmatic-api-only`](examples/combinations/programmatic-api-only/README.md) | Operations plus handlers | Establish one invocation path for tests and library consumers. |\n| [`api-plus-cli`](examples/combinations/api-plus-cli/README.md) | Operations plus CLI projection | Generate human commands and machine JSON routes while keeping CLI code thin. |\n| [`api-plus-dashboard`](examples/combinations/api-plus-dashboard/README.md) | Operations plus dashboard projection | Generate local dashboard view metadata that invokes the same operations. |\n| [`api-plus-mcp`](examples/combinations/api-plus-mcp/README.md) | Operations plus MCP projection | Expose selected operations as MCP tools without adding business logic to the MCP layer. |\n| [`schema-plus-cli`](examples/combinations/schema-plus-cli/README.md) | Schemas plus CLI projection | Generate validation or inspection command metadata from schemas alone. |\n| [`schema-plus-dashboard`](examples/combinations/schema-plus-dashboard/README.md) | Schemas plus dashboard projection | Generate dashboard form/table metadata from schemas before operations exist. |\n| [`full-stack`](examples/combinations/full-stack/README.md) | Schemas, operations, handlers, CLI, dashboard, MCP, receipts, manifest, ledger, and generated source | Show the complete one-source contract workflow across all generated surfaces. |\n\nUse names such as `workspace-tool`, `project-console`, and `acme-tool` in\npublic examples.\n\n## Compatibility Workflow\n\n```sh\napi-contract check --manifest api-contract.json\napi-contract ledger --manifest api-contract.json --out API_SURFACE.md\napi-contract ledger --manifest api-contract.json --check API_SURFACE.md\napi-contract diff --before old-api-contract.json --after api-contract.json\napi-contract impact --before old-api-contract.json --after api-contract.json --consumers consumers.json\napi-contract usage scan --target src --package-name acme-tool --dependency workspace-tool --catalog api-contract.json --out api-usage.json\n```\n\n`impact` is intended as a cheap preflight for explicit many-repo impact runs.\nRead the latest consumer manifests or usage files first; then run full dependent\nrepo checks only for consumers that actually use changed features.\n\n`usage scan` is a line-oriented source preflight. It records dependency and\nfeature-string evidence, but it is not a full parser or proof of semantic usage.\n\n## Design Rules\n\n- Keep business logic in programmatic handlers.\n- Treat CLI, dashboard, and MCP as projections.\n- Let dashboards call machine-stable CLI JSON commands, not human prompt text.\n- Make MCP exposure explicit by default.\n- Keep README prose and dashboard layout hints out of compatibility hashes\n  unless they are explicitly mapped to feature ids.\n- Use bounded docs references instead of embedding unbounded markdown by\n  default.\n- Keep host-specific validation in the host package.\n- Preserve the existing `api-contract.package.v1` manifest envelope.\n- Put richer generation metadata under `x-interface`.\n- Keep this package generic. Host packages may map their own domain concepts\n  into schema, operation, CLI, dashboard, MCP, and evidence metadata later.\n\n## Subpath Exports\n\n```txt\n@async/api-contract\n@async/api-contract/schema\n@async/api-contract/interface\n@async/api-contract/projection\n@async/api-contract/generators\n@async/api-contract/types\n```\n\n`@async/api-contract` owns the stable compatibility core: feature catalogs,\nsurfaces, hashes, manifest parsing, diffing, impact reports, usage scan, and API\nsurface markdown rendering.\n\n`@async/api-contract/schema` owns generic schema metadata.\n\n`@async/api-contract/interface` owns programmatic operation contracts.\n\n`@async/api-contract/projection` owns CLI, dashboard, and MCP projection\nmetadata.\n\n`@async/api-contract/generators` owns deterministic artifact generators.\n\n`@async/api-contract/types` owns type-only compatibility helpers.\n\n## Maintainer Workflow\n\nThe repository's package scripts and GitHub Actions are generated from\n`pipeline.ts` through `@async/pipeline`.\n\n```sh\npnpm run pipeline:verify\npnpm run pipeline:api-surface\npnpm run pipeline:api-surface:generate\npnpm run pipeline:github:check\npnpm run pipeline:sync:check\npnpm run release:check\n```\n\nRelease and preview lifecycle commands are also synced from `pipeline.ts`:\n\n```sh\npnpm run pipeline:preview\npnpm run pipeline:snapshot\npnpm run pipeline:publish\npnpm run pipeline:release:doctor\n```\n\n## Relationship To @async/claims\n\n`@async/claims` can wrap surfaces with issuer, evidence, trust, policy, and\nsignatures. It should not redefine feature ids, hashes, derivation, or\ncompatibility rules.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasync%2Fapi-contract","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasync%2Fapi-contract","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasync%2Fapi-contract/lists"}