infra stuff in gleam
gleam atproto lexicon codegen oauth

Files
README.md

gleam-atproto #

Gleam packages for building on atproto, extracted from at-record. All are alpha: pre-1.0, evolving alongside at-record, breaking changes between 0.x releases.

Package Hex What it does
atproto_core hex.pm Shared sans-io core: XRPC error vocabulary and the OAuth effect kernel.
atproto_client hex.pm Transport-agnostic client: XRPC, identity, OAuth, blobs, repo CRUD. Dual-target.
atproto_browser hex.pm Browser-native OAuth + XRPC: WebCrypto DPoP/PKCE, async fetch. javascript-only.
atproto_lexicon hex.pm Bidirectional lexicon AST, source resolver, pinned cache with lockfile, semantic diff.
atproto_codegen hex.pm Generates Gleam types, JSON codecs, and a typed XRPC client from lexicons.
atproto_mlf hex.pm Parse and print mlf against the atproto_lexicon AST.
atproto_sdl hex.pm Prisma/GraphQL-inspired lexicon schema language over the same AST.
atproto_openapi hex.pm One-way OpenAPI 3.1.0 emitter from lexicons.

The lexicon toolchain (the json, mlf, and sdl front-ends and the codegen and openapi back-ends) meets at the atproto_lexicon AST. Each package's README and hexdocs carry the details.

Versioning & releases #

Semver, per package, versioned independently. While pre-1.0: breaking changes bump minor, everything else bumps patch.

Every user-facing change lands under ## [Unreleased] in that package's CHANGELOG.md. Releasing moves it under a version heading, bumps gleam.toml, and pushes a <package>-v<version> tag (e.g. atproto_client-v0.2.0); CI verifies the tag matches gleam.toml and publishes to Hex.

Cross-package changes #

Packages depend on each other through Hex version ranges, never by path on main: Hex rejects path dependencies, so a path dep on main blocks the release of every package that carries it. A path dependency is fine on a local branch for developing across packages, but swap it back before opening the PR.

A change that spans packages ships in dependency order, one PR per layer: release the lower package first (e.g. atproto_core), and once it is on Hex, point its dependents at the new version in a follow-up PR.

The 0.x range rule #

A sibling dependency needs an upper bound on a minor boundary above its lower bound, because pre-1.0 minors are breaking. From a 0.x lower bound that is < 0.k.0, never < 1.0.0; from 1.x it is < (M+1).0.0. Spanning several minors is fine when the code is verified against all of them.

atproto_core = ">= 0.2.0 and < 0.3.0"   # ok
atproto_core = ">= 0.1.1 and < 0.3.0"   # ok, if tested against 0.1 and 0.2
atproto_core = ">= 0.2.0 and < 1.0.0"   # rejected

make depcheck (also a PR CI step) enforces this and fails on any path dependency; the publish workflow runs it for the tagged package before publishing. make depcheck-test runs the rule's table of cases.

Before a breaking 0.x release of a package, check the published ranges of its dependents on Hex: make release-check PKG=<package> VERSION=<version> (report only). A release is breaking when it changes the minor (0.x) or major (1.x+). For each sibling that depends on the package, the check reads the latest release of every minor line from Hex and fails if one still accepts the new version, or if a requirement cannot be parsed or Hex cannot be reached. Ship capped patch releases of the named dependents first (below). A dependent that accepts the release and was tested against it is listed in scripts/release-check.verified (<package> <version> <dependent> <dependent-version>). The publish workflow runs the same check right before gleam publish.

Maintenance releases #

To fix an older line: cut release/<package>-<major>.<minor> from the last tag of that line (git switch -c release/atproto_client-0.3 atproto_client-v0.3.0), make the fix, bump the patch version, and tag from that branch. The publish workflow accepts a tag that is an ancestor of main or of the matching release/<package>-<major>.<minor> branch, nothing else. The branch needs the current publish.yml and scripts/, since CI runs the workflow committed at the tag.

Reverting a release #

Hex allows reverting a release within 24 hours: from the package directory, gleam hex revert --package <package> --version <version>. Delete the tag as well (locally and on the remote), or CI will publish it again.

What the checks guard #

  • make depcheck: path dependencies and uncapped 0.x sibling ranges. Runs in PR CI.
  • make fixtures: generates clients from fixture lexicons and compiles them against the packages as published on Hex. It cannot pass before the versions its ranges name exist, so it is the last step of a release, run by hand once every package in the set is on Hex. It is not part of CI.
  • Republishing a version that was reverted on Hex produces a new tarball with a new checksum: update the outer_checksum in every manifest that locks it. A local build can hide the stale checksum, because gleam's package cache is keyed by checksum and still holds the old tarball.