Rule: the coding agent uses these versions. Newer versions are proposed in a slice's NOTES.md, approved by
the human, then recorded here with a new "verified" date. mix versions.verify (Slice 000) diffs mix.lock
against this file.
Verification legend: ✅ verified against hex.pm on the date in the row; 🔍 from prior research, re-verify at
Slice 000;
Correction, 2026-09-05. The ✅ marks in the first version of this file were not all measured. Two were wrong on the packages the OTP pin rests on. Every ✅ below was re-derived on 2026-09-05 by:
$ curl -s https://hex.pm/api/packages/<name>
A ✅ means that command was run and its answer is in the row, with the date. Nothing else earns one.
The mark is derived, never typed. mix versions.gen reads mix.lock through
Mix.Dep.Lock.read/0 and emits the Verified column from membership:
| Mark | Means |
|---|---|
✅ in mix.lock |
the package is present in mix.lock at this sha |
🔍 not yet a dependency |
absent from mix.lock; the slice that adds it flips this |
🔍 not a single package |
the row names a choice or a pair, so lock membership cannot answer it |
✅ .tool-versions |
a toolchain component, marked from the pin file rather than from hex |
This replaces the old legend, under which ✅ meant "someone ran curl against hex.pm on the
date in the row". That mark could not be re-derived and outlived the fact twice: finding B3
caught two false ✅ marks on the two packages the OTP pin rested on. A mark a command produces
cannot go stale without the command saying so, and mix versions.gen --check is a gate step.
The tables below are generated. Editing them by hand fails the gate.
mix hex.info <package> # latest stable + retired flags
mix hex.outdated # what moved since the pin
mix hex.audit # retired packages in lock
mix deps.audit # known vulnerabilities
Record the output in the slice's PROOF.md and update this file's "Latest seen" column with the date.
Rules: prefer the newest stable that satisfies the packaging chain (Burrito/ex_tauri); never pin an -rc;
never pin a version hex marks as retired or vulnerable.
| Name | Pin | Verified | Note |
|---|---|---|---|
Erlang/OTP |
28.5.0.5 | ✅ .tool-versions |
Measured at Slice 000, not read from a README: Burrito 1.6.0's ERTS resolver names one artifact source per target, and 28.5.0.5 is the newest OTP returning 200 on all four (macOS universal, Linux x86_64, Linux aarch64, Windows). 28.5.0.6 is released but its macOS and Linux artifacts are unbuilt (404). OTP 29 is 404 on macOS and both Linux arches. |
Elixir |
1.20.4-otp-28 | ✅ .tool-versions |
Confirmed at Slice 000: elixir --version reports Elixir 1.20.4 on Erlang/OTP 28, erts-16.4.0.5. Built-in type checker is part of the gate. boundary 0.10.4 compiles and enforces on this pair, measured at Slice 000 (H7). |
asdf |
v0.18.0 | 📐 asdf --version |
.tool-versions committed in Slice 000. mise is absent on the build machine; measured at Slice 000 G1 with which mise asdf. asdf cannot pin itself, so this row is a command, not a file. rust 1.92.0 line is omitted from asdf current and asdf install still exits 0. A pin file entry is only a pin where a plugin exists. |
Rust |
1.92.0 | ✅ rust-toolchain.toml |
Measured at Slice 001 line 3: rustc --version reports 1.92.0 (ded5c06cf 2025-12-08), exit 0. Pinned in rust-toolchain.toml, not .tool-versions: asdf here has no rust plugin and silently ignores a rust line, whereas rustup show active-toolchain reports this file as an override. See NOTES.md deviation D1. Corrected 2026-09-06: this row previously read `Rust + Tauri CLI |
Tauri CLI |
2.11.4 | 📐 _build/_tauri/bin/cargo-tauri tauri --version |
Measured at Slice 001 line 3. Not on PATH and not pinned by any file in the tree: ex_tauri provisions it with cargo install tauri-cli --version ^2 --root . inside _build/_tauri, which is gitignored, so cargo tauri --version exits 101 on a fresh machine. 📐 rather than ✅ because nothing at this sha verifies it. The ^2 floats; 2.11.4 is what it resolved to on 2026-09-06. |
Zig |
0.16.0 | ✅ .tool-versions |
Measured at Slice 001 line 3: burrito 1.6.0 compares Zig for equality, not a range (@zig_version_expected in deps/burrito/lib/burrito.ex), and exits 1 on any other version. zig version reports 0.16.0, exit 0. Installed through the asdf zig plugin, added this slice. Corrected 2026-09-06: this row previously read `version required by Burrito |
FIPS leg base image (UBI9) |
sha256:9295c5c688f487fa5cf27a734fa55ecd57aeb7dc0904ba537da4f42dfa1d0acb | ✅ ci/fips/Containerfile |
Added at Slice 003: the base of the FIPS build leg's image (docs/fips-leg.md), registry.access.redhat.com/ubi9/ubi:latest resolved by digest on 2026-09-20 (Red Hat Enterprise Linux release 9.8, openssl-libs 3.5.8-1.el9_8, openssl-fips-provider-so 3.0.7-11.el9_8). The image itself is OTP 28.5.0.5 built from source with --enable-fips against that OpenSSL, plus Elixir 1.20.4; the two archives are pinned by SHA-256 in the Containerfile and the image tag is scripts/fips_image_tag.sh over .tool-versions and the Containerfile. The FIPS provider the image runs is what the distribution ships and names; docs/fips-leg.md states what Trinity does and does not claim about it. |
| Name | Pin | Verified | Note |
|---|---|---|---|
phoenix |
~> 1.8.13 | ✅ in mix.lock |
|
phoenix_live_view |
~> 1.2.0 | ✅ in mix.lock |
1.2 line; earlier 1.2.x flagged vulnerable on hex, do not pin lower. |
phoenix_pubsub |
~> 2.1 | ✅ in mix.lock |
|
bandit |
~> 1.5 | ✅ in mix.lock |
HTTP server. |
ecto_sql |
~> 3.13 | ✅ in mix.lock |
|
ecto_sqlite3 |
>= 0.0.0 | ✅ in mix.lock |
Primary DB. FTS5 available. |
postgrex |
>= 0.0.0 (optional) | ✅ in mix.lock |
Secondary DB driver, optional: true so the desktop build carries none of it; compiled in only under TRINITY_DB=postgres, which the CI job proves. Added at Slice 010. Was one row with pgvector; pgvector keeps its own row below. |
pgvector |
optional, ~> 0.3 | 🔍 not yet a dependency | Vectors on the Postgres path. Not yet a dependency; Slice 032 decides. Split from the postgrex row at Slice 010. |
oban |
~> 2.24 | 🔍 not yet a dependency | Uses Oban.Engines.Lite on SQLite. |
req |
~> 0.5 | ✅ in mix.lock |
HTTP client. |
req_llm |
~> 1.22 | ✅ in mix.lock |
Provider layer (streaming, tools, structured output, usage). ~> 1.10 against a recorded latest of 1.10.0; the real latest was twelve minors ahead. Check event shapes against the current version at Slice 011, not against this file's prose. Added at Slice 011. |
beam_mcp |
~> 0.8 | 🔍 not yet a dependency | MCP server core, Apache-2.0, ADR-0007 decision 5 (owner decision 2026-09-08, recorded 2026-09-20). 0.8.0 on hex.pm, standing before 1.0.0. Server side only: the client, MRTR and OAuth are Trinity's, above it. Added at Slice 059. The earlier candidate list (anubis_mcp, fastest_mcp, gen_mcp) is history. |
jido |
not used (ADR-0009, decided 2026-09-20) | 🔍 not a single package | Measured at the Slice 012 checkpoint and not adopted: the agent runtime duplicates PubSub, Oban and the gateways and adds a second tool executor; the action shape is written in-tree at Slice 020 with jsv for its schemas. The row stays so the decision is visible where a reader would look for the package. |
jason |
~> 1.2 | ✅ in mix.lock |
|
boundary |
~> 0.10 | ✅ in mix.lock |
Compile-time module dependency enforcement. Measured at Slice 000: it compiles and enforces on Elixir 1.20.4 / OTP 28, and it reports violations as warnings, so it enforces only while --warnings-as-errors is on the compile step. |
nimble_options |
~> 1.1 | ✅ in mix.lock |
Config validation for behaviours. |
| Name | Pin | Verified | Note |
|---|---|---|---|
phoenix_ecto |
~> 4.5 | ✅ in mix.lock |
Ecto integration for Phoenix. Scaffold. |
phoenix_html |
~> 4.1 | ✅ in mix.lock |
HTML helpers. Scaffold. |
phoenix_live_dashboard |
~> 0.8.3 | ✅ in mix.lock |
Runtime dashboard. Slice 090 surfaces it. |
phoenix_live_reload |
~> 1.2 | ✅ in mix.lock |
Dev only. Scaffold. |
esbuild |
~> 0.10 | ✅ in mix.lock |
JS bundling, dev only. Scaffold. |
tailwind |
~> 0.5 | ✅ in mix.lock |
CSS, dev only. Scaffold. Slice 013 decides the design language on top of it. |
heroicons |
v2.2.0 (github, sparse) | 🔍 not a single package | Icon set, fetched from git rather than hex, so it has no lock key. Scaffold. |
daisyui |
v5.5.20 (github, sparse) | 🔍 not a single package | Component classes, fetched from git rather than hex, so it has no lock key. Scaffold. |
gettext |
~> 1.0 | ✅ in mix.lock |
Translations. Scaffold. |
dns_cluster |
~> 0.2.0 | ✅ in mix.lock |
Node discovery. Unused until a clustered deployment exists. |
telemetry_metrics |
~> 1.0 | ✅ in mix.lock |
Metric definitions. Slice 090 consumes them. |
telemetry_poller |
~> 1.0 | ✅ in mix.lock |
VM measurements. Slice 090 consumes them. |
| Name | Pin | Verified | Note |
|---|---|---|---|
nx, exla |
latest stable | 🔍 not a single package | Local embeddings. EXLA binary size matters for desktop: measure in 032. Two packages, so no single lock key. |
bumblebee |
~> 0.7 | 🔍 not yet a dependency | all-MiniLM-L6-v2 embeddings; Whisper later. Added at Slice 032. |
sqlite_vec |
~> 0.1 | 🔍 not yet a dependency | Vectors in SQLite. Verify the loadable extension works inside the Burrito bundle (Slice 032). |
hnswlib |
~> 0.1.7 | 🔍 not yet a dependency |
| Name | Pin | Verified | Note |
|---|---|---|---|
muontrap |
~> 2.0 | ✅ in mix.lock |
The shell tool's process wrapper (Trinity.Tools.Shell.Run, Slice 022): a C port, SIGTERM then SIGKILL, the child dies with the port. Read against 2.0.0 at Slice 022: cmd/3 takes :timeout (SIGTERM at expiry, :timeout as the status), :delay_to_sigkill, :cd, :env, optional cgroup v2 limits. |
floki |
~> 0.38 | ✅ in mix.lock |
HTML to text for web_fetch (Slice 022): script, style, nav, header, footer and aside dropped, the body's text taken. |
luerl (+ sandbox) |
latest | 🔍 not a single package | Slice 110 only. Two packages, so no single lock key. |
burrito |
~> 1.6 | ✅ in mix.lock |
~> 1.5 / 1.5.0 ✅; that mark was not measured. Added at Slice 001. |
ex_tauri |
~> 0.2 | ✅ in mix.lock |
otp_release: "~> 27.0", and Slice 000's probe refutes the reason it gives: OTP 28 macOS universal returns 200 and OTP 27 returns 404. Whether it runs on the pinned OTP is Slice 001's first measurement. |
nostrum |
~> 0.10 | 🔍 not yet a dependency | Discord. |
telegex |
not pinned | 🔍 not a single package | Telegram. -rc. Alternative: ex_gram. Slice 071 decides with the measurement. |
phoenix_streamdown |
not used (measured at Slice 013, 2026-09-20) | 🔍 not a single package | Streaming markdown renderer for LiveView. Measured at Slice 013: 1.0.0-beta.4 (2026-05-03) was still the latest release with no stable behind it, and this file's own rule forbids a pre-release. It is 801 lines over mdex, whose own streaming: true option completes fragments; the rest is a rendering rule Slice 013 keeps anyway. The row stays so the decision is visible where a reader would look for the package. |
mdex |
~> 0.13 | ✅ in mix.lock |
Markdown renderer for the chat (TrinityWeb.Markdown), streaming fragments completed by its streaming: true option, raw HTML omitted (unsafe: false) and the default sanitizer on top. Added at Slice 013 after the measurement in its NOTES.md: earmark 1.4.49 is retired on hex with an open XSS advisory (EEF-CVE-2026-48591), which the gate refuses. mdex_native): the first in the bundle. Measured at Slice 013 (NOTES finding 13): neither precompiled artifact loads in Burrito's musl ERTS on Linux, so the linux package builds it from source for musl with Zig as the linker (rustler below, scripts/zig-cc-musl, the three settings in config/config.exs); macOS and Windows load the precompiled artifact. The --smoke path prints whether it rendered, and the package workflow reads that line on every target. |
jsv |
~> 0.23 | ✅ in mix.lock |
JSON Schema (2020-12) validation of tool arguments in Trinity.Tools.Schema, with cast: false so a malformed call is refused and never repaired (docs/07). Was transitive through req_llm; direct since Slice 020 because a module of ours calls it (ADR-0009: Trinity's own tool behaviour, jsv for its schemas). |
jcs |
~> 0.2 | ✅ in mix.lock |
RFC 8785 canonical JSON, under every approval fingerprint (Trinity.Permissions.Fingerprint, Slice 021) and, at 024, under the receipts' signed payload. Chosen at Slice 021: it matches the RFC's own example vector byte for byte on this OTP, and test/trinity/permissions/fingerprint_test.exs keeps that vector so a release that stops matching fails the gate. rfc8785 1.0.0, refuses OTP 28 and waits on the OTP pin. |
rustler |
~> 0.38 | ✅ in mix.lock |
Build time only (runtime: false): what rustler_precompiled needs to compile mdex_native from source when MDEX_NATIVE_BUILD=1, which the linux package sets (owner decision 2026-09-20, Slice 013 NOTES finding 14). Nothing in the tree calls it. |
| Name | Pin | Verified | Note |
|---|---|---|---|
credo |
~> 1.7 | ✅ in mix.lock |
--strict in the gate; hosts the eval-family check. |
mox |
~> 1.2 | ✅ in mix.lock |
Mocks for every behaviour. |
mix_audit |
~> 2.1 | ✅ in mix.lock |
mix deps.audit. |
sobelow |
~> 0.15 | ✅ in mix.lock |
Phoenix security lint. Blocking in the gate with a committed --skip list (M5). .sobelow-skips.reasons. |
ex_doc |
~> 0.38 | ✅ in mix.lock |
Docs. |
lazy_html |
(transitive via LiveView test) | ✅ in mix.lock |