All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

Changed

  • The README, the tutorials, and the Cite docs read the API key from TYPESAFE_API_KEY instead of JEV_API_KEY. Cite itself reads no environment variable, so only code copied from the examples is affected.

0.2.0 - 2026-10-01

Added

  • concurrency on Cite.judge/4: the most requests in flight at once within a round, 4 by default. Given the same replies, the report is the same at any setting. Set concurrency: 1 to send one request at a time, as 0.1 did.

Changed

  • A client that returns something outside its contract raises RuntimeError instead of ArgumentError. Cite.judge/4 itself raises ArgumentError only on a bad argument, before any request. What the client raises passes through as is.
  • The client runs in a task process, even at concurrency: 1. Logger metadata and process level carry over, and Cite carries nothing else: OpenTelemetry context, for one, does not. In the client, self() is the task, not the caller.
  • Cite.Provider asks two more things of a provider. judge/2 must be safe to call from several processes at once with the same handle. And it must not raise on a condition that concurrency makes routine, such as waiting for a connection. A custom client must be safe to call concurrently too, or be run at concurrency: 1.
  • In a caller that traps exits, a crash in a process the client links to now makes Cite.judge/4 exit with the same reason. As with a raise, the exit comes once the requests before it have answered, and it stops the rest as a raise does. Before, such a caller (a GenServer, say) received an :EXIT message and the run carried on. A caller that doesn't trap exits still dies at once, through the link.
  • At concurrency above 1, a raise mid-run comes once the requests before it have answered. Once a call raises, throws, or exits, no new request starts. A request before it still finishes, including the halves Cite sends when it is too large and any retries the client makes. One after it is stopped at once, but the provider may already have received and billed it.
  • Cite.Provider.TypeSafe waits for a pooled connection with no time limit, instead of raising after 5 seconds. A pool_timeout under finch:, in req_options or the app's Req.default_options/0, still sets one.
  • Cite.Provider.TypeSafe applies its :retry_delay check to the app's Req.default_options/0 as well as req_options: a :retry_delay from either needs a :retry in req_options. A retry_delay: nil now passes, as Req reads it as unset.
  • The RAG grounding tutorial runs at the default window: screening an answer's sentences together costs no more and makes no more mistakes than one at a time.

Fixed

0.1.1 - 2026-09-28

Added

  • Tutorial: Checking RAG answers against their sources. It finds the sentences of a generated answer that its retrieved documents contradict or never state, with a filter for sentences that assert nothing.
  • Tutorial: Filtering RAG retrieval results. It keeps the retrieved passages that answer a query, judging each query's candidates together.
  • A roadmap for 0.2.0, marking each item planned, exploring, or not planned.
  • A logo, shown in the docs sidebar, as the favicon, and beside the README heading.

Changed

  • The guides say what one round-1 request holds, and that shown meta is the only context a passage carries besides its text: a value every passage shares, such as the question they are judged against, goes on each passage. The window docs say it takes any positive integer, including 1.
  • Writing policies defines not_for against its own block's what, so it can go in a no block as well as a yes.
  • Each tutorial opens by saying what you write and build, and what Cite does in between.

Security

  • Mint, the HTTP client under Req, has three advisories fixed in 1.11.0 (EEF-CVE-2026-91043, EEF-CVE-2026-92103, EEF-CVE-2026-94194). Cite's own lockfile now pins 1.11.0. Hex packages do not ship a lockfile, so run mix deps.update mint in your project.

0.1.0 - 2026-09-27

Added

  • use Cite.Policy: a policy declared once in a module, built on Spark. Filters, concerns (screened directly with a detect and an optional confirm, or built from factors with roles and checks), factors, and Score or Choice descriptors. A passage is evidence for every concern it matches. Questions name what they read by placeholder ({passage}, {household}) and Cite replaces each with a path in the request. Any question may add a one-line focus. Every mistake in a policy is a compile error.
  • A DSL reference in Cite.Policy's docs, generated from the DSL by Spark.
  • Cite.source/2: the caller's passages, kept byte for byte, with as: for the word they sit under and show: for the meta the model sees.
  • Cite.judge/4: two fixed rounds. A screen of every passage for every detect in windows, fixed rules that gather matches into findings, and one judgment per finding on all of its evidence, gated by a review band. Options: threshold, review_band, window. A client, source, policy, or options of the wrong kind raise ArgumentError.
  • Replies are checked before they count: a reply that skips a question or answers out of range makes its whole request an error, never a verdict. Errors are reported beside the findings, one per failed request.
  • Cite.Report, Cite.Finding, Cite.Citation, Cite.Passage, and Cite.Error as the outputs, encodable with Jason. A finding carries its verdict, the raw answers to its checks and descriptors, the passages it cites and those its confirm dropped; the report keeps every round-1 score, token usage, and the model ids that answered.
  • Cite.Provider behaviour and Cite.Provider.TypeSafe, a Req client for TypeSafe System One; Cite.client/2 builds the client function judge/4 takes. A request's "state" may hold Cite.Wire.Object values, JSON objects that keep their key order. The TypeSafe client takes api_key, model, base_url, max_retry_delay, and req_options. It retries 429, 529, 500–504, and connection failures up to three times, honouring Retry-After, with delays capped at 30 seconds; timeouts are not retried.
  • Round-1 windows over the provider's size cap ({:error, :request_too_large}) are halved and retried; only a lone passage still over the cap becomes an error. A round-2 request refused as too large is that finding's error.
  • Guides: Writing policies, and How judging works. Tutorials, each building a policy from scratch: Triaging logs, Finding sponsor segments, Labelling allergens in recipes, and Checking support calls against procedure.
  • Stability tiers, named in the README and grouping the docs: Core API (the SemVer contract), Providers, and Internal.
  • Requires Elixir ~> 1.18.