agentleFS
chinthakatchinthakat/agent-skills/skills/contract-change/SKILL.md

contract-change

Skill0 starsChanged 54 days agoMITView on GitHub

Change a shared contract — an API schema, shared types, an event payload, a database column that something else reads — without breaking the consumers that drift from it silently. Use when editing a schema or shared package, when a local mock or stub has diverged from the real service, or when a change works locally and fails against the deployed system.

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 4 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write the list. It is always longer than the two you were thinking of:

    line 15
  2. Distinctive:

    Test fixtures and recorded responses.

    line 19
  3. Distinctive:

    When you do version:

    line 103
  4. Distinctive:

    Only remove when usage is zero, and say who the remaining callers are if it is not.

    line 121

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Changing a shared contract

A contract is any shape that more than one thing depends on: an API schema, a shared types package, an event payload, a stored document, a CSV a customer parses. The failure is always the same — one side changes, the other finds out in production.

1. Enumerate the consumers before you touch it

Write the list. It is always longer than the two you were thinking of:

  • The obvious callers — the web app, the mobile app, the service next door.
  • Mocks, stubs and local development servers that reimplement the contract.
  • Test fixtures and recorded responses.
  • Generated clients, SDKs and typed hooks.
  • Reporting queries, exports, dashboards and the analytics pipeline.
  • Anything replaying stored events, which means old payloads already written.
  • Third parties, who will not be redeployed because you said so.
  • Cached bundles and installed mobile apps — versions of your own frontend still running in the wild.

That last group is the one that turns a "coordinated deploy" into an outage. You control the server; you do not control which version of the client is open.

2. The local mock is the one that drifts

A hand-maintained local development server, an in-memory fake, or a stub that mirrors the real schema will drift, because nothing fails when it does. Everyone develops happily against a contract that no longer matches production.

Two acceptable answers:

  • Generate it. One source of truth; the mock is derived. Drift becomes impossible rather than unlikely.
  • Test it against the real thing. A contract test that runs the same suite against the mock and against a real instance, in CI. Drift becomes loud.

"We'll remember to update both" is not one of them. If neither is affordable today, at least put a line in the instruction file saying the mirror exists and must be updated — see agent-instructions.

3. Additive is safe; removing and renaming are not

ChangeSafe?
Add an optional fieldYes
Add a new endpoint, event type or enum producer sideUsually — check how consumers handle unknown values
Make an optional field requiredNo — old clients omit it
Remove a fieldNo — something reads it
Rename a fieldNo — this is a remove plus an add, and the remove is what breaks
Change a type (string to number, seconds to milliseconds)No, and the worst kind: it fails silently and corrupts data
Change the meaning of a field, same typeNo, and undetectable by any tooling
Tighten validationNo — data that was accepted yesterday is rejected today
Add a new enum valueOnly if consumers were written to tolerate unknown values

The last row is worth designing for up front: consumers that reject unknown enum values make every future addition a breaking change.

4. Expand, migrate, contract

Any unsafe change becomes safe as three deploys:

1. EXPAND    Add the new field alongside the old. Write both. Read the old.
             Ship. Nothing breaks.
2. MIGRATE   Backfill. Move readers to the new field one at a time. Ship each.
             Keep writing both.
3. CONTRACT  When nothing reads the old field — proven, not assumed — stop
             writing it, then remove it. Ship.

Each step is independently deployable and independently revertible. This is slower than a rename and it is the difference between a change and an incident.

The step people skip is proving nothing reads the old field. Assume something does until telemetry says otherwise.

5. Types passing is not compatibility

A green type check proves that the code in this repository agrees with itself right now. It says nothing about:

  • The mobile app version from three months ago.
  • A cached JavaScript bundle in someone's browser.
  • Events already written to a queue or a log.
  • Documents already stored under the old shape.
  • A third party's integration.

Compatibility is a statement about data that already exists and clients already running. Reason about it explicitly; the compiler cannot.

6. Version when you must, additive when you can

Versioning an API is expensive — two code paths, two sets of tests, two things to deprecate — so exhaust additive changes first. Most "we need v2" moments are three additive changes and a deprecation.

When you do version:

  • Version the whole surface or an individual endpoint, consistently.
  • Set the end date for the old version when you launch the new one, not later.
  • Instrument usage so the shutdown is a fact, not a hope.
  • Tell the consumers who are actually using it, identified by telemetry.

For stored documents, prefer a version field on the record and a reader that handles each known shape — the same idea as versioned-publishing, applied to data rather than content.

7. Deprecate visibly

A deprecation nobody notices is not a deprecation:

  • Mark it in the schema and in the docs, with the date it goes.
  • Log or emit a metric on every use, tagged with the caller.
  • Warn in the client — a runtime warning is seen; a changelog entry is not.
  • Only remove when usage is zero, and say who the remaining callers are if it is not.

8. One contract test both sides run

The highest-value artifact here: a suite that the producer runs against itself and every consumer runs against its expectation of the producer. It fails on the side that broke, in CI, before anything ships.

Where a full contract-testing tool is too much, a shared schema file plus a test that validates real recorded responses against it catches most of the same problems for an afternoon's work.

Checklist

  • Every consumer enumerated, including mocks, fixtures, stored data and clients in the wild
  • Local mock or dev server either generated from the source of truth or contract-tested
  • Change classified as additive or breaking, honestly
  • Breaking changes split into expand / migrate / contract, each shippable alone
  • "Nothing reads the old field" proven by telemetry, not assumed
  • Compatibility reasoned about for old clients and already-written data, not just the type check
  • Additive exhausted before versioning; end date set when a new version launches
  • Deprecation instrumented and warned at runtime, not only documented
  • A contract test both sides run in CI

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.