Quick start

Contents

10-minute CI quick start

Set up InterfaceDelta in your repository in about ten minutes: install the CLI, write one JSON file, run one check, add one GitHub Action step. Use public services you can inspect without signing in for this first check.

What you get

InterfaceDelta checks the agent services your project depends on (MCP servers, A2A agents, OpenAPI services) for interface changes and tells you deterministically whether each change is breaking. You commit the service list and baselines in your repository, and a GitHub Action fails a pull request when a configured change appears.

Install

The CLI needs Node.js 22 or newer.

npm install -g interfacedelta@0.4.0
interfacedelta version

interfacedelta version prints 0.4.0, the CLI's own version constant. You can also run it without installing: npx interfacedelta@0.4.0 check.

Write .interfacedelta/dependencies.json

In your repository root, create .interfacedelta/dependencies.json. This example lists one MCP server and one OpenAPI service. Replace the example.com URLs with your own reachable public HTTPS services before running the commands; these placeholder addresses are not working services. Remove an entry if you only need one service:

{
  "formatVersion": "interfacedelta-dependencies-v1",
  "failOn": "breaking",
  "dependencies": [
    {
      "name": "docs-search",
      "url": "https://mcp.docs-search.example.com",
      "mcpEndpoint": "https://mcp.docs-search.example.com/mcp",
      "baseline": "docs-search.json"
    },
    {
      "name": "orders-api",
      "url": "https://api.example.com",
      "baseline": "orders-api.json"
    }
  ]
}

Field reference

Unknown fields are refused. Start with the example above; add owners, rules and acceptances as your project needs them.

FieldTypeRequiredMeaningAllowed values and limits
formatVersionstringyesFile format versionExactly interfacedelta-dependencies-v1
failOnstringnoWhich classifications fail the runComma-separated list of breaking, non_breaking, indeterminate, informational, metadata; default breaking
onErrorstringnoWhat happens when a dependency cannot be inspectedfail (default) or warn
ownerstringnoDefault owner for every changeHandle or team name matching @?[A-Za-z0-9][A-Za-z0-9._/-]{0,99}
dependenciesarrayyesThe services to check1 to 50 entries; entries are strict objects
dependencies[].namestringyesYour name for the service; unique up to caseMatches [A-Za-z0-9][A-Za-z0-9._-]{0,63}
dependencies[].urlstringyesPublic HTTPS service URL to inspect1 to 2048 characters; must be a URL; no query or fragment
dependencies[].mcpEndpointstringnoExplicit MCP endpoint URL (needed to bind a sign-in token)1 to 2048 characters
dependencies[].baselinestringyesBaseline JSON path, relative to the dependencies file1 to 512 characters; ends in .json; relative; stays inside the dependencies directory; no \ or :; normalized path must not escape the directory; unique up to case
dependencies[].ownerstringnoWho acts on this dependency's changesSame owner pattern as above
rulesarraynoDecision rulesAt most 100; each has required id, when, then, and optional owner, note
rules[].idstringyesRule name; unique in the fileMatches [a-z0-9][a-z0-9-]{0,63}
rules[].whenobjectyesWhich changes match; each field takes one value or a list of 1–50 values; every listed field must match; an empty when matches everything, and a rule after one is refuseddependency (name or list), classification (breaking, non_breaking, indeterminate, informational), code (a known change code), domain (product, security_compliance, finance), name (capability name or endpoint URL; * matches any run of characters)
rules[].thenstringyesThe decision for matching changesblock, warn, or allow
rules[].owner, rules[].notestringnoWho acts; a one-line noteOwner pattern; note 1–300 characters, one line
acceptedarraynoExpiring acceptances of single changesAt most 200; each has required dependency, change, reason, expires, and optional by
accepted[].dependencystringyesDependency being acceptedAn existing dependency name, 1–64 characters
accepted[].changestringyesThe change id check printschange: followed by 24 lowercase hex characters
accepted[].reasonstringyesWhy the change is accepted1–300 characters, one line
accepted[].expiresstringyesExpiry date, YYYY-MM-DDA real calendar date, at most 366 days ahead
accepted[].bystringnoWho acceptedOwner pattern

Limits

  • At most 50 dependencies, 100 rules, and 200 acceptances per file.
  • Acceptances run at most 366 days into the future; for a permanent decision, write an allow rule instead.
  • Hosted watch uploads are limited to 256 KiB; the local CLI reader does not enforce this byte limit.
  • Dependency names are unique up to case, and no two dependencies share a baseline path.
  • Rules must name dependencies that exist in the file, and a rule that follows an empty when is refused because it could never match.

Check locally

From the repository root:

interfacedelta baseline
interfacedelta check

baseline inspects each service once and writes the missing .json baseline files next to the dependencies file. check compares each service with its baseline. Review the baselines, then commit the dependencies file and baselines with git add .interfacedelta && git commit -m "Add InterfaceDelta baselines". Existing baselines are preserved; use baseline --force only after reviewing a change you intend to adopt.

For two unchanged services, a passing run looks like this (your URLs will differ):

InterfaceDelta compatibility check

Policy: ci-policy-v2 (breaking); on-error: fail
Dependencies: 2
Failed: 0
Errors: 0
Blocked: 0
Warned: 0
Result: PASSED

Dependencies
- docs-search  PASSED  unchanged  https://mcp.docs-search.example.com/
- orders-api  PASSED  unchanged  https://api.example.com/

Exit codes are stable:

CodeMeaning
0Success or policy pass
1Policy failure: a change was blocked (or selected by failOn)
2Usage, configuration, or baseline error; also credential errors
3Inspection failure: a dependency could not be inspected

For a dependencies file the highest applies, in the order 2, 3 (unless --on-error warn), 1.

Add the GitHub Action

Create .github/workflows/interfacedelta.yml in your repository:

name: InterfaceDelta
on: pull_request

permissions:
  contents: read
  security-events: write

jobs:
  compatibility:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: arto-a/interfacedelta-action@c06ddb383cbd5d4b4fe487e9af7906f155d72257 # v0.4.0
        with:
          sarif-output: interfacedelta.sarif
      # Pin upload-sarif to a reviewed commit SHA before adopting this workflow.
      - uses: github/codeql-action/upload-sarif@v3
        if: ${{ !cancelled() && hashFiles('interfacedelta.sarif') != '' }}
        with:
          sarif_file: interfacedelta.sarif

The Action needs no InterfaceDelta token and no GITHUB_TOKEN for the check itself: it reads .interfacedelta/dependencies.json (the default), inspects each public service, and fails the job when a decision blocks. security-events: write is needed only for the SARIF upload step; remove that permission, the entire upload step, and sarif-output if you do not use code scanning. The upload runs even if the check fails, when a SARIF file exists. The check uses the file’s policy (breaking changes and inspection errors fail by default). Push your commit and open a pull request to run it; unchanged reachable services should pass. SARIF upload is optional and requires code scanning to be available for your repository.

Useful inputs, all optional:

  • dependencies: path to the dependencies file (default .interfacedelta/dependencies.json).
  • fail-on: comma-separated breaking (default), non_breaking, indeterminate, informational, metadata.
  • on-error: fail (default) or warn; a dependency that cannot be reached is then a warning, not a failure.
  • sarif-output: write a SARIF 2.1.0 file for GitHub code scanning.
  • url, mcp-endpoint, baseline: check one service instead of the file.

Watch it hosted (optional)

The workflow above checks pull requests. Hosted watching requires Pro or Team. Hosted InterfaceDelta checks continuously and delivers each decision to its owner (Slack, a signed webhook, a GitHub issue, or email) before the next build breaks. Sync the same dependencies file from CI with either the CLI or the Action:

export INTERFACEDELTA_API_TOKEN=...   # a watch token from Routing → Watch tokens, with lockfiles:write
interfacedelta watch

Create a separate .github/workflows/interfacedelta-watch.yml (replace main if your default branch has another name):

name: InterfaceDelta watch
on:
  push:
    branches: [main]
    paths: ['.interfacedelta/**']
  workflow_dispatch:
permissions:
  contents: read
jobs:
  watch:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
      - uses: arto-a/interfacedelta-action@c06ddb383cbd5d4b4fe487e9af7906f155d72257 # v0.4.0
        with:
          check: false
          watch: true
          api-token: ${{ secrets.INTERFACEDELTA_WATCH_TOKEN }}

The Action form runs on your default branch whenever the file changes, with actions/checkout set to fetch-depth: 0 so commit order can be proved. Baselines stay in your repository and are not uploaded.

Create the token in the site under Routing, in Watch tokens: each token is bound to one repository and branch, and watch needs the lockfiles:write scope. Store it as the INTERFACEDELTA_WATCH_TOKEN repository secret and pass it through the Action’s api-token input. The CLI reads that same watch-token value from INTERFACEDELTA_API_TOKEN. Account REST API tokens do not grant repository watching. Configure destinations in Routing for delivery; GitHub issues also need the issues workflow in the delivery guide. Hosted observations are public, so they may differ from a local signed-in check.

Troubleshooting

Errors print as InterfaceDelta error: <message> on stderr. The examples below identify common failures; paths and validation details depend on your file.

The dependencies file is missing. Dependencies file could not be read: .interfacedelta/dependencies.json. Create it (see the README), or check one service with `interfacedelta check <url> --baseline <file>`. Run from the directory that contains .interfacedelta/, or pass --dependencies <file>.

The dependencies file is not valid JSON. Dependencies is not valid JSON. Fix the syntax; exit code 2.

A field is wrong. Dependencies file is invalid at <field>: <what is wrong>. The path after at names the field, for example dependencies.0.url. Common causes: a missing baseline, a formatVersion that is not exactly interfacedelta-dependencies-v1, an unknown field, or a name with a character outside letters, digits, ., _, -.

A baseline file is missing. Baseline file could not be read: /your/repo/.interfacedelta/docs-search.json. Record one with `interfacedelta baseline`. Run interfacedelta baseline, then commit the new file.

A baseline path escapes the directory. Dependencies file is invalid at dependencies.0.baseline: A baseline is a relative .json path inside the dependencies directory. Baselines must stay within the dependencies directory; move the file and fix the path. Duplicate names and shared baselines fail the same way, with Duplicate dependency name: <name> or Two dependencies share the baseline <path>.

A service cannot be inspected (exit 3). The dependency is listed with ERROR (inspection) and the run exits 3. A network failure, timeout, or server error can be downgraded to a warning with --on-error warn (or "onError": "warn" in the file). Configuration, credential and unexpected internal errors always fail, whatever on-error says.

Inspecting a service

Use the hosted inspector with whichever public HTTPS URL you have: a service root or a supported machine-readable endpoint. InterfaceDelta discovers the supported surfaces a service publishes, or inspects a known endpoint directly. Inspection is bounded and passive; it does not create a monitor.

  1. Open Inspect.
  2. Enter a public service URL, MCP endpoint, OpenAPI document, A2A Agent Card, or ARD manifest.
  3. Review protocol, capability, access and consistency evidence.
  4. Use the Type control only when a nonstandard endpoint cannot be identified safely from its URL.

The inspector is the starting point

The browser inspector accepts one primary public HTTPS URL, performs bounded passive observation, and renders the resulting Passport. A separate MCP endpoint belongs under Advanced only when it differs from the primary URL, including an explicitly authorized cross-origin endpoint. Its current POST /api/inspect transport is unversioned and subject to change; it is not presented as InterfaceDelta API v1.

Three integration boundaries

REST uses first-party account tokens. Public MCP reads recorded evidence anonymously. Inspector MCP uses WorkOS authorization for a separate resource and writes a durable observation.

Choose an access surface

Start with the outcome you need. The three interfaces deliberately have different authorization and persistence boundaries.

Conventional programmatic access

Use an Account-created bearer token for non-persistent inspection, protected evidence reads, and account-owned monitor operations.

View REST API →

Existing recorded evidence

Use the anonymous public MCP resource to read existing public Passports, history, and changes without starting a scan.

View recorded-evidence MCP →

Fresh persisted observation

Use the WorkOS-authorized Inspector resource. Each successful invocation records one durable public observation.

View Inspector MCP →

Back to contents

Next: CLI and GitHub Action