app-api-contract-testing
Skill9 starsChanged 27 days agoMITView on GitHub
Author, validate, publish, and centrally verify consumer-driven contracts for cross-app API calls. Use when: 1. An app's runtime calls another app via AppApisApi.callAppApi(...), 2. Authoring or editing *.contract.json files, 3. Confirming a provider you depend on still behaves as expected, 4. Checking whether a provider change would break dependent apps.
In this repository119 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/fusebase-flow-always.mdcCursor rule
- .cursor/rules/fusebase-flow-implementation.mdcCursor rule
- .cursor/rules/fusebase-flow-security.mdcCursor rule
- .cursor/rules/fusebase-flow-specs.mdcCursor rule
- .cursor/rules/fusebase-flow-validation.mdcCursor rule
- api-explorationSkill
- app-backendSkill
- app-business-docsSkill
- app-dev-practicesSkill
- app-e2e-testsSkill
- app-quality-patternsSkill
- app-routingSkill
- app-secretsSkill
- app-sidecarSkill
- app-ui-designSkill
- business-logic-guardianSkill
- client-vs-internalSkill
- code-reviewSkill
- comment-policySkill
- communicationSkill
- design-discovery-ideationSkill
- dev-debug-logsSkill
- documentation-budgetSkill
- file-uploadSkill
- find-wasted-codeSkill
- find-wasted-effortSkill
- fusebase-cliSkill
- fusebase-dashboardsSkill
- fusebase-flow-health-checkSkill
- fusebase-gateSkill
- fusebase-portal-specific-appsSkill
- git-history-diagnosticSkill
- git-workflowSkill
- handling-authentication-errorsSkill
- handoffSkill
- implementation-planningSkill
- invite-with-passwordSkill
- lightweight-laneSkill
- liveness-disciplineSkill
- managed-integrationsSkill
- mcp-gate-debugSkill
- module-size-disciplineSkill
- north-starSkill
- phase-auditSkill
- product-apps-decompositionSkill
- product-docs-firstSkill
- product-ownerSkill
- project-onboardingSkill
- release-deploy-reportingSkill
- remote-logsSkill
- repo-onboarding-context-mapSkill
- requirements-specificationSkill
- role-disciplineSkill
- security-permissions-reviewSkill
- skill-authoringSkill
- smoke-testingSkill
- task-delegationSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 0 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
When this app calls another app via Gate AppApisApi.callAppApi(...), it becomes a
- Very specific: line 19
After adding or changing a callAppApi(...) dependency in runtime code.
- Very specific: line 20
Before relying on a provider, or after a provider you depend on is upgraded (run verify-consumer).
- Very specific: line 22
Before shipping a change to an app other apps call (run verify-provider to catch every dependent consumer org-wide).
- Very specific: line 81
Treat a scaffolded-but-unreviewed contract as incomplete: validate/publish/verify only after the expect blocks express the app's real …
- Very specific: line 88
Add --json to validate / verify-consumer / verify-provider for CI: a single JSON document with a top-level ok flag mirroring the exit code.
- Very specific: line 94
When callAppApi(...) is dynamic and static analysis cannot resolve the target, declare it by hand, then scaffold that one:
- Very specific: line 129
replace
inputplaceholders with real values: before publish. Matchers are meaningful only in expect. - Very specific: line 143
When the provider publishes a manifest, verification also checks responses against its OpenAPI schema automatically — even a bare { …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Cross-App API Contract Testing
When this app calls another app via Gate AppApisApi.callAppApi(...), it becomes a
consumer that depends on the provider operation behaving a certain way. A
contract captures that expectation. Contracts are authored and validated
locally, then verified centrally (public-api → Gate runs the real provider
call) — there is no local runtime verification command.
A contract is identified by providerAppId + operationId — the business
contract is the provider operation, not the HTTP transport.
When to do this (during app development)
- After adding or changing a
callAppApi(...)dependency in runtime code. - Before relying on a provider, or after a provider you depend on is upgraded
(run
verify-consumer). - Before shipping a change to an app other apps call (run
verify-providerto catch every dependent consumer org-wide).
Prerequisites
fusebase auth --api-key=<id>.<key>(an API key is required).orgId/productIdinfusebase.json, and the app configured with apath.- The
cross-app-api-calls-analysisflag (already enabled — this skill is only present when it is).
Workflow
# 1. Discover dependencies — scans runtime TS for callAppApi(...) and writes
# fusebaseAppApiDependenciesMeta into fusebase.json
fusebase analyze app-apis --feature <appId>
# 2. Scaffold draft contracts from the resolved callsites
fusebase app-api-contracts scaffold --app <appId>
# → drafts are bare { "expect": { "status": 200 } } with input inferred from
# the call payload. EDIT them into real assertions (see "Contract files").
# Existing *.contract.json files are SKIPPED (your edits are safe); only missing
# ones are created. Pass --force to overwrite existing files back to fresh
# drafts (discards your edits).
# 3. Validate offline — structure + that each contract maps to a real dependency.
# No provider call.
fusebase app-api-contracts validate --app <appId>
# 4. Publish the validated set to central storage (full replacement, idempotent;
# aborts and uploads nothing if any contract is invalid)
fusebase app-api-contracts publish --app <appId>
# 5. Verify centrally against the live provider
fusebase app-api-contracts verify-consumer --app <appId> # this app's contracts
fusebase app-api-contracts verify-provider --app <providerAppId> # org-wide inbound checkReview and complete every draft (required, not optional)
Scaffolding is a starting point, not a finished contract. It seeds only the
request side (input, inferred from the call payload). The response
assertion is NOT generated — each draft gets only expect.status: 200, never an
expect.body or expect.error. An unedited draft therefore asserts almost
nothing (just "the call returned 200").
So after every scaffold, open each generated *.contract.json and edit it to
match what this app actually relies on:
- Define
expectby hand — addexpect.bodymatchers for the response fields the app reads, and add the error cases the app handles (expect.status+expect.errorfor the 4xx/5xx paths). This is the core of the contract and is never produced by scaffolding. - Check
input— fix or complete the inferred payload if it doesn't reflect a real call the app makes (and add cases for other meaningful inputs). - Rename cases — give each
case.namea meaningful description of the scenario. - Remove any scaffolded contract for a dependency the app doesn't truly depend on.
Treat a scaffolded-but-unreviewed contract as incomplete: validate/publish/verify
only after the expect blocks express the app's real expectations.
Key rule: verify-* read the published set, not local files. After editing
a contract, re-run publish before verifying — otherwise the old published version
is tested.
Add --json to validate / verify-consumer / verify-provider for CI: a single
JSON document with a top-level ok flag mirroring the exit code. publish is an
action, not a check — branch on its exit code.
Dynamic (unresolved) calls
When callAppApi(...) is dynamic and static analysis cannot resolve the target,
declare it by hand, then scaffold that one:
fusebase app-api-contracts unresolved --app <appId>
fusebase app-api-contracts add-manual-dependency --app <appId> --provider <providerAppId> --operation <operationId>
fusebase app-api-contracts scaffold --app <appId> --provider <providerAppId> --operation <operationId> --forceContract files
Discovered under <app-path>/contracts/app-apis/<providerAppId>/<operationId>.contract.json:
{
"kind": "app-api-consumer-contract",
"schemaVersion": "2026-06-03",
"providerAppId": "<provider app id>",
"operationId": "listTasks",
"cases": [
{
"name": "lists open tasks",
"input": { "query": { "status": "open" } },
"expect": { "status": 200, "body": { "tasks": [ { "id": { "$matcher": "string" } } ] } }
}
]
}input→ the Gate request envelope (path/query/body); omit to send{}.inputis sent, not asserted. A matcher left ininputis synthesized into a concrete sample before the call ({"$matcher":"string"}→"contract-draft",number→1,enum→ first$value,$optional→ omitted). Scaffolding may seed a matcher for a value it couldn't read from your code (e.g. a dynamic pathid) — the synthesized sample is almost certainly not a real record, so replaceinputplaceholders with real values beforepublish. Matchers are meaningful only inexpect.expect.statusis required;expect.bodyandexpect.errorare optional.expect.errormatchesdata.erroron non-2xx responses.- Matchers (type-only):
{"$matcher":"string"|"number"|"boolean"},{"$matcher":"enum","$value":[...]}. Add"$optional":trueto allow absence,"$nullable":trueto allow an explicitnull(combinable). Plain JSON = exact match; objects match partially (only listed keys checked); a length-1 array[ X ]matches every element (so a nullable element needs[{"$matcher":"string","$nullable":true}]), a length-N array expects exactly N positional elements. - Not supported (ignored-with-warning if seen in the provider schema): regex,
ranges/lengths, formats (date/uuid/email),
oneOf/anyOf/allOf.
When the provider publishes a manifest, verification also checks responses
against its OpenAPI schema automatically — even a bare { "status": 200 } draft
gets that check. Missing manifest / unsupported keywords surface as warnings, never
failures.
Notes
- Verification runs the real provider handler, so it can cause side effects (writes, emails). There is no fixture/sandbox environment.
verify-providerruns every targeting consumer's contracts as the triggering user; it is org-wide (sees consumers beyond the localfusebase.json).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

