# The unit contract v1

The contract is the stable surface between the platform and your process. It is published as [JSON Schemas](/units-code/schemas) (draft 2020-12) and is versioned by an integer **major**.

## Environment

| Variable | Value |
|---|---|
| `ZAROZ_CONTRACT_VERSION` | `1` |
| `ZAROZ_DIR` | `/zaroz` |
| `ZAROZ_UNIT_ID`, `ZAROZ_UNIT_KEY` | the unit's id and key |
| `ZAROZ_WORKLOAD` | the Workload's slug |
| `ZAROZ_PRIVATE_NAME` | `<key>.<workload>`, how other Workloads of the project reach this unit alone |
| `ZAROZ_PROJECT_ID`, `ZAROZ_REGION`, `ZAROZ_SERVICE_INSTANCE_ID` | where it runs |
| `MEMORY_LIMIT_MIB` | the unit's memory limit |
| `ZAROZ_API_URL` | only when the Workload has a [service principal](/guides/units-api/principals) |

Per-unit values are fixed when the pod is created, because a unit's key never changes. Only pods that carry the agent or a principal get the new variables: a Workload that does not use these features runs unchanged.

## Files in `/zaroz`

| Path | Schema | Notes |
|---|---|---|
| `contract.json` | `contract.schema.json` | `{version: 1, agent_version}` |
| `unit.json` | `unit.schema.json` | identity; `labels` update live |
| `user-data.json` | `user-data.schema.json` | the JSON value or `null` |
| `allocation.json` | `allocation.schema.json` | `null` or `{id, allocated_at, generation}` |
| `state.json` | `state.schema.json` | `{draining: false}` or `{draining: true, reason}` |
| `signals/` | | write-only: `ready`, `accepting`, `idle`, `busy`, `shutdown` |
| `signal.sock` | `signal-response.schema.json`, `accepting-request.schema.json`, `error.schema.json` | HTTP/1.1 over a Unix socket |
| `credentials/token` | | only with a principal; rotated, read it per request |

Every file is written atomically. See [Signals](/units-code/signals) for how to use them.

## Events

The envelope of `GET .../units/events` and of webhook deliveries is `event.schema.json`. See [Events](/guides/units-api/events). `data` is typed per event type.

## The versioning rule

- Within a major, changes are **additive only**: new optional fields, new files, new signals, new event types. Consumers must ignore what they do not know.
- Removing or renaming a field, or changing a type or a meaning, is a **new major**, chosen per Workload by `contract_version` on the policy (default: the newest).
- The previous major keeps being served for **at least 12 months** after the next one ships.
- The agent embeds every supported major's schemas and validates every file it writes and every event against them. The kernel's event emitter is tested against the same files.

## Guarantees

The lifecycle guarantees (ready means ready, allocate is atomic, drain before kill, stopped costs nothing, fast refusal, out of load balancing in about a second, events never skip) are listed on [Units your code controls](/units-code/concepts#guarantees). Each is checked by the open conformance suite.
