Interface contract tooling for the Surfaces ecosystem. Validates, compares, and enforces compliance between defined interface contracts and actual implementation artifacts across multiple surfaces.
This repository contains two packages:
-
@surfaces/interfacectl-validator— Core validation library with TypeScript types, schema validation, and bundled contract schema definitions. Provides the foundation for contract validation. -
@surfaces/interfacectl-cli— Command-line interface that consumes the validator to run contract checks from any repository. Most users only need this package.
- Node.js: >=18.20.0 or >=20.10.0 (required for
with { type: "json" }import syntax support) - pnpm: 10.26.2 (specified in
packageManagerfield)
Install the CLI package as a development dependency:
pnpm add -D @surfaces/interfacectl-cliAfter installation, validate your surfaces against a contract:
interfacectl validate --root . --contract ./contracts/ui.contract.jsonFor detailed command documentation, see API.md.
The CLI provides three main commands:
Validates configured surfaces against a shared interface contract. Performs comprehensive validation including contract structure validation, surface descriptor collection, and compliance checking for fonts, colors, layout, motion, and sections.
interfacectl validate [options]Compares a contract against observed artifacts and generates a detailed diff. Performs structural comparison showing additions, removals, modifications, and renames with drift risk detection.
interfacectl diff [options]Enforces policy on interface contracts using configurable enforcement modes: fail (validate and exit on violations), fix (automatically apply safe fixes), or pr (generate patches for review).
interfacectl enforce [options]For complete command documentation with all options, exit codes, and output formats, see API.md.
Validate all surfaces against a contract:
interfacectl validate --root . --contract ./contracts/ui.contract.jsonValidate with JSON output for CI integration:
interfacectl validate --root . --contract ./contracts/ui.contract.json --format jsonValidate specific surfaces only:
interfacectl validate --surface my-surface --surface another-surfaceCompare contract against observed artifacts:
interfacectl diff --root . --contract ./contracts/ui.contract.jsonGenerate diff with normalization disabled (for debugging):
interfacectl diff --no-normalizeFail on violations (useful for CI):
interfacectl enforce --mode failPreview automatic fixes:
interfacectl enforce --mode fix --dry-runApply automatic fixes:
interfacectl enforce --mode fixGenerate patch for review:
interfacectl enforce --mode pr --format json --out fix-patch.jsonConfiguration options can be set via environment variables:
SURFACES_ROOT— Project root directory (defaults to current working directory)SURFACES_CONTRACT— Path to contract JSON file (defaults tocontracts/surfaces.web.contract.json)SURFACES_CONFIG— Path to interfacectl config JSON file (defaults tointerfacectl.config.json)
Precedence: CLI flags > environment variables > defaults
Create an interfacectl.config.json file in your project root to map surface IDs to their root directories:
{
"surfaceRoots": {
"demo-surface": "src/demo-surface",
"my-app": "apps/my-app"
}
}The config file tells interfacectl where to find surface descriptors in your codebase. Each key is a surface ID that must match an entry in your contract file.
Example GitHub Actions workflow:
- uses: pnpm/action-setup@v4
with:
version: 10.26.2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm exec interfacectl validate --root . --contract contracts/ui.contract.json --format jsonFor enforcement in CI, use:
- run: pnpm exec interfacectl enforce --mode fail --strictBuild produces dist/ directories in each package:
pnpm install
pnpm run buildTests assume dist/ exists and run against built artifacts. Consumers depend only on the CLI interface, not build internals. The tarball-install test validates CLI works from a packaged install.
pnpm run test- Run
pnpm changesetand choose affected packages. - Merge the generated changeset.
- Trigger the Release workflow (requires
NPM_TOKEN) or push av*tag.
The release workflow builds, tests, and publishes packages through Changesets.