# The tarball contains its own contract.

*31 July 2026 · the launch journal*

There are two ways a machine caller learns a CLI. It can probe: run the tool, parse whatever comes out, guess at the failure modes, and hope the next release guesses the same way. Or it can read: open a file that states the verb set, the output discipline, and the exit codes as promises, and integrate against the promises. Probing is what agents do to tools that never wrote anything down. This package chose the other path: **the contract is a file in the tarball**, at `node_modules/epcis.dev/AGENTS.md`, and its first line of business says why — *"grep it where you already are. It is the contract, not marketing."*

## What the contract promises

The load-bearing clauses, as the shipped file states them:

- **Verbs (closed set):** `validate`, `hash`, `translate`, `capture`, `mcp`, `conformance run`, `conformance rejudge`, `pins`, `version`. Bare `npx epcis.dev` prints the orientation. Unknown verbs are a typed USAGE refusal with a hint, exit 2.
- **`--json` on every verb.** Deterministic machine JSON — same data and same exit code as text mode. Text mode is token-cheap TSV-style lines: never colored, never wrapped.
- **stdout is payload-only.** Errors are typed on **stderr**: `{"error":{"code","message","hint"?}}` in json mode, `error\tcode=…` in text mode. `JSON.parse(stdout)` never sees a half-written object.
- **Exit codes (stable):** `0` ok · `1` fail (a negative domain verdict: invalid document, failed translation, rejected capture) · `2` usage · `3` not-found · `4` internal.
- **Error `code` strings are stable across releases** — match on `code`, never on prose.

The closed verb set is the quiet promise most tools refuse to make. It means no surprise surface area between versions: the nine verbs an agent persisted in its [residency block](/journal/the-tool-that-survives-the-session/) are the nine verbs that exist, and an unknown verb is a *typed* refusal rather than an adventure.

## Three commands, contract held

Not claims — a transcript, run against the shipped fixtures:

```
$ npx epcis.dev validate golden-corpus/valid-standard/aggregation-event-packing.json
valid	schema=epcis-json-schema.json	version=2.0.1
$ echo $?
0

$ npx epcis.dev validate golden-corpus/invalid/object-event-missing-action.json
schema-error	/epcisBody/eventList/0	must have required property 'action'
schema-error	/epcisBody/eventList/0	must match "then" schema
schema-error	/	must match "then" schema
invalid	errors=3
$ echo $?
1

$ npx epcis.dev frobnicate
error	code=USAGE	message=unknown verb "frobnicate"	hint=run `npx epcis.dev` with no arguments for the verb map
$ echo $?
2
```

Read the second one carefully, because it is the clause agents get wrong about every other tool: **exit 1 is not a crash.** The validator did its job perfectly — it found an invalid document and said so, with JSON-Pointer paths on stdout as payload. The fail-closed path *working* is exit 1; the tool itself breaking is exit 4. A caller that treats every nonzero exit as an error will retry a verdict, and a verdict does not change on retry. (The HTTP side of this contract — [typed problem documents an agent can branch on](/journal/errors-agents-branch-on/) — keeps the same law.) Distinct codes are what let a machine build the correct branch: `0` proceed, `1` route the finding, `2` fix the call, `3` fix the path, `4` escalate.

The same run in `--json` returns the same verdict as structured payload — including the provenance of the ruler it was measured with:

```json
{ "valid": true,
  "schema": { "artefact": "epcis-json-schema.json", "version": "2.0.1",
              "sha256": "0f46ff694efffd8d8ce840a33dfde84228add11b516b8b258f3200740ae210af" } }
```

That `sha256` is the pin of GS1's own published schema, checkable against [/conformance/](/conformance/) and against `ref.gs1.org` directly. Even the validation result carries its evidence.

## Token economics are contract clauses too

Text mode being TSV-style is not aesthetics. An agent pays for every byte it reads back, so the default output is engineered to be the cheapest faithful representation: one tab-separated line per fact, no color codes to strip, no wrapping to reassemble, no banner. The `hash` verb answers one line per event — `hash	0	ni:///sha-256;e5624abc…?ver=CBV2.0` — and nothing else. When an agent wants structure, `--json` is there on every verb with identical semantics; when it wants cheap, text mode is already minimal. Both modes keep stdout payload-only, so the pipe never carries prose that has to be recognized and discarded.

Why put the contract in the tarball instead of only on a website? Because the file is versioned with the code it describes. The `AGENTS.md` an agent reads at `node_modules/epcis.dev/AGENTS.md` shipped in the same publish as the binary it documents — there is no skew between the docs revision and the tool revision, and no network fetch to a page that may describe a newer release. The contract also carries the sharp edges honestly, in a section titled *Hazards*: `translate` in text mode prints the document as line 2 of stdout (use `--json` when piping); the `hash` algorithm itself excludes `eventID` and `recordTime` per CBV 2.0 §8.9, so do not pre-strip anything; conformance runs are advisory and unsigned, never anyone's attestation. Extension fields, where the corpus carries them, ride under a declared JSON-LD context, and the projection always validates against the pinned official EPCIS 2.0.1 schema — the file states both halves of that sentence and forbids restating either half alone.

The idiom repeats across the family by design. The [business-transaction layer](/business-transactions/)'s `biztx` CLI ships the same laws verb for verb — `--json` everywhere, payload on stdout, typed stderr, exits `0`/`1`/`2` — so an agent that learned one door has learned the family.

`npx epcis.dev`, then read the file. The integration is a read, not a reverse-engineering project.

*Sources: `node_modules/epcis.dev/AGENTS.md` (contract clauses quoted from the shipped file); CLI transcript captured 2026-07-31 against the packaged golden corpus; pinned-schema digests at [/conformance/](/conformance/) and ref.gs1.org.*

---

**Proof, not adjectives.** This build could not verify the gateway's test suite green, so no sentence on this page claims a passing run — the last verified run is recorded in the repository's own CI, not here. Live on this origin, no key: POST /translate, /validate, /hash. No conformance attestation has ever been issued. The dated ledger is /what-ships-today/.
